1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
private static final String ENCRYPT_ALGORITHM = "AES";
private static final String AES_CBC_CIPHER_SPEC = "AES/CBC/PKCS5Padding";
private static final String AES_CBC_KEYGEN_SPEC = "PBKDF2WithHmacSHA1";
private static final int AES_CBC_SALT_LENGTH = 16; // in bytes = N x 8 bits
private static final int AUTH_KEY_LENGTH = 8; // in bytes
private static final int ITERATIONS = 32768;
public static void encryptAESCBC(int lKeyLength, String pPassword, InputStream pInput, OutputStream pOutput)
throws EncryptionException, IOException {
// Check validity of key length
if (lKeyLength != 128 && lKeyLength != 192 && lKeyLength != 256) {
throw new EncryptionException("Invalid AES key length: " + lKeyLength);
}
// generate salt and derive keys for authentication and encryption
SecureRandom lSecureRandom = new SecureRandom();
byte[] lSalt = getByteArrayFromRandom(lSecureRandom, AES_CBC_SALT_LENGTH);
Keys lKeys = keygenAESCBC(lKeyLength, pPassword.toCharArray(), lSalt);
// initialize AES encryption
Cipher lEncrypt = null;
try {
lEncrypt = Cipher.getInstance(AES_CBC_CIPHER_SPEC);
lEncrypt.init(Cipher.ENCRYPT_MODE, lKeys.encryption);
} catch (NoSuchAlgorithmException exc) {
throw new EncryptionException(
"Transformation is null, empty, in an invalid format, or no Provider supports a CipherSpiimplementation for the specified algorithm",
exc);
} catch (NoSuchPaddingException exc) {
throw new EncryptionException("Transformation contains a padding scheme that is not available", exc);
} catch (InvalidKeyException exc) { // 192 or 256-bit AES not available
throw new EncryptionException(lKeyLength + "-bit AES encryption is not available on this Java platform.", exc);
}
// get initialization vector
byte[] lIv = null;
try {
lIv = lEncrypt.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
} catch (InvalidParameterSpecException exc) {
throw new EncryptionException("Invalid parameter for initialization vector", exc);
}
// write authentication and AES initialization data
pOutput.write(lKeyLength / 8);
pOutput.write(lSalt);
pOutput.write(lKeys.authentication.getEncoded());
pOutput.write(lIv);
// read data from input into buffer, encrypt and write to output
byte[] lBuffer = new byte[BUFFER_SIZE];
int lNumRead;
byte[] lEncrypted = null;
while ((lNumRead = pInput.read(lBuffer)) > 0) {
lEncrypted = lEncrypt.update(lBuffer, 0, lNumRead);
if (lEncrypted != null) {
pOutput.write(lEncrypted);
}
}
try { // finish encryption - do final block
lEncrypted = lEncrypt.doFinal();
} catch (IllegalBlockSizeException | BadPaddingException exc) {
throw new EncryptionException("Exception when doing doFinal", exc);
}
if (lEncrypted != null) {
pOutput.write(lEncrypted);
}
}
private static byte[] getByteArrayFromRandom(SecureRandom pSecureRandom, int pLength) {
byte[] lSalt = new byte[pLength];
pSecureRandom.nextBytes(lSalt);
return lSalt;
}
private static Keys keygenAESCBC(int pKeyLength, char[] pPassword, byte[] pSalt) throws EncryptionException {
SecretKeyFactory lFactory;
try {
lFactory = SecretKeyFactory.getInstance(AES_CBC_KEYGEN_SPEC);
} catch (NoSuchAlgorithmException impossible) {
return null;
}
// derive a longer key, then split into AES key and authentication key
KeySpec lSpec = new PBEKeySpec(pPassword, pSalt, ITERATIONS, pKeyLength + AUTH_KEY_LENGTH * 8);
SecretKey lTmp = null;
try {
lTmp = lFactory.generateSecret(lSpec);
} catch (InvalidKeySpecException impossible) {
// TODO
}
byte[] lFullKey = lTmp.getEncoded();
SecretKey lAuthKey = new SecretKeySpec( // key for password authentication
Arrays.copyOfRange(lFullKey, 0, AUTH_KEY_LENGTH), ENCRYPT_ALGORITHM);
SecretKey lEncKey = new SecretKeySpec( // key for AES encryption
Arrays.copyOfRange(lFullKey, AUTH_KEY_LENGTH, lFullKey.length), ENCRYPT_ALGORITHM);
return new Keys(lEncKey, lAuthKey);
}
private static class Keys {
public final SecretKey encryption, authentication;
public Keys(SecretKey pEncryption, SecretKey pAuthentication) {
this.encryption = pEncryption;
this.authentication = pAuthentication;
}
} |
Partager