|
@@ -24,61 +24,62 @@ import static org.springframework.security.crypto.util.EncodingUtils.subArray;
|
|
|
|
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.SecretKey;
|
|
import javax.crypto.SecretKey;
|
|
|
|
+import javax.crypto.spec.IvParameterSpec;
|
|
|
|
+import javax.crypto.spec.PBEKeySpec;
|
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
|
|
|
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
|
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
|
|
-import org.springframework.security.crypto.keygen.KeyGenerators;
|
|
|
|
|
|
+import org.springframework.security.crypto.util.EncodingUtils;
|
|
|
|
|
|
/**
|
|
/**
|
|
- * A general purpose encryptor for password-based encryption (PBEwith{prf}and{encryption} algorithms).
|
|
|
|
- * Prepends a random salt to each encrypted value to aid in the prevention of password compromise with the aid of a dictionary/rainbow table.
|
|
|
|
- * The salt allows the same secret key to be used for multiple encryption operations.
|
|
|
|
- * The password should be not be shared.
|
|
|
|
- * Note: {prf} = Pseudo random function e.g. MD5; {encryption} = Encryption method e.g. DES or AES.
|
|
|
|
|
|
+ * Encryptor that uses 256-bit AES encryption.
|
|
* @author Keith Donald
|
|
* @author Keith Donald
|
|
*/
|
|
*/
|
|
-final class PasswordBasedBytesEncryptor implements BytesEncryptor {
|
|
|
|
|
|
+final class AesBytesEncryptor implements BytesEncryptor {
|
|
|
|
|
|
private final SecretKey secretKey;
|
|
private final SecretKey secretKey;
|
|
|
|
|
|
- private final BytesKeyGenerator saltGenerator;
|
|
|
|
-
|
|
|
|
private final Cipher encryptor;
|
|
private final Cipher encryptor;
|
|
|
|
|
|
private final Cipher decryptor;
|
|
private final Cipher decryptor;
|
|
|
|
|
|
- public PasswordBasedBytesEncryptor(String algorithm, String password) {
|
|
|
|
- secretKey = newSecretKey(algorithm, password);
|
|
|
|
- saltGenerator = KeyGenerators.secureRandom();
|
|
|
|
- encryptor = newCipher(algorithm);
|
|
|
|
- decryptor = newCipher(algorithm);
|
|
|
|
|
|
+ private final BytesKeyGenerator ivGenerator;
|
|
|
|
+
|
|
|
|
+ public AesBytesEncryptor(String password, String salt, BytesKeyGenerator ivGenerator) {
|
|
|
|
+ PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), EncodingUtils.hexDecode(salt), 1024, 256);
|
|
|
|
+ SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
|
|
|
|
+ this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
|
|
|
+ encryptor = newCipher(AES_ALGORITHM);
|
|
|
|
+ decryptor = newCipher(AES_ALGORITHM);
|
|
|
|
+ this.ivGenerator = ivGenerator;
|
|
}
|
|
}
|
|
|
|
|
|
public byte[] encrypt(byte[] bytes) {
|
|
public byte[] encrypt(byte[] bytes) {
|
|
- byte[] salt = saltGenerator.generateKey();
|
|
|
|
- byte[] encrypted;
|
|
|
|
synchronized (encryptor) {
|
|
synchronized (encryptor) {
|
|
- initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, salt, 1024);
|
|
|
|
- encrypted = doFinal(encryptor, bytes);
|
|
|
|
|
|
+ byte[] iv = ivGenerator.generateKey();
|
|
|
|
+ initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
|
|
|
+ byte[] encrypted = doFinal(encryptor, bytes);
|
|
|
|
+ return concatenate(iv, encrypted);
|
|
}
|
|
}
|
|
- return concatenate(salt, encrypted);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
public byte[] decrypt(byte[] encryptedBytes) {
|
|
public byte[] decrypt(byte[] encryptedBytes) {
|
|
- byte[] salt = saltPart(encryptedBytes);
|
|
|
|
- byte[] decrypted;
|
|
|
|
synchronized (decryptor) {
|
|
synchronized (decryptor) {
|
|
- initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, salt, 1024);
|
|
|
|
- decrypted = doFinal(decryptor, cipherPart(encryptedBytes, salt));
|
|
|
|
|
|
+ byte[] iv = ivPart(encryptedBytes);
|
|
|
|
+ initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
|
|
|
+ return doFinal(decryptor, cipherPart(encryptedBytes, iv));
|
|
}
|
|
}
|
|
- return decrypted;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private byte[] saltPart(byte[] encrypted) {
|
|
|
|
- return subArray(encrypted, 0, saltGenerator.getKeyLength());
|
|
|
|
|
|
+ // internal helpers
|
|
|
|
+
|
|
|
|
+ private byte[] ivPart(byte[] encrypted) {
|
|
|
|
+ return subArray(encrypted, 0, ivGenerator.getKeyLength());
|
|
}
|
|
}
|
|
|
|
|
|
- private byte[] cipherPart(byte[] encrypted, byte[] salt) {
|
|
|
|
- return subArray(encrypted, salt.length, encrypted.length);
|
|
|
|
|
|
+ private byte[] cipherPart(byte[] encrypted, byte[] iv) {
|
|
|
|
+ return subArray(encrypted, iv.length, encrypted.length);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
|
|
}
|
|
}
|