/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.commons.beans.utils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.apache.commons.codec.binary.Base64;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.primitives.primes.utils.PemUtils;

/**
 * Allows a password (string) to be encrypted and decrypted.
 */
public final class PasswordEncrypter {

    private final AsymmetricServiceAPI asymmetricService;

    public PasswordEncrypter(final AsymmetricServiceAPI asymmetricService) {

        this.asymmetricService = asymmetricService;
    }

    /**
     * Encrypts the received password using the private key.
     * <P>
     * If the received private key is {@code null} or an empty string, then this method will return the original password.
     *
     * @param plaintextPassword
     *            the password to be encrypted.
     * @param publicKeyToBeUsedToEncryptThePassword
     *            the public key to be used to encrypt the password (in PEM format).
     * @return the encrypted password.
     * @throws GeneralCryptoLibException
     */
    public String encryptPasswordIfEncryptionKeyAvailable(final String plaintextPassword,
            final String publicKeyToBeUsedToEncryptThePassword) throws GeneralCryptoLibException {

        if (publicKeyToBeUsedToEncryptThePassword == null || publicKeyToBeUsedToEncryptThePassword.isEmpty()) {

            return plaintextPassword;

        } else {

            PublicKey publicKey = PemUtils.publicKeyFromPem(publicKeyToBeUsedToEncryptThePassword);

            return Base64.encodeBase64String(asymmetricService.encrypt(publicKey, plaintextPassword.getBytes()));
        }
    }

    /**
     * Decrypts the received encrypted password using the received private key (represented as a string in PEM format).
     *
     * @param encryptedPassword
     *            the encrypted password to be decrypted.
     * @param privateKeyAsPem
     *            private key in PEM format.
     * @return the decrypted password.
     * @throws GeneralCryptoLibException
     * @throws IOException
     */
    public String decryptPassword(final String encryptedPassword, final String privateKeyAsPem)
            throws GeneralCryptoLibException, IOException {

        return decryptPassword(encryptedPassword, PemUtils.privateKeyFromPem(privateKeyAsPem));
    }

    /**
     * Decrpyt the received encrypted password using the received private key.
     *
     * @param encryptedPassword
     *            the encrypted password to be decrypted.
     * @param privateKey
     *            a private key.
     * @return the decrypted password.
     * @throws GeneralCryptoLibException
     * @throws IOException
     */
    public String decryptPassword(final String encryptedPassword, final PrivateKey privateKey)
            throws GeneralCryptoLibException, IOException {

        byte[] ciphertextAsBytes = Base64.decodeBase64(encryptedPassword);

        byte[] plaintextAsBytes = asymmetricService.decrypt(privateKey, ciphertextAsBytes);

        return new String(plaintextAsBytes, StandardCharsets.UTF_8);
    }
}
