使用 Java-8 AES/GCM 验证/加密数据块的一部分

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

我的任务是使用AES/GCM的一个特殊功能来验证单个数据块的A部分和加密B部分。我在使用 Java-8.

实施解决方案时遇到问题

以下示例使用256位的数据块。前 128 位应仅被认证。接下来的 128 位将被加密。组合操作的结果标签预计为 128 位。

我相信我能够实现加密两个 128 位数据块的纯加密变体。

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();

任何人都可以提供有关如何修改代码以便只验证前 128 位数据的说明吗?

您需要使用 updateAAD methods 之一。

在您的情况下,是这样的(请注意,您需要在 updatedoFinal 调用之前进行 updateAAD 调用 :

cipher.updateAAD(data, 0, 128);              // first 128 bits are authenticated
cipher.update(data, 128, 128, encrypted, 0); // next 128 are encrypted

Matt 说得对,您需要使用 updateAAD。但是还有很多地方不对。

例如,您不能只使用 BigInteger 来创建随机值。问题是对于某些值,左侧会有一个额外的 00 值(用于编码无符号整数),有时却没有。如果数量少,也可能生成的字节太少。

此外,在 Java 中,标签被视为密文的一部分。我认为这是一个错误,它确实会损害功能。但目前就是这样。

更好的编程方式是这样的:

// --- 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);

它以不同的方式生成所有参数,并通过 Cipher 实例动态确定输出缓冲区的大小。