I'm using AES/GCM/NoPadding
encryption in Java 8 and I'm wondering whether my code has a security flaw. My code seems to work, in that it encrypts and decrypts text, but a few details are unclear.
My main question is this:
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????
Does that IV satisfy the requirement of "For a given key, the IV MUST NOT repeat." from RFC 4106?
I'd also appreciate any answers / insight for my related questions (see below), but that first question is bugging me the most. I don't know where to find source code or documentation that answers this.
Here is the full code, roughly. I apologize in case I introduced errors while writing this post:
class Encryptor {
Key key;
Encryptor(byte[] key) {
if (key.length != 32) throw new IllegalArgumentException();
this.key = new SecretKeySpec(key, "AES");
}
// the output is sent to users
byte[] encrypt(byte[] src) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // See question #1
assert iv.length == 12; // See question #2
byte[] cipherText = cipher.doFinal(src);
assert cipherText.length == src.length + 16; // See question #3
byte[] message = new byte[12 + src.length + 16]; // See question #4
System.arraycopy(iv, 0, message, 0, 12);
System.arraycopy(cipherText, 0, message, 12, cipherText.length);
return message;
}
// the input comes from users
byte[] decrypt(byte[] message) throws Exception {
if (message.length < 12 + 16) throw new IllegalArgumentException();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
cipher.init(Cipher.DECRYPT_MODE, key, params);
return cipher.doFinal(message, 12, message.length - 12);
}
}
Suppose that users cracking my secret key = game over.
More detailed questions / related questions:
Is the IV returned by cipher.getIV() safe for me to use in this way?
- Does it avoid the catastrophe of reusing the IV,key combination in Galois/Counter Mode?
- Is it still safe when I have multiple applications running this code at once, all displaying encrypted messages to users from the same src data (possibly in the same millisecond)?
- What's the returned IV made of? Is it an atomic counter plus some random noise?
- Do I need to avoid
cipher.getIV()
and construct an IV myself, with my own counter? - Is the source code implementing
cipher.getIV()
available online somewhere, assuming I'm using Oracle JDK 8 + JCE Unlimited Strength extension?
Is that IV always 12 bytes long?
Is the authentication tag always 16 bytes (128 bits) long?
With #2 and #3, and the lack of padding, does that mean my encrypted messages are always
12 + src.length + 16
bytes long? (And so I can safely squish them into one byte array, for which I know the correct length?)Is it safe for me to display an unbounded number of src data encryptions to users, given constant src data that the users know?
Is it safe for me to display an unbounded number of src data encryptions to users, if the src data is different every time (e.g. including
System.currentTimeMillis()
or random numbers)?Would it help if I padded the src data with random numbers before encryption? Say 8 random bytes in front and back, or only on one end? Or would that not help at all / make my encryption worse?
(Because these questions are all about the same block of my own code, and they are strongly related to each other, and others might/should have the same set of questions when implementing the same functionality, it felt wrong to split the questions into multiple posts. I can re-post them separately if that is more appropriate for StackOverflow's format. Let me know!)