AES CTR模式的互操作性?

时间:2012-09-21 11:28:03

标签: cryptography aes commoncrypto ctr-mode

我在CTR模式下使用AES128加密进行加密,为不同的客户端(Android / Java和iOS / ObjC)实现。加密数据包时使用的16字节IV格式如下:

<11 byte nonce> | <4 byte packet counter> | 0

对于发送的每个数据包,数据包计数器(包含在已发送的数据包中)增加1。最后一个字节用作块计数器,因此少于256个块的数据包始终获得唯一的计数器值。我假设CTR模式指定计数器应该为每个块增加1,使用8个最后字节作为计数器以大端方式,或者这至少是事实上的标准。在Sun加密实现中似乎也是如此。

当相应的iOS实现(使用CommonCryptor,iOS 5.1)无法解码除解码数据包之外的第一个块时,我感到有些惊讶。似乎CommonCryptor以其他方式定义了计数器。 CommonCryptor可以在big endian和little endian模式下创建,但CommonCryptor代码中的一些模糊注释表明这不是(或至少没有)完全支持:

http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-60026/Source/API/CommonCryptor.c

/* corecrypto only implements CTR_BE.  No use of CTR_LE was found so we're marking
   this as unimplemented for now.  Also in Lion this was defined in reverse order.
   See <rdar://problem/10306112> */

通过逐块解码,每次按照上面的说明设置IV,它都可以很好地工作。

我的问题:在单次解码中解码多个块时,是否存在实现CTR / IV模式的“正确”方式,或者在使用不同的加密库时我是否可以期望它是互操作性问题? CommonCrypto在这方面是否存在漏洞,或者仅仅是以不同方式实施CTR模式的问题?

2 个答案:

答案 0 :(得分:4)

NIST recommendation sp800-38a Appendix B中(松散地)指定了计数器的定义。请注意,NIST仅指定如何在安全性方面使用CTR模式;它没有为计数器定义一个标准算法。

要直接回答您的问题,无论您做什么,您都应该期望计数器每次增加1。根据NIST规范,计数器应代表128位大端整数。可能只有最低有效位(最右边)位会递增,但除非传递2 ^ 32 - 1或2 ^ 64 - 1值,否则通常不会产生差异。

为了兼容性,你可以决定使用第一个(最左边的)12个字节作为 random nonce,并将后者保留为零,然后让实现CTR的增量。在这种情况下,您只需在开始时使用96位/ 12字节随机,在这种情况下,不需要数据包计数器。

然而,在计数器耗尽所有可用位之前,您将被限制为2 ^ 32 * 16字节的明文。如果计数器返回零或者nonce本身包含在计数器中,那么它是特定于实现的,因此您可能希望将自己限制为68,719,476,736 = ~68 GB的消息(是的,基数为10,Giga 意味着 1,000,000,000)。

  • 由于生日问题,你有2 ^ 48的机会(48 = 96/2)为nonce创建一个碰撞(每个消息所需,而不是每个块) ,所以你应该限制消息的数量;
  • 如果某个攻击者欺骗你为同一个nonce解密2 ^ 32个数据包,你的计数器用完了。

如果这仍然不兼容(测试!),则使用最初的8个字节作为nonce。不幸的是,这确实意味着由于生日问题,您需要限制邮件数量。

答案 1 :(得分:3)

进一步调查揭示了CommonCrypto问题:

在iOS 6.0.1中,little endian选项现在未实现。此外,我已经验证了CommonCrypto的错误,因为CCCryptorReset方法实际上并没有改变IV,而是使用预先存在的IV。 6.0.1中的行为与5.x不同。

如果您使用无效的IV初始化CommonCrypto,并且在加密之前将其重置为实际IV,则可能存在安全危险。这将导致您的所有数据使用相同(无效)IV进行加密,并且多个流(可能应该具有不同的IV但使用相同的密钥)将通过具有相应ctr的简单XOR数据包泄漏数据。