Java tutorial
/****************************************************************************** * 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; } }