问题
I am writing a simple app to encrypt my message using AES / CBC (mode). As my understanding CBC mode requires IV parameter but I don't know why my code work without IV parameter used. Anyone can explain why? Thanks.
The encrypted message printed: T9KdWxVZ5xStaisXn6llfg== without exception.
public class TestAES {
public static void main(String[] args) {
try {
byte[] salt = new byte[8];
new SecureRandom().nextBytes(salt);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec("myPassword".toCharArray(), salt, 100, 128);
SecretKey tmp = keyFactory.generateSecret(keySpec);
SecretKeySpec key = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
enCipher.init(Cipher.ENCRYPT_MODE, key);
// enCipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] cipherBytes = enCipher.doFinal("myMessage".getBytes());
String cipherMsg = BaseEncoding.base64().encode(cipherBytes);
System.out.println("Encrypted message: " + cipherMsg);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
回答1:
When it is used without an IV, for certain types of ciphers including AES, it implicitly uses 0 IV. See Cipher class documentation.
The disadvantage of a null IV (or a deterministic IV) is that it is vulnerable to dictionary attacks. The requirement for IV is to prevent the same plain text block producing the same cipher text every time.
回答2:
Like other users have said, it depends on the JCE provider. Java SE generates a random IV for you if you specify none.
Only Android1 and Javacard API use a blank IV, which is non-conforming to the Java Crypto spec, which states:
If this cipher requires any algorithm parameters that cannot be derived from the given
key
, the underlying cipher implementation is supposed to generate the required parameters itself (using provider-specific default or random values) if it is being initialized for encryption or key wrapping, and raise anInvalidKeyException
if it is being initialized for decryption or key unwrapping. The generated parameters can be retrieved usinggetParameters
orgetIV
(if the parameter is an IV).
If you do not specify the IV, in Java SE you get a random one, and will need to retrieve it with cipher.getIV()
and store it, as it will be needed for decryption.
But better yet, generate a random IV yourself and provide it via IvParameterSpec
.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
rnd.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivParams);
byte[] ciphertext = cipher.doFinal(input.getBytes());
1That could be because Android is Java-esque, like the Eminem-esque ad. Just guessing, that's all.
来源:https://stackoverflow.com/questions/20888851/does-aes-cbc-really-requires-iv-parameter