Selaa lähdekoodia

SEC-1751: Applied patch to use zero-IV for queryable text encryption.

Luke Taylor 14 vuotta sitten
vanhempi
commit
21295a58e5

+ 26 - 8
core/src/main/java/org/springframework/security/crypto/encrypt/AesBytesEncryptor.java

@@ -46,13 +46,17 @@ final class AesBytesEncryptor implements BytesEncryptor {
 
     private final BytesKeyGenerator ivGenerator;
 
+    public AesBytesEncryptor(String password, CharSequence salt) {
+        this(password, salt, null);
+    }
+
     public AesBytesEncryptor(String password, CharSequence salt, BytesKeyGenerator ivGenerator) {
         PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), Hex.decode(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;
+        this.ivGenerator = ivGenerator != null ? ivGenerator : NULL_IV_GENERATOR;
     }
 
     public byte[] encrypt(byte[] bytes) {
@@ -60,27 +64,41 @@ final class AesBytesEncryptor implements BytesEncryptor {
             byte[] iv = ivGenerator.generateKey();
             initCipher(encryptor, Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
             byte[] encrypted = doFinal(encryptor, bytes);
-            return concatenate(iv, encrypted);
+            return ivGenerator != NULL_IV_GENERATOR ? concatenate(iv, encrypted) : encrypted;
         }
     }
 
     public byte[] decrypt(byte[] encryptedBytes) {
         synchronized (decryptor) {
-            byte[] iv = ivPart(encryptedBytes);
+            byte[] iv = iv(encryptedBytes);
             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
 
-    private byte[] ivPart(byte[] encrypted) {
-        return subArray(encrypted, 0, ivGenerator.getKeyLength());
+    private byte[] iv(byte[] encrypted) {
+        return ivGenerator != NULL_IV_GENERATOR ? subArray(encrypted, 0, ivGenerator.getKeyLength()) : NULL_IV_GENERATOR.generateKey();
     }
 
-    private byte[] cipherPart(byte[] encrypted, byte[] iv) {
-        return subArray(encrypted, iv.length, encrypted.length);
+    private byte[] encrypted(byte[] encryptedBytes, int ivLength) {
+        return subArray(encryptedBytes, ivLength, encryptedBytes.length);
     }
 
     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;
+        }
+
+    };
 }

+ 2 - 2
core/src/main/java/org/springframework/security/crypto/encrypt/Encryptors.java

@@ -52,7 +52,7 @@ public class Encryptors {
 
     /**
      * 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.
      * 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
      */
     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));
     }
 
     /**