2

We're using Cipher and CipherInputStream in an Android app to decrypt files downloaded from a server.

For some reason, all the calls to Cipher.update return an empty block and the call to Cipher.doFinal returns the entire file in one block.

This causes OOM on large files.

This is the code we use to initialize the cipher:

final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(keyData, "AES");
GCMParameterSpec nonce = new GCMParameterSpec(128, nonceData);
cipher.init(Cipher.DECRYPT_MODE, key, nonce);
  1. Why is this happening?
  2. Is this something that can be fixed on the client side?

Note: I don't currently have access to the server's code. When I have I will post it too. Note 2: This happens on Android API 25.0.1

daramasala
  • 3,040
  • 2
  • 26
  • 33

1 Answers1

1

Good question! It's because you're using GCM mode. The authentication tag can't be checked until all of the data has been received from the server, so Java automatically buffers this data, checks it, and then gives you the final data once the tag has been checked.

GCM mode is excellent for relatively small message sizes or files, but large files shouldn't be encrypted with GCM mode.

You might prefer to use CBC mode with an HMAC, stream the file to disk, validate the HMAC and then decrypt. It's more roundabout, but avoids the issue you're currently having.

Luke Joshua Park
  • 9,527
  • 5
  • 27
  • 44