简体   繁体   中英

Using Java-8 AES/GCM to authenticate / encrypt parts of a data block

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM