使用PolarSSL AES-CBC加密字符串后,我无法解密该字符串。

3
我编写了一个程序,使用PolarSSL AES-CBC算法对字符串进行加密。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <polarssl/aes.h>
#include <polarssl/havege.h>

int main()
{
    char buff[2][64] = {"Who can tell me WHY?", ""};
    havege_state hs;
    int retval;
    unsigned char IV[16];

    aes_context enc_ctx;
    aes_context dec_ctx;

    aes_setkey_enc(&enc_ctx, "password", 256);
    aes_setkey_dec(&dec_ctx, "password", 256);

    havege_init(&hs);
    havege_random(&hs, IV, 16);

    //encrypt
    aes_crypt_cbc(&enc_ctx, AES_ENCRYPT, 64, IV, buff[0], buff[1]);
    havege_random(&hs, IV, 16);

    //decrypt
    aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV, buff[1],buff[0]);

    printf("After decrypt:%s\n", buff[0]);
    return 0;
}

但是当我运行它时,在解密后我得到了错误的文本。

我并不完全理解AES算法,因为我的英语很差,所以对于一些文章我很难阅读明白。

-------------------------midCat添加--------------------------------------------

我遵循了你的建议,改变了我的代码, 现在我使用相同的IV和256位密钥,这是新代码。

int main()
{
    char buff[2][64] = {"ABCDEFGHIJKLMN", ""};
    havege_state hs;
    int retval;
    unsigned char IV[16];
    unsigned char IV2[16];
    unsigned char key[32];

    aes_context enc_ctx;
    aes_context dec_ctx;

    havege_init(&hs);
    havege_random(&hs, IV, 16);
    havege_random(&hs, key, 32);
    strncpy(IV, IV2, 16);           //copy IV

    aes_setkey_enc(&enc_ctx, key, 256);
    aes_setkey_dec(&dec_ctx, key, 256);


    //encrypt
    aes_crypt_cbc(&enc_ctx, AES_ENCRYPT, 64, IV, buff[0], buff[1]);
    printf("Before encrypt:%s\n", buff[0]);

    //decrypt
    aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV2, buff[1],buff[0]);
    printf("After decrypt:%s\n", buff[0]);
    return 0;
}

我把它编译了,并运行了很多次,都得到了相同的输出:
Before encrypt:ABCDEFGHIJKLMN
After decrypt:ABCDEFGHYC
                        LMN

如何获取IV


AES工作在字节级别而不是字符级别。这有微妙的差别。你不能使用strncpy()来复制IV。你必须使用memcpy(),因为IV可能包含空字符。对于其余部分,这段代码是可以的(并且在我的机器上运行良好)。 - Paul
你还交换了源操作数和目标操作数,你想使用memcpy(IV2, IV, sizeof(IV))。 - dnaq
3个回答

4
编辑:正如丹尼尔在他的回答中指出的那样,你试图使用随机IV进行解密是一个大问题(这将不会给你期望的结果)。然而,我建议您也阅读本答案的其余部分。
首先,aes_set_key_encaes_set_key_dec不接受密码作为输入,它们接受密钥。密钥应该是完全随机的值,长度与密钥长度相同(在您的情况下是32字节的随机字符串,因为您想使用256位密钥)。
在您的情况下,您正在使用短密码调用aes_set_key_enc/aes_set_key_dec,但告诉它应该期望一个256位密钥,这将导致这些函数使用超出您的密码的内存作为密钥的一部分,并且会导致加密和解密密钥不同。
总之,AES(或任何密码算法)期望随机密钥,这些算法本身没有扩展密码到密钥的概念。
如果您想使用密码作为密钥,则需要某个函数将非随机密码扩展为伪随机密钥。唯一合理的方法是使用旨在具有密码学安全性但速度较慢的函数,以减轻对密码的暴力攻击的风险。
可以使用的好函数是Colin Percivals的scryptbcryptPBKDF2,其中我最推荐使用scrypt。
但是,我想强调的是,您可能根本不应该在这个抽象级别上工作。您正在使用的基元(块密码,CBC模式)处于非常低的抽象级别上,使用这些基元构建加密系统可能非常危险。例如,您没有对密文使用任何形式的身份验证,这可能会使您的实现面临所选密文攻击的风险。
我认为,如果您想在应用程序中使用密码学,最好的方法是尝试在更高的抽象级别上工作,例如使用丹·伯恩斯坦的NaCl或Google的KeyCzar
总之,您的特定问题可以通过使用256位密钥来解决,但是您应该三思而后行,是否要在此抽象级别上实现自己的加密系统。

这是非常好的建议,我完全同意。然而,根据编译器的不同,它很可能并不是问题的真正源头。 - Daniel Roethlisberger
你说得对,我漏看了他使用了随机IV来解密。 - dnaq
PolarSSL 包含一个 PBKDF2 模块。因此,与此代码结合使用,很可能是最好的选择。(除了 IV 问题很可能是问题的原因之外) - Paul
我遵循了你的建议,使用256位密钥,加密和解密时使用相同的IV。但我仍然得到了错误的文本。在加密之前,文本是“ABCDEFGHIJKLMN”,解密后,文本变成了“ABCDEFGHYCLMN”。 - midCat
1
你需要使用memcpy来复制iv,因为strncpy会在输入中找到空字节后立即停止。 - dnaq

4

您正在使用随机初始化向量(IV)进行解密。这是错误的。解密需要使用与加密相同的IV。只需删除第二次调用即可。

havege_random(&hs, IV, 16);

在加密和解密之间确保使用 32 字符数组作为 aes_setkey_encaes_setkey_dec 的第二个参数,因为当前代码正在读取字符串的末尾。根据编译器的不同,这可能导致加密和解密使用不同的密钥(从而失败)。

(编辑第二部分问题)

将此更改为:

strncpy(IV, IV2, 16);           //copy IV

转换为:

memcpy(IV2, IV, 16);           //copy IV

那应该使用memcpy而不是strncpy,因为IV是随机数据,可能包含字符串终止符'\0',而这两个函数的第一个参数都是目标地址,而不是源地址。你把一个字符串从IV2复制到了IV,而不是从IV复制到IV2的内存中。
至于如何获取解密用的IV:通常,IV只需与密文一起发送。每个IV只能使用一次,不能可预测,但无需保密。一个常见的构造方法是为每个消息选择一个随机的IV,并将其简单地放在密文前面或存储在文件头中,具体取决于情况。
话虽如此,我同意不要使用加密原语构建自己的加密协议,除非你知道自己在做什么。

我按照你的建议去做了,但是还是出现了错误的文本。我刚刚粘贴了我的新代码。 - midCat
1
你的strncpy参数顺序错误了,而且你需要使用memcpy。 - Daniel Roethlisberger

-1
我刚刚将64更改为14。
aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV2, buff[1],buff[0]);

一切正常运行!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接