1

When I initialize a Cipher object with the default AES/GCM algorithm, it has a reandom 12 bytes IV but the first 4 byte does not get incremented ater doFinal is called and throws the java.lang.IllegalStateException: Cannot re-use same key and IV for multiple encryptions exception.

SecretKey secretKey = ...

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);

byte[] iv1 = encCipher.getIV();
byte[] ctext = encCipher.doFinal("a".getBytes());
      
cipher.update("b".getBytes());
byte[] iv2 = encCipher.getIV();
ctext = encCipher.doFinal();
zjmo
  • 625
  • 2
  • 8
  • 1
    And what is your question? What are you trying to accomplish? – Artjom B. Oct 23 '20 at 18:15
  • Maybe I'm misusing the cipher. I don't understand why it uses the 12 byte IV instead of 16 if it does not increment. I have to encrypt a large file with the same 256bit key chunking it and incrementing the counter of the nonce automatically. – zjmo Oct 23 '20 at 18:23
  • Why not use a random IV for each chunk? If the chunks are independent then you can use a different IV. If they are not, do the encryption once and chunk it afterwards – Artjom B. Oct 23 '20 at 18:44
  • 1
    Kindly see this answer from @Maarten Bodewes to this topic: https://crypto.stackexchange.com/a/41610/50189. The IV/nonce length recommendation is 96 bit/12 byte is a) for compability with other programs and b) any other length require a new (internal) recalculating. – Michael Fehr Oct 23 '20 at 18:59
  • I cannot split after encryption because the ciphertext will be kept in memory until the end, in case of large file it will throw an exception because insufficient memory. – zjmo Oct 24 '20 at 06:39

1 Answers1

5

java.lang.IllegalStateException: Cannot re-use same key and IV for multiple encryptions exception.

This is for your protection and hopefully, the library keeps this behavior at least when used under the same Cipher object.

The AES-GCM internally uses AES in CTR mode for encryption and for CTR mode the reuse of the (key,IV) pair is a catastrophic failure of the confidentiality by the crib-dragging.

The AES-GCM uses 12-byte IV/nonce and the remaining is used for the counter. The first two counter values are reserved so you can encrypt at most 2^32-2 blocks and that makes 2^39-256 bits and makes around 68-GB under a single (IV, key) pair.

The 12-byte nonce is standard by the NIST 800-38d. If you supply a nonce not equal to 12-byte, then it will be processed with GHASH and the size will be 12-byte after that.

if len(IV) = 96 then 
    J_0 = IV || 0^{31}1
else 
    J_0=GHASH_H(IV||0^{s+64}||len(IV_64))

It is not advised if you use counter-based IV generation as suggested by NIST because it will make it random. Also, it will make your encryption a bit slower due to the GHASH call.

When I initialize a Cipher object with the default AES/GCM algorithm, it has a reandom 12 bytes IV but the first 4 byte does not get incremented

This is what expected. The counterpart is set to zero again. Do you want to continue where it is left since your file is larger than the counter supports? Divide the file and make chain.

  • Additionally, see What are the rules for using AES-GCM correctly?
  • Whenever a tag is incorrect, don't use the plaintext at all.
  • There is an AES-GCM-SIV mode that eliminates the (IV,key) pair misuse. It only leaks that the same message is sent again under the same IV and key.
  • TLS actually uses a new (key,IV) pair per record which has at most 2^14-byte this prevents memory fill attacks. Consider you spend your memory on decryption of 68-GB then you have seen that the tag is incorrect. Nice DOS attack point for servers.
  • Using ChaCha20-Poly1305 much easier than AES-GCM where available. It has still (IV,key)-reuse problem, though.
  • There is an XChaCha20 that uses a 192-bit nonce and 64-bit counter. That can handle very large data sizes and random nonces securely.
kelalaka
  • 5,064
  • 5
  • 27
  • 44
  • "The 12-byte nonce is standard by the NIST 800-38d. If you supply a nonce not equal to 12-byte, then it will be processed with GHASH and the size will be 12-byte after that." If I set the IV manually with GCMParameterSpec object, it is actually a 16byte IV not 12. I know that the IV must be used once so I tought that the cipjer object automatically increment the count part of the iv after submitting the cleartext for encryption. Would be fine if I input the (ciphertex+tag) to update the aad of next file segment ? – zjmo Oct 24 '20 at 06:25
  • The ciphertext is too big for aad, it can be a number between 1 and 2^64. Because it is [not processed yet](https://chromium.googlesource.com/android_tools/+/18728e9dd/sdk/sources/android-19/javax/crypto/spec/GCMParameterSpec.java)! – kelalaka Oct 24 '20 at 07:01
  • Is your file too big? – kelalaka Oct 24 '20 at 07:03
  • Yes it is big. If i split it in 4mb part should be not a problem to pass it as authentication, should be? – zjmo Oct 24 '20 at 07:08
  • How big is it? More than 68-GB in a phone? The aad can be at most 64-bit by the standard. Do you have to use AES-GCM? – kelalaka Oct 24 '20 at 07:15
  • I will set a limit to 10gb. I dont have to use AES/GCM but since it is the default algorithm for the Android Security API I would like to keep compatibility for future jetpack updates. – zjmo Oct 24 '20 at 08:36
  • Actually now I'm trying o figure out how to export keys from the Tink keyset. This would solve my problem, so that I dont have to reimplement the streamingAEAD function already present in Tink library. I know is not so good to use something withouth knowing how it works, but there is very old or completely absent documentation about this – zjmo Oct 24 '20 at 12:00
  • That it another question that you have. Why do you need to export the keys? Did you search it around? – kelalaka Oct 24 '20 at 12:42
  • Yes I did. Because otherwise the user cannot decrypt the backup offline. The master key is not exportable. I could try to decrypt the keyset with a cipher but I dont know how they have ordered the bytes – zjmo Oct 24 '20 at 13:51