我在解密字符串时遇到了一些麻烦。令人气愤的是它只是前几个字节搞砸了,剩下的字符是正确的。
因此,当我使用硬编码IV进行加密和解密时,我的测试程序运行正常。该程序接受一个字符串,加密它(使用AES),然后我得到加密二进制的十六进制表示。当我试图将IV附加到密文的末尾时出现问题。特别是,在附加IV之后,十六进制字符串的长度没有增加。但是,解密函数似乎是从密文结尾处获取IV,否则它将无法解密任何一个,对吧?
我尝试了很多不同的东西,比如创建一个需要的确切大小的缓冲区,并使用memcpy
添加密文和IV。这是代码:
AES加密
int encryptAes(const char *plainText, char *cipherText, const char *key) {
unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
int plainTextLength = strlen(plainText);
int cipherTextLength = 0;
int blockLength = 0;
static const int MAX_PADDING_LENGTH = 16;
EVP_CIPHER_CTX encryptCtx;
EVP_CIPHER_CTX_init(&encryptCtx);
EVP_EncryptInit_ex(&encryptCtx, EVP_aes_256_cbc(), NULL, key, iv);
if (!EVP_EncryptUpdate(&encryptCtx, cipherText, &blockLength, (unsigned char *) plainText, plainTextLength) ) {
printf("Error in EVP_EncryptUpdate \n");
return 1;
}
cipherTextLength += blockLength;
if (!EVP_EncryptFinal_ex(&encryptCtx, cipherText + cipherTextLength, &blockLength)) {
printf("Error in EVP_EncryptFinal_ex \n");
return 1;
}
cipherTextLength += blockLength;
// Append the IV
memcpy(cipherText + cipherTextLength, iv, 16);
EVP_CIPHER_CTX_cleanup(&encryptCtx);
return cipherTextLength;
}
AES解密
int decryptAes(const char *cipherText, char *decipheredPlainText, const size_t cipherTextLength, const char *key) {
// unsigned char iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
unsigned char iv[16];
memcpy(iv, cipherText + cipherTextLength, 16);
int plainTextLength = 0;
int blockLength = 0;
EVP_CIPHER_CTX decryptCtx;
EVP_CIPHER_CTX_init(&decryptCtx);
EVP_DecryptInit_ex(&decryptCtx, EVP_aes_256_cbc(), NULL, key, iv);
if (!EVP_DecryptUpdate(&decryptCtx, decipheredPlainText, &blockLength, cipherText, cipherTextLength)) {
printf("Error in EVP_DecryptUpdate\n");
return 1;
}
plainTextLength += blockLength;
if (!EVP_DecryptFinal_ex(&decryptCtx, decipheredPlainText + plainTextLength, &blockLength)) {
printf("Error in EVP_DecryptFinal_ex\n");
return 1;
}
plainTextLength += blockLength;
decipheredPlainText[plainTextLength] = '\0';
EVP_CIPHER_CTX_cleanup(&decryptCtx);
return plainTextLength;
}
这会产生输出:
Original Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text [�}kaw&d��~C�Rmfpher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
如果我从加密函数中删除行memcpy(cipherText + cipherTextLength, iv, 16);
,并在解密函数开始时取消注释硬编码IV(并注释以下两行),则输出正确:
Original Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
Hexadecimal is [be1c1aaa5827be124023a96a3360da922c244acd845e8914d03cfac69d312948e10f8ef7a99a64acbc6996724315f6cb0bf441ba3b08ab25cae64389f6ded77b1579e847d3e18ca89e71a3c4ec5ca4e3089b7bc2e6bc9ef8d175406bf4b53005a91e285d117e5990176d85793bd75853]
Decrypted Plain Text [cipher cipher cipher cipher CIPHER TEXT! 187? 1$5 78@2 14 .TӒ��틪�ձ1z.$�?�U���<y]
注意!,两种情况下的十六进制相同。
任何人都可以在这里看到我出错的地方。我之前遇到过类似的东西,但似乎无法记住我是如何绕过它的。显然,在尝试附加IV时会有一些事情发生。 cipherText
中有足够的空间来容纳IV的添加。
提前致谢。
答案 0 :(得分:2)
使用相同的密钥但不正确的IV解密文本实际上会破坏明文输出的第一个块并正确解密其余的块。所以我会说你的IV是不正确的,即使在前几个字节之后明文是正确的。
答案 1 :(得分:1)
encryptAes()
应该表示的返回值是多少?在我看来,它应该代表加密过程产生的数据的字节长度。您是否在考虑需要处理的数据比这长16个字节的事实?如果您在一个地方加密数据,并将其复制到另一个地方以致电decryptAes()
,则您可能忘记考虑额外的十六个字节。
如果是这种情况,那么你有效的做法是:
encryptAes()
,将文本传递给加密,输出缓冲区和加密密钥。encryptAes()
中,您生成IV,执行加密,将加密数据写入输出缓冲区,计算长度。cipherTextLength
计数器。encryptAes()
返回,将cipherTextLength
返回给来电者。请注意,这是比实际数据短16个字节的值。decryptAes()
,将文本传递给解密,输出缓冲区,加密数据的大小和密钥。decryptAes()
中,将紧随加密数据的16个随机字节数据复制到IV中。这是我能想到的最有可能的解释,为什么你的IV会被破坏。