Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreThis is a continuation of CVE-2020-5408.
Applications using AesBytesEncryptor with the two-argument constructor or when passing a null IV generator and CBC as the encryption mode encrypt data with AES/CBC using a null (all-zero) initialization vector. Because the IV is fixed, identical plaintexts always produce identical ciphertext for a given password and salt, regardless of when or how many times the value was encrypted.
An attacker with read access to the encrypted data store can exploit this property to determine when two records share the same plaintext value, correlate encrypted values across rows or users, and mount dictionary attacks by pre-encrypting candidate values and comparing the results.
Spring Security:
| Fix version | Availability |
|---|---|
| 7.1.1 | OSS |
| 7.1.0.1 | Enterprise Support Only |
| 7.0.7 | OSS |
| 7.0.6.1 | Enterprise Support Only |
| 6.5.12 | Enterprise Support Only |
| 6.4.19 | Enterprise Support Only |
| 5.8.28 | Enterprise Support Only |
| 5.7.26 | Enterprise Support Only |
Users should review the migration guide to determine whether data re-encryption is also required.
This release introduces AesCbcBytesEncryptor and AesGcmBytesEncryptor as secure replacements for AesBytesEncryptor, which is now deprecated.
Encryptors.standard(), Encryptors.stronger(), Encryptors.text(), and Encryptors.delux() are deprecated for the same reason.
If you supplied a SecretKey--either with CipherAlgorithm.CBC and a non-null ivGenerator or with CipherAlgorithm.GCM--the new encryptors produce byte-for-byte equivalent ciphertext.
In those cases, the code can be updated in the following way with no further steps:
| Deprecated | Replace With |
|---|---|
| AesBytesEncryptor(secretKey, null, CipherAlgorithm.GCM) | AesGcmBytesEncryptor.withSecretKey(SecretKey).build() |
| AesBytesEncryptor(secretKey, ivGenerator, CipherAlgorithm.GCM) | AesGcmBytesEncryptor.withSecretKey(SecretKey).ivGenerator(ivGenerator).build() |
| AesBytesEncryptor(secretKey, ivGenerator, CipherAlgorithm.CBC) | AesCbcBytesEncryptor.withSecretKey(SecretKey).ivGenerator(ivGenerator).build() |
If you are using the Encryptors API, are using AesBytesEncryptor with a password, or are using CipherAlgorithm.CBC with a null ivGenerator, the old and new encryptors are not compatible for one or more of the following reasons:
In these cases, ciphertext written by an old encryptor can only be decrypted by an old encryptor instance, so a direct swap is not possible without a migration step.
The replacement APIs in these cases are as follows:
| Deprecated | Replaced By |
|---|---|
| Encryptors.standard() | AesCbcBytesEncryptor.withPassword |
| Encryptors.stronger() | AesGcmBytesEncryptor.withPassword |
| Encryptors.text() | AesCbcBytesEncryptor.withPassword, then hex-encode/decode the bytes yourself (e.g. with org.springframework.security.crypto.codec.Hex) |
| Encryptors.delux() | AesGcmBytesEncryptor.withPassword, then hex-encode/decode the bytes yourself (e.g. with org.springframework.security.crypto.codec.Hex) |
| AesBytesEncryptor(password, salt) | AesCbcBytesEncryptor.withPassword(password, salt) |
| AesBytesEncryptor(..., CipherAlgorithm.CBC) | AesCbcBytesEncryptor.withPassword |
| AesBytesEncryptor(..., CipherAlgorithm.GCM) | AesGcmBytesEncryptor.withPassword |
Encryptors.text() and Encryptors.delux() return a TextEncryptor that hex-encodes its output, whereas AesCbcBytesEncryptor/AesGcmBytesEncryptor return a BytesEncryptor operating on raw bytes, so callers that need string-in/string-out semantics are responsible for the encoding step themselves.
Spring Security offers no migration API for encrypted material, but the effort should be quite similar to when your organization rotates the encryption password or secret key as a normal business operation. While you should perform your own analysis to decide how to migrate your data, the following pseudocode illustrates what this could look like:
BytesEncryptor v1 = Encryptors.stronger(oldPassword, salt);
BytesEncryptor v2 = AesGcmBytesEncryptor.withPassword(newPassword, salt);
for (Entity e : entities) {
byte[] b = e.getEncryptedData();
e.setEncryptedData(v2.encrypt(v1.decrypt(b)));
e.save();
}
Note that since this migration upgrades the key derivation algorithm, it is a good opportunity to rotate the password, as this snippet additionally illustrates.
To report a security vulnerability for a project within the Spring portfolio, see the Security Policy