19

I'm using AES GCM authentication in my android project and it works fine. But getting some issues with authentication tag when it compare with openssl API generate tag. Please find the java code below:

SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
byte[] iv = generateRandomIV();
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
int outputLength = cipher.getOutputSize(data.length); // Prepare output buffer
byte[] output = new byte[outputLength];
int outputOffset = cipher.update(data, 0, data.length, output, 0);// Produce cipher text
outputOffset += cipher.doFinal(output, outputOffset);

I am using openssl for the same in iOS and generating authentication tag using below code

NSMutableData* tag = [NSMutableData dataWithLength:tagSize];
EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, [tag length], [tag mutableBytes])

In java or bouncy castle, not able to get the exact authentication tag which openssl return and can you help me to resolve this issue. Thanks

Oleg Estekhin
  • 8,063
  • 5
  • 49
  • 52
user3656812
  • 191
  • 1
  • 1
  • 3
  • Can you clarify what is the exact problem? Do you need to configure the tag length or do you want to get the tag value from the cipher ? – Oleg Estekhin May 26 '14 at 07:33
  • Thank Oleg Estekhin. I am trying to get the tag value from cipher as same as the openssl generated tag. – user3656812 May 26 '14 at 09:25

1 Answers1

30

In Java the tag is unfortunately added at the end of the ciphertext. You can configure the size (in bits, using a multiple of 8) using GCMParameterSpec - it defaults to the full size of 128 bits otherwise. You can therefore grab the tag using Arrays.copyOfRange(ciphertext, ciphertext.length - (tagSize / Byte.SIZE), ciphertext.length) if you really want to.

It is unfortunate since the tag does not have to be put at the end, and it messes up the online nature of GCM decryption - requiring internal buffering instead of being able to directly return the plaintext. On the other hand, the tag is automatically verified during decryption.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • 1
    I've just discovered myself that the AES/GCM cipher will keep an ever growing internal buffer that sooner or later outgrow the Java memory heap space for really large decryption operations. The cipher doing decryption will write 0 bytes during calls to update() and finally, doFinal() output all the decoded buffered bytes. That is unfortunate in many ways. For example, Cipher.update(ByteBuffer, ByteBuffer) require the target buffer to have a capacity at least that of Cipher.getOutputSize() or a ShortBufferException is thrown. Cipher.getOutputSize() continuously increase ... [see next comment] – Martin Andersson Nov 13 '14 at 19:26
  • 1
    ... the reported required size (as the internal buffer grow) forcing my application as well to allocated bigger and bigger target ByteBuffers despite Cipher.update() not ever writting one single byte to the allocated ByteBuffers :'( I think the solution for me here is to split the files to 1 mb chunks either in direct memory or on disk and then patch the chunks together once the whole process is done. I'm not a crypto guy but you say that the current design of Java is flawed. If it could be made in another way, then surely it is as my own amateur experience prove. [see next comment] – Martin Andersson Nov 13 '14 at 19:28
  • 3
    But! Correct me if I am wrong - which I must be - isn't it so that the MAC is a hash of all input bytes? Then surely the implementation must "remember" all bytes in order to compute the MAC? That would explain why the MAC, or "authentication tag" in this case, is put at the end of the ciphertext and that explains the internal buffering? Please elaborate on this issue if you will because it matters so much to me, and probably many others. Thank you owlstead! You're amazing. – Martin Andersson Nov 13 '14 at 19:28
  • Try the bouncy castle provider code instead. It should only buffer the maximum tag size, if I'm not mistaken. You should only *use* the plaintext after MAC verification, but GCM uses CTR internally, it should be easy to *store* the plaintext before using it. – Maarten Bodewes Nov 13 '14 at 19:28
  • 2
    Done. See [http://stackoverflow.com/q/26920906/1268003](http://stackoverflow.com/q/26920906/1268003). – Martin Andersson Nov 14 '14 at 00:19