mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-26 22:02:41 +00:00
SEC-1751: Applied patch to use zero-IV for queryable text encryption.
This commit is contained in:
parent
5a4aed238c
commit
21295a58e5
@ -46,13 +46,17 @@ final class AesBytesEncryptor implements BytesEncryptor {
|
|||||||
|
|
||||||
private final BytesKeyGenerator ivGenerator;
|
private final BytesKeyGenerator ivGenerator;
|
||||||
|
|
||||||
|
public AesBytesEncryptor(String password, CharSequence salt) {
|
||||||
|
this(password, salt, null);
|
||||||
|
}
|
||||||
|
|
||||||
public AesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
|
public AesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
|
||||||
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);
|
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(salt), 1024, 256);
|
||||||
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
|
SecretKey secretKey = newSecretKey("PBKDF2WithHmacSHA1", keySpec);
|
||||||
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
this.secretKey = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
||||||
encryptor = newCipher(AES_ALGORITHM);
|
encryptor = newCipher(AES_ALGORITHM);
|
||||||
decryptor = newCipher(AES_ALGORITHM);
|
decryptor = newCipher(AES_ALGORITHM);
|
||||||
this.ivGenerator = ivGenerator;
|
this.ivGenerator = ivGenerator != null ? ivGenerator : NULL_IV_GENERATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] encrypt(byte[] bytes) {
|
public byte[] encrypt(byte[] bytes) {
|
||||||
@ -60,27 +64,41 @@ final class AesBytesEncryptor implements BytesEncryptor {
|
|||||||
byte[] iv = ivGenerator.generateKey();
|
byte[] iv = ivGenerator.generateKey();
|
||||||
initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||||
byte[] encrypted = doFinal(encryptor, bytes);
|
byte[] encrypted = doFinal(encryptor, bytes);
|
||||||
return concatenate(iv, encrypted);
|
return ivGenerator != NULL_IV_GENERATOR ? concatenate(iv, encrypted) : encrypted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] decrypt(byte[] encryptedBytes) {
|
public byte[] decrypt(byte[] encryptedBytes) {
|
||||||
synchronized (decryptor) {
|
synchronized (decryptor) {
|
||||||
byte[] iv = ivPart(encryptedBytes);
|
byte[] iv = iv(encryptedBytes);
|
||||||
initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
initCipher(decryptor, Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
|
||||||
return doFinal(decryptor, cipherPart(encryptedBytes, iv));
|
return doFinal(decryptor, ivGenerator != NULL_IV_GENERATOR ? encrypted(encryptedBytes, iv.length) : encryptedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private byte[] ivPart(byte[] encrypted) {
|
private byte[] iv(byte[] encrypted) {
|
||||||
return subArray(encrypted, 0, ivGenerator.getKeyLength());
|
return ivGenerator != NULL_IV_GENERATOR ? subArray(encrypted, 0, ivGenerator.getKeyLength()) : NULL_IV_GENERATOR.generateKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] cipherPart(byte[] encrypted, byte[] iv) {
|
private byte[] encrypted(byte[] encryptedBytes, int ivLength) {
|
||||||
return subArray(encrypted, iv.length, encrypted.length);
|
return subArray(encryptedBytes, ivLength, encryptedBytes.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
|
private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||||
|
|
||||||
|
private static final BytesKeyGenerator NULL_IV_GENERATOR = new BytesKeyGenerator() {
|
||||||
|
|
||||||
|
private final byte[] VALUE = new byte[16];
|
||||||
|
|
||||||
|
public int getKeyLength() {
|
||||||
|
return VALUE.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] generateKey() {
|
||||||
|
return VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public class Encryptors {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an encryptor for queryable text strings that uses standard password-based encryption.
|
* Creates an encryptor for queryable text strings that uses standard password-based encryption.
|
||||||
* Uses a shared, or constant 16 byte initialization vector so encrypting the same data results in the same encryption result.
|
* Uses a 16-byte all-zero initialization vector so encrypting the same data results in the same encryption result.
|
||||||
* This is done to allow encrypted data to be queried against.
|
* This is done to allow encrypted data to be queried against.
|
||||||
* Encrypted text is hex-encoded.
|
* Encrypted text is hex-encoded.
|
||||||
*
|
*
|
||||||
@ -60,7 +60,7 @@ public class Encryptors {
|
|||||||
* @param salt a hex-encoded, random, site-global salt value to use to generate the secret key
|
* @param salt a hex-encoded, random, site-global salt value to use to generate the secret key
|
||||||
*/
|
*/
|
||||||
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
|
public static TextEncryptor queryableText(CharSequence password, CharSequence salt) {
|
||||||
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(), salt, KeyGenerators.shared(16)));
|
return new HexEncodingTextEncryptor(new AesBytesEncryptor(password.toString(), salt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user