iOS中的AES解密:PKCS5填充和CBC

Pau*_*man 9 aes padding ios

我正在为iOS实现一些解密代码,用于源自我无法控制的服务器上的消息.另一个平台上的先前实现记录了解密要求AES256,指定了密钥和初始化向量,并且还说:

 * Cipher Mode: CBC
 * Padding: PKCS5Padding
Run Code Online (Sandbox Code Playgroud)

创建CCCryptor对象的选项仅包括kCCOptionPKCS7Padding和kCCOptionECBMode,注意CBC是默认值.根据我对填充加密的理解,我不明白如何使用这两者; 我以为它们是相互排斥的.在创建用于解密的CCCryptor时,我尝试使用0作为选项和kCCOptionPKCS7Padding,但是在解密之后都给了我乱码.

我已经将这个解密的转储与另一个平台上解码的字节缓冲区的转储进行了比较,并确认它们确实是不同的.所以我在这个实现中做的事情有很大不同,我只是不知道是什么......并且没有关于如何处理它的线索.平台不同,很难从之前的实现中推断出很多,因为它基于一个非常不同的平台.当然,之前实施的作者已经离开了.

任何猜测其他可能不兼容或如何解决这个问题?

Maa*_*wes 6

PKCS#5填充和PKCS#7填充实际上是相同的(在算法的块大小的长度上添加字节01,或0202或0303等,在这种情况下为16字节).正式的PKCS#5填充应仅用于8字节块,但在许多运行时,两者可以互换而没有问题.填充总是出现在密文的末尾,所以如果你只是乱码,那就不是填充.ECB是一种块操作模式(不应该用于加密可以与随机数区分开的数据):它需要填充,因此两者不是互斥的.

最后,如果你只是执行解密(不是MAC或其他形式的完整性控制),并且你将unpadding的结果返回给服务器(解密失败),那么由于填充oracle攻击,你的纯文本数据是不安全的.


ind*_*div 5

首先,您可以稍后担心填充。0像您一样提供意味着 AES CBC 没有填充,并且使用该配置您应该可以很好地看到您的消息。Albiet 最后可能带有一些填充字节。所以剩下的:

  1. 您没有正确加载密钥。
  2. 您没有正确加载 IV。
  3. 您没有正确加载数据。
  4. 服务器正在做一些你意想不到的事情。

要对此进行调试,您需要隔离您的系统。您可以通过实施环回测试来实现此目的,在该测试中您加密然后解密数据以确保正确加载所有内容。但这可能会产生误导。即使您做错了什么(例如,向后加载密钥),您仍然可以解密您加密的内容,因为您在双方都以完全相同的错误方式进行了解密。

因此,您需要针对Known Answer Tests(KAT)进行测试。您可以在AES 维基百科条目上查找官方 KAT 。但碰巧的是,我在这里发布了另一个我们可以使用的答案

鉴于此输入:

KEY: 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
IV:  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
PLAIN TEXT:   encrypt me
CIPHER TEXT:  338d2a9e28208cad84c457eb9bd91c81
Run Code Online (Sandbox Code Playgroud)

用第三方程序验证可以解密密文,得到明文。

$ echo -n "encrypt me" > to_encrypt
$ openssl enc -in to_encrypt -out encrypted -e -aes-256-cbc \
> -K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
> -iv 0000000000000000
$ hexdump -C encrypted
00000000  33 8d 2a 9e 28 20 8c ad  84 c4 57 eb 9b d9 1c 81  |3.*.( ....W.....|
00000010
$ openssl enc -in encrypted -out plain_text -d -aes-256-cbc \
> -K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
> -iv 0000000000000000
$ hexdump -C plain_text 
00000000  65 6e 63 72 79 70 74 20  6d 65                    |encrypt me|
0000000a
Run Code Online (Sandbox Code Playgroud)

所以现在尝试在你的程序中解密这个已知答案测试。请务必启用 PKCS7 填充,因为这是我在本示例中使用的。作为练习,在没有填充的情况下解密它并查看结果是相同的,除了在“加密我”文本之后填充字节。

实施 KAT 是一大步。它说您的实现是正确的,但是您对服务器行为的假设是错误的。然后是时候开始质疑这些假设了......

(和 PS,你提到的那些选项并不相互排斥。ECB 意味着没有 IV,而 CBC 意味着你有一个 IV。与填充无关。)

好吧,我知道我说的是练习,但我想证明,即使你用填充加密和不填充解密,你也不会得到垃圾。因此,鉴于使用 PKCS7 填充的 KAT,我们使用无填充选项对其进行解密,并获得一条可读消息,然后06用作填充字节。

$ openssl enc -in encrypted -out plain_text -d -aes-256-cbc \
-K 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f \
-iv 0000000000000000 -nopad
$ hexdump -C plain_text
00000000  65 6e 63 72 79 70 74 20  6d 65 06 06 06 06 06 06  |encrypt me......|
00000010
$ 
Run Code Online (Sandbox Code Playgroud)