【问题标题】:Using Java-8 AES/GCM to authenticate / encrypt parts of a data block使用 Java-8 AES/GCM 对数据块的部分进行身份验证/加密
【发布时间】:2017-01-21 21:25:37
【问题描述】:

我的任务是使用 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 位数据进行身份验证的说明吗?

【问题讨论】:

    标签: java java-8 cryptography aes-gcm


    【解决方案1】:

    您需要使用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
    

    【讨论】:

      【解决方案2】:

      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 实例动态确定输出缓冲区的大小。

      【讨论】:

      • 我已经想知道我的随机字节初始化对生成字节数的一些奇怪的随机影响。傻我。不应该忽略这一点。
      • @Twonky BigInteger 和很多其他函数,例如整数十六进制编码,经常被错误地使用。简单提示:如果您需要二进制并且可以保持二进制,则不要转换为数字或字符串。这实际上适用于大多数类型,除非必要,否则不要转换。
      • 标签长度是否传递给 GCMParameterSpec(128) 和 aad 字节数组 (128) 的大小是否必须相同?它们有关联吗?
      猜你喜欢
      • 2018-08-20
      • 2020-05-29
      • 2014-07-14
      • 1970-01-01
      • 1970-01-01
      • 2014-11-17
      • 2015-12-28
      • 2013-10-31
      • 2013-07-17
      相关资源
      最近更新 更多