com.password.locker.crypto.SecureCryptoImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.password.locker.crypto.SecureCryptoImpl.java

Source

/******************************************************************************
 * Copyright (c) 2014 Fred Laderoute.
 * All rights reserved. This program and the accompanying
 * materials are made available under the terms of the GNU 
 * Public License v3.0 which accompanies this distribution, 
 * and is available at http://www.gnu.org/licenses/gpl.html
 *
 * Contributors:
 *      Fred Laderoute - initial API and implementation
 ******************************************************************************/
package com.password.locker.crypto;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.crypto.PBEParametersGenerator;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;

import com.password.locker.util.Constants;
import com.password.locker.util.ExceptionUtils;
import com.password.locker.util.PasswordUtils;

/**
 * SecureCrypto implementation class.
 * @author fred
 *
 */
public final class SecureCryptoImpl extends Crypto {

    /**
     * The length of the keys.
     */
    private static final int KEY_LEN = 256;

    /**
     * The length of the keys.
     */
    private static final int IV_LEN = 128;

    /**
     * The number of iterations.
     */
    private static final int ITERATIONS = 2048;

    /**
     * Encryption cipher.
     */
    private volatile Cipher encryption;

    /**
     * Encryption cipher.
     */
    private volatile Cipher decryption;

    /**
     * Salt instance.
     */
    private final byte[] salt;

    /**
     * SecureCrypto Constructor.
     * 
     * @param password
     *       password for the crypto keyspec.
     * 
     * @throws InvalidAlgorithmParameterException 
     * @throws InvalidKeyException 
     * @throws NoSuchPaddingException 
     * @throws NoSuchProviderException 
     * @throws NoSuchAlgorithmException 
     */
    public SecureCryptoImpl(final char[] password) throws InvalidKeyException, InvalidAlgorithmParameterException,
            NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {

        SHA256Digest digest = new SHA256Digest();

        String s = Constants.PROPERTIES.getStringProperty(Constants.SALT_KEY, PasswordUtils.getSalt(digest));
        salt = Hex.decode(s);
        if (salt.length != digest.getDigestSize()) {
            LOGGER.warn("Warning salt size is not the size of the Digest.");
        }

        //---------------------------------------------------
        // Setup encryption.
        //---------------------------------------------------
        PBEParametersGenerator pGen = new PKCS12ParametersGenerator(digest);

        pGen.init(PBEParametersGenerator.PKCS12PasswordToBytes(password), salt, ITERATIONS);

        ParametersWithIV params = (ParametersWithIV) pGen.generateDerivedParameters(KEY_LEN, IV_LEN);

        SecretKeySpec encKey = new SecretKeySpec(((KeyParameter) params.getParameters()).getKey(), "AES");

        encryption = Cipher.getInstance(Constants.CRYPTO_ALGORITHM, new BouncyCastleProvider());

        encryption.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV()));

        //---------------------------------------------------
        // Setup decryption.
        //---------------------------------------------------

        decryption = Cipher.getInstance(Constants.CRYPTO_SEC_KEY_SPEC, new BouncyCastleProvider());

        PBEKeySpec keySpec = new PBEKeySpec(password, salt, ITERATIONS);
        SecretKeyFactory fact = SecretKeyFactory.getInstance(Constants.CRYPTO_SEC_KEY_SPEC,
                new BouncyCastleProvider());

        try {
            decryption.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec));
        } catch (InvalidKeySpecException e) {
            ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
        }
        Constants.PROPERTIES.addProperty(Constants.SALT_KEY, s);
    }

    @Override
    public byte[] encrypt(final byte[] plain) {
        synchronized (encryption) {
            try {
                byte[] data = Base64.encode(plain);
                return encryption.doFinal(data);
            } catch (IllegalBlockSizeException e) {
                ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
            } catch (BadPaddingException e) {
                ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
            }
            return plain;
        }
    }

    @Override
    public byte[] decrypt(final byte[] encrypt) {
        synchronized (decryption) {
            try {
                byte[] data = decryption.doFinal(encrypt);
                return Base64.decode(data);
            } catch (IllegalBlockSizeException e) {
                ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
            } catch (BadPaddingException e) {
                ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
            }
            return encrypt;
        }
    }

    @Override
    public String encrypt(final String plain) {
        try {
            byte[] ciphertext = encrypt(plain.getBytes(Constants.ENCODING));
            return new String(Base64.encode(ciphertext), Constants.ENCODING);
        } catch (UnsupportedEncodingException e) {
            ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
        }
        return plain;
    }

    @Override
    public String decrypt(final String cipher) {
        try {
            byte[] data = Base64.decode(cipher.getBytes(Constants.ENCODING));
            byte[] plain = decrypt(data);
            return new String(plain);
        } catch (UnsupportedEncodingException e) {
            ExceptionUtils.fatalError(SecureCryptoImpl.class, e);
        }
        return cipher;
    }

}