Reputation: 53
I want to make a function encrypt data by GCM mode with authentication tag for Android. This is my source code:
public static byte[] GCMEncrypt(String hexKey, String hexIV, byte[] aad) throws Exception {
byte[] aKey = hexStringToByteArray(hexKey);
byte[] aIV = hexStringToByteArray(hexIV);
Key key = new SecretKeySpec(aKey, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(16 * Byte.SIZE, aIV));
cipher.updateAAD(aad);
byte[] encrypted = cipher.doFinal(aKey);
return encrypted;
}
How to insert authentication tag into this code?
Upvotes: 2
Views: 4865
Reputation: 93988
You already have included the authentication tag. Java (unfortunately - see below) includes the authentication tag in the ciphertext. That means that it is generated during that last call to doFinal
.
You can easily check this by viewing the size of the ciphertext. It should be the same size as the plaintext (in this case aKey
) plus 128 bits, the default and sensible size of the authentication tag.
This is also why AEADBadTagException
is derived from BadPaddingException
: during decryption the verification takes place implicitly. So older code would still be compatible with GCM mode.
As I indicated earlier I think including the authentication tag in the ciphertext is a major design mistake for an API:
In my opinion that doesn't weigh up to the advantages of retrofitting the Cipher
class without adding methods and maintaining compatibility. It would have been better if the designer had just added methods for retrieving and verifying the authentication tag separately.
Because it is currently raining I have created an example:
public static void main(String... args) throws Exception {
int tagSize = 96;
Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey aesKey = new SecretKeySpec(new byte[16], "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(tagSize, new byte[gcm.getBlockSize()]);
gcm.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpec);
byte[] pt = "Maarten Bodewes creates code".getBytes(StandardCharsets.UTF_8);
System.out.println(pt.length);
byte[] ctAndTag = new byte[gcm.getOutputSize(pt.length)];
System.out.println(ctAndTag.length);
int off = 0;
off += gcm.update(pt, 0, pt.length, ctAndTag, off);
// prints 16 (for the Oracle crypto provider)
// meaning it is not online, buffering even during encryption
System.out.println(off);
off += gcm.doFinal(new byte[0], 0, 0, ctAndTag, off);
// prints 40 for the Oracle crypto provider, meaning it doesn't *just*
// output the tag during doFinal !
System.out.println(off);
int ctSize = ctAndTag.length - tagSize / Byte.SIZE;
System.out.println(ctSize);
byte[] ct = Arrays.copyOfRange(ctAndTag, 0, ctSize);
byte[] tag = Arrays.copyOfRange(ctAndTag, ctSize, ctAndTag.length);
System.out.println(Hex.toHexString(ct));
System.out.println(Hex.toHexString(tag));
}
Notes:
Upvotes: 5