写点什么

AES128 解密只能解一半的问题

用户头像
李日盛
关注
发布于: 2021 年 01 月 20 日

0x01 问题复现

最近基于 opessl 的 C 语言库做 AES 加解密的实现。在测试的过程中,发现概率性(一半概率)的会出现用加密生成的字符串,解密后的内容只剩一半的问题,具体的测试用的字符串如下:

加密用的key: IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p加密用的IV: c9c47d64e1b036f540a38255ba88af48加密用的字符串:IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p
复制代码


正常调用 AES128 加密,结果用 Base64 转换成字符串输出,得到的加密后的字符串为:ER04NG0hqYv+qyySaxLbNaVMZxBLBnxMIwfNAF/rBV9uDChhlx3CKW758nzNHmBB 具体的加密转换过程输出为:

plain len:32,value:.......................................49 57 41 63 72 50 46 68 6D 72 42 44 31 39 54 72 53 66 62 37 4C 33 4F 63 30 54 52 55 4F 56 36 70 

aes len:48,value:.......................................11 1D 38 34 6D 21 A9 8B FE AB 2C 92 6B 12 DB 35 A5 4C 67 10 4B 06 7C 4C 23 07 CD 00 5F EB 05 5F 6E 0C 28 61 97 1D C2 29 6E F9 F2 7C CD 1E 60 41

base len:64,value:.......................................45 52 30 34 4E 47 30 68 71 59 76 2B 71 79 79 53 61 78 4C 62 4E 61 56 4D 5A 78 42 4C 42 6E 78 4D 49 77 66 4E 41 46 2F 72 42 56 39 75 44 43 68 68 6C 78 33 43 4B 57 37 35 38 6E 7A 4E 48 6D 42 42
复制代码


可以看到,数据从一个 32 位的数组,AES 加密后变成 48 位,最终基于 base64 转换为一个 64 位的数组。

然后神奇的事情发生了,我们用上面得到的加密后的字符串,进行解密,可以得到下面的结果:

src len:64,value:.......................................45 52 30 34 4E 47 30 68 71 59 76 2B 71 79 79 53 61 78 4C 62 4E 61 56 4D 5A 78 42 4C 42 6E 78 4D 49 77 66 4E 41 46 2F 72 42 56 39 75 44 43 68 68 6C 78 33 43 4B 57 37 35 38 6E 7A 4E 48 6D 42 42 

aes len:27,value:.......................................11 1D 38 34 6D 21 A9 8B FE AB 2C 92 6B 12 DB 35 A5 4C 67 10 4B 06 7C 4C 23 07 CD
plain len:16,value:.......................................49 57 41 63 72 50 46 68 6D 72 42 44 31 39 54 72
复制代码

从中间的转换过程来看,base64 的输入是正常的,还是 64 位,但是到了 ase 解密完了以后,就不对了,变成了只剩下了 27 位的数组了,最终输出结果变成了 16 位数组,对比原始数据,数据减少了一半。


这种情况也不是每次都能出现,比如将刚才输入的内容: IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p 的最后一位,改成 s,也就是 IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6s 计算结果又是正常了。

0x02 问题分析

本人对于 AES 算法本身不是非常了解,不过所有的对称加密算法,本质上面就是一组数矩阵基于某种运算规则进行各种变换。结合问题的现象来看,最终输出的结果其实是解密成功了,只是少了一半数据。我估计可能的原因是在转换的过程中,出现了类似溢出的问题,导致最终结果缺失数据。这可能是 openssl 本身的代码实现可能有问题导致的。为了验证是不是我本身代码的问题,我用编译好的 openssl 程序进行加解密测试了一波:


加密:

echo "IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p" > name.txt
openssl enc -aes-128-cbc -in name.txt -a -out enc_name.txt -K IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p -iv c9c47d64e1b036f540a38255ba88af48
复制代码


输出的结果保存到 enc_name.txt 文件中,内容如下:

ER04NG0hqYv+qyySaxLbNaVMZxBLBnxMIwfNAF/rBV96qBLPB4x4fTViwzW47KpF
复制代码


解密:

openssl enc -d -aes-128-cbc -in enc_name.txt -a -out dec_name.txt -K IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p -iv c9c47d64e1b036f540a38255ba88af48cat dec_name.txt
复制代码


输出结果如下:

IWAcrPFhmrBD19TrSfb7L3Oc0TRUOV6p
复制代码


可以看到,基于 openssl 程序生成是可以正常解密回来的,说明应该不是算法和参数本身的问题,问题应该是我自己的代码实现这里。

回到上面的现象,其实问题是比较清楚了,就是 base64 解密的时候,数组的长度变了,少了部分内容应该是 48 位)。看 base64 解密的实现:

int openssl_base64_decrypt(    const char *ciphertext, unsigned int ciphertext_len, unsigned char *plaintext){    BIO *b64 = NULL;    BIO *bmem = NULL;
b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(ciphertext, ciphertext_len); bmem = BIO_push(b64, bmem);
BIO_read(bmem, plaintext, ciphertext_len); BIO_free_all(bmem);
return strlen(plaintext);}
复制代码


问题出现在最后一行。如果转换后的结果数组里面,中间有零的话,其实获取到的不是最终的结果长度。为了验证假设,我这边打印了下完整数组的内容:

aes len:27,value:.......................................11 1D 38 34 6D 21 A9 8B FE AB 2C 92 6B 12 DB 35 A5 4C 67 10 4B 06 7C 4C 23 07 CD 00 5F EB 05 5F 6E 0C 28 61 97 1D C2 29 6E F9 F2 7C CD 1E 60 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
复制代码

Bingo! 果然是有零。位置为第 28 位,所以得出数组的长度是 27 这个结论,最终导致后面的 AES 解密缺失数据。至此,问题定位完成。

0x03 问题解决

修改 base64 解密代码,获取准确的数组长度,代码如下:


int openssl_base64_decrypt(    const char *ciphertext, unsigned int ciphertext_len, unsigned char *plaintext){    BIO *b64 = NULL;    BIO *bmem = NULL;    BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf(ciphertext, ciphertext_len); bmem = BIO_push(b64, bmem);
int len = BIO_read(bmem, plaintext, ciphertext_len); BIO_free_all(bmem);
return len;}
复制代码


再测试,可以正常解密。至此,问题完全解决。

发布于: 2021 年 01 月 20 日阅读数: 23
用户头像

李日盛

关注

好架构=低成本+可实现 2018.01.22 加入

还未添加个人简介

评论

发布
暂无评论
AES128解密只能解一半的问题