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

iOS中的AES解密:PKCS5填充和CBC,ios,aes,padding,Ios,Aes,Padding,我正在为iOS实现一些源于我无法控制的服务器上的消息的解密代码。以前在另一个平台上的实现记录了解密要求AES256,指定了密钥和初始化向量,还表示: * Cipher Mode: CBC * Padding: PKCS5Padding 创建CCCryptor对象的选项仅包括kCCOptionPKCS7Padding和kCCOptionECBMode,注意CBC是默认值。从我对加密填充的理解来看,我不明白如何同时使用两者;我认为它们是相互排斥的。在创建用于解密的CCCryptor时,我尝试使

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

 * Cipher Mode: CBC
 * Padding: PKCS5Padding
创建CCCryptor对象的选项仅包括kCCOptionPKCS7Padding和kCCOptionECBMode,注意CBC是默认值。从我对加密填充的理解来看,我不明白如何同时使用两者;我认为它们是相互排斥的。在创建用于解密的CCCryptor时,我尝试使用0作为选项和KCCOPionPKCS7Padding,但这两种方法在解密后都会让我胡言乱语

我将这个解密转储与另一个平台上的解码字节缓冲区转储进行了比较,并确认它们确实不同。所以我在这个实现中做了一些不同的事情,这是非常不同的,我只是不知道。。。也不知道该怎么处理。这些平台差异很大,很难从以前的实现中推断出什么,因为它基于一个非常不同的平台。当然,上一个实现的作者已经离开了


猜猜还有什么是不兼容的,或者如何解决这个问题?

首先,您可以在以后担心填充问题。像您所做的那样提供
0
意味着AES CBC没有填充,使用该配置,您应该可以看到您的消息。Albiet的结尾可能有一些填充字节。因此,剩下:

  • 您没有正确加载密钥
  • 你的静脉注射没有正确
  • 您没有正确加载数据
  • 服务器正在做一些您意想不到的事情
  • 要调试它,您需要隔离您的系统。您可以通过实现一个环回测试来做到这一点,在该测试中,您对数据进行加密,然后解密,以确保正确加载所有内容。但这可能会产生误导。即使您做了一些错误的事情(例如,向后加载密钥),您仍然可以解密您加密的内容,因为您在两侧都以完全相同的错误方式进行解密

    因此,您需要针对已知答案测试进行测试。你可以在网上查到官方的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
    
    请使用第三方程序验证您是否可以解密密码文本并获取纯文本

    $ 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
    
    现在,请尝试在您的程序中解密这个已知答案测试。请确保启用PKCS7填充,因为这就是我在本例中使用的。作为练习,在没有填充的情况下解密它,并查看结果是否相同,只是在“encrypt me”文本之后有填充字节

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

    (顺便说一句,你提到的这些选项并不是相互排斥的。ECB意味着没有IV,CBC意味着你有IV。与填充无关。)

    好吧,我知道我说过这是一个练习,但我想证明,即使你用填充加密 并且在没有填充的情况下解密,就不会得到垃圾。因此,考虑到使用PKCS7填充的KAT,我们使用no padding选项对其进行解密,并得到一条可读的消息,后跟用作填充字节的
    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
    $ 
    

    事实证明,对我所经历的事情的解释非常简单:我错误地解释了我在以前的实现中读到的东西,暗示它使用的是256位密钥,但实际上它使用的是128位密钥。做出这样的改变,原本模糊的东西突然变成了清晰的文本。:-)

    options参数0调用CBC实际上是正确的。在以前的实现中,对PKCS5填充的引用仍然是个谜,但这并不重要,因为我现在得到的东西可以工作了

    感谢您的快照,indiv.

    (将字节01、0202或0303等添加到算法的块大小长度,在本例中为16字节)。官方的PKCS#5填充只能用于8字节块,但在许多运行时,这两种填充可以互换而不会出现问题。填充总是发生在密文的末尾,所以如果你只是胡言乱语,那不是填充。ECB是一种块操作模式(不应用于加密可与随机数区分的数据):它需要填充,因此两者并不相互排斥

    最后,如果您只是执行解密(而不是MAC'ing或其他形式的完整性控制),并将取消添加的结果返回到服务器(解密失败),则由于填充oracle攻击,您的纯文本数据不安全。

    Paul,
    需要PKCS#5填充来识别解密数据中的填充。对于CBC,输入缓冲区必须是密码块大小的倍数(AES为16)。因此,将要加密的缓冲区扩展为附加字节。请注意,加密后,数据的原始大小将丢失。PKCS#5填充允许检索该大小。这是通过用重复字节填充扩展数据缓冲区来完成的,其值等于填充大小。e、 g如果您的明文缓冲区是12个字节,要使其成为16的倍数,您需要再添加4个字节。(如果数据是16,您将再添加16,使其成为32)。然后用“0x4”填充这4个字节,以符合PKCS#5填充。解密时,只需查找解密数据中的最后一个字节,然后从解密缓冲区的长度中减去该数字。 您正在使用“0”填充。虽然您似乎很高兴看到结果,但当您的原始数据以一个或多个“0”结尾时,您会大吃一惊。

    PKCS#5填充不是唯一的选择