I've been doing some learning/experimentation with the basic Java AES stuff, and I can't figure out where I'm doing things wrong. According to the docs, doFinal() should encrypt/decrypt everything in one shot, and it does appear to do so; however, on decryption, with an invalid IV, I can still decrypt most of the data. In the interest of security, please tell me where the heck I messed up in my test code?
Notes: I am not using BC or the Java Unlimited Strength Crypto Extensions. This code follows examples and guidance from The Oracle JCA Reference Guide. In the code below, I select AES with CFB (same results with CBC), generate a key, generate an IV, feed encrypt, nuke the IV, and feed decrypt, and ideally (if I understand CBC and CFB correctly) the nuked IV should render the decrypted output into garbage. But it does not...at least, not on my installation...
It should also be noted that GCM does work correctly (you'll no doubt see the commented-out algo string below), but it bothers me that CBC and CFB are acting this way. Reality-check, please?
public static void encdec() throws Exception {
// let's encrypt something!
String message = "This is a super-secret message. Don't read this message. This message will self-destruct...";
final String symmetricCipherSpec = "AES/CFB/PKCS5Padding";// "AES/GCM/NoPadding";
final String symmetricKeySpec = "AES";
System.out.println("\n\nSelecting plaintext cypher...");
Cipher cipher = Cipher.getInstance(symmetricCipherSpec);
// What did we get?
System.out.println("--> Cipher Algorithm Selected: " + cipher.getAlgorithm());
AlgorithmParameters parameters = cipher.getParameters();
System.out.println("--> Parameters for algo: " + parameters.getAlgorithm());
System.out.println("--> block size: " + cipher.getBlockSize());
final int blockSize = cipher.getBlockSize();
KeyGenerator keyGenerator = KeyGenerator.getInstance(symmetricKeySpec);
keyGenerator.init(128);
Key key = keyGenerator.generateKey();
System.out.println("\nsymmetric key = " + Hex.encodeHexString(key.getEncoded()));
// set up for encryption
int tLen = 16;
byte[] basicIV = new byte[tLen];
for (int i = 0; i < basicIV.length; i++) {
basicIV[i] = (byte) i;
}
byte[] messageToEncrypt = message.getBytes();
IvParameterSpec ivSpec = new IvParameterSpec(basicIV);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encryptedMessage = cipher.doFinal(messageToEncrypt);
System.out.println("\nencrypted = " + Hex.encodeHexString(encryptedMessage));
byte[] iv = cipher.getIV();
System.out.println("iv = " + Hex.encodeHexString(iv) + " (len=" + iv.length + ")");
// reset IV to garbage.
basicIV = new byte[tLen];
ivSpec = new IvParameterSpec(basicIV);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = cipher.doFinal(encryptedMessage);
System.out.println("\ndecrypted = " + new String(decrypted));
System.out.println("original = " + message);
System.out.println("iv = " + Hex.encodeHexString(cipher.getIV()) + " (len=" + cipher.getIV().length + ")");
}