【发布时间】:2012-09-13 19:43:49
【问题描述】:
我在 CTR 模式下使用 AES128 加密进行加密,针对不同的客户端(Android/Java 和 iOS/ObjC)实施。加密数据包时使用的 16 字节 IV 格式如下:
<11 byte nonce> | <4 byte packet counter> | 0
每发送一个数据包,数据包计数器(包含在发送的数据包中)就会增加一。最后一个字节用作块计数器,因此少于 256 个块的数据包总是获得唯一的计数器值。我假设 CTR 模式指定计数器应该为每个块增加 1,以大端方式使用最后 8 个字节作为计数器,或者这至少是事实上的标准。 Sun 加密实现中似乎也是这种情况。
当相应的 iOS 实现(使用 CommonCryptor,iOS 5.1)在解码数据包时未能解码除第一个块之外的每个块时,我有点惊讶。似乎 CommonCryptor 以其他方式定义了计数器。 CommonCryptor 可以在 big endian 和 little endian 模式下创建,但是 CommonCryptor 代码中的一些模糊的 cmets 表明这不是(或至少没有)完全支持:
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 模式的问题?
【问题讨论】:
-
计数器中包含多少位似乎变化很大。有些使用 64 位,有些使用整个 128 位。但这对您的情况应该没有任何影响,因为 LSB 为 0,并且每个 IV 的块数永远不会超过 256 个。
-
@CodesInChaos 确实如此,而且您加密超过 2^64 个块的机会也不高,因此前 64 位将不受影响。
-
@owlstead 2^32 个数据包足以潜在地导致翻转到 OP 方案中的最高位。这仍然不太可能。在整个 IV 是随机的方案中,即使是第二个块也可能导致 128 位和 64 位计数器之间存在差异。
-
@CodesInChaos:我同意,但我希望包号是完全唯一的,并且它永远不会包含超过 blocksize * 256 字节。在我看来,有人在 CommonCrypto 实现中被破坏了,或者库的使用方式与预期不同(过早地完成加密而不是更新)。
-
@owlstead 是的,它们是独一无二的,不应该有重复使用相同 IV 的情况,除非随机随机数被偶然重复使用。此外,密钥永远不会重复使用,因此每个新的 nonce 都带有一个新的随机密钥。
标签: cryptography aes commoncrypto ctr-mode