Reputation: 806
My task is to use a special feature of AES/GCM to authenticate part A and encrypt part B of a single data block. I have problems with implementing the solution using Java-8.
The following example uses a data block of 256 bit. The first 128 bit shall be authenticated only. The following 128 bit shall be encrypted. The resulting tag for the combined operation is expected to be 128 bit.
I believe I was able to implement an encryption-only variant which encrypts both 128 bit data blocks.
SecureRandom random = new SecureRandom();
byte[] initVector = new BigInteger(96, random).toByteArray();
byte[] data = new BigInteger(255, random).toByteArray();
byte[] key = new BigInteger(255, random).toByteArray();
byte[] encrypted = new byte[data.length];
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(16 * Byte.SIZE, initVector));
cipher.update(data, 0, data.length, encrypted, 0);
byte[] tag = cipher.doFinal();
Could anybody give instructions on how to modify the code so that the first 128 bit of data are only authenticated?
Upvotes: 1
Views: 5557
Reputation: 94018
Matt is right that you need to use updateAAD
. But there are many other things wrong.
For instance, you cannot just use BigInteger
to create random values. The problem is that for some values there will be an additional 00
value to the left (to encode an unsigned integer) and sometimes it is not. And it may generate too few bytes as well if the number is small.
Furthermore, in Java the tag is considered part of the ciphertext. That's a mistake in my opinion, and it really hurts functionality. But currently that's how it is.
A better way to program this would be something like this:
// --- create cipher
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// --- generate new AES key
KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
aesKeyGen.init(256);
SecretKey aesKey = aesKeyGen.generateKey();
// --- generate IV and GCM parameters
SecureRandom random = new SecureRandom();
byte[] initVector = new byte[96 / Byte.SIZE];
random.nextBytes(initVector);
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initVector);
cipher.init(Cipher.ENCRYPT_MODE, aesKey,
gcmParameterSpec);
// --- process any AAD (just a bunch of zero bytes in this example)
byte[] aad = new byte[128];
cipher.updateAAD(aad);
// --- process any data (just a bunch of zero bytes in this example)
byte[] data = new byte[128];
// use cipher itself to create the right buffer size
byte[] encrypted = new byte[cipher.getOutputSize(data.length)];
int updateSize = cipher.update(data, 0, data.length, encrypted, 0);
cipher.doFinal(encrypted, updateSize);
It generates all the parameters differently and it determines the size of the output buffer dynamically through the Cipher
instance.
Upvotes: 1
Reputation: 79773
You need to use one of the updateAAD
methods.
In your case, something like this (note you need to make the updateAAD
calls before the update
or doFinal
calls):
cipher.updateAAD(data, 0, 128); // first 128 bits are authenticated
cipher.update(data, 128, 128, encrypted, 0); // next 128 are encrypted
Upvotes: 3