C - 使用 AES 加密和解密字符串

问题描述 投票:0回答:4

我试图了解如何使用这个c库tiny-AES-c)。作为一名 Web 开发人员,我正在寻找 this JS fiddle 的等效 C 代码。

JS代码很简单:

// Encrypt
var ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123');


console.log("Encrypted: " + ciphertext.toString());

// Decrypt
var bytes  = CryptoJS.AES.decrypt(ciphertext.toString(), 'secret key 123');
var plaintext = bytes.toString(CryptoJS.enc.Utf8);

console.log("Decrypted: " + plaintext);

给定要加密的消息和秘密,代码会生成加密数据并将结果转换为字符串。


我的C代码:

int main()
{
    uint8_t in[]  = "my message";
    uint8_t key[] =  "secret key 123";

    struct AES_ctx ctx;

    AES_init_ctx(&ctx, key);
    printf("ORIG: %s",(char*) in);

    // Encrypt
    AES_ECB_encrypt(&ctx, in);
    printf("\nENC: %s",(char*) in);

    // Decrypt
    AES_ECB_decrypt(&ctx, in);
    printf("\nDEC: %s",(char*) in);

    return 0;
}

输出:

ORIG: my message
ENC: ̤�+��5<n]EYK�ظ/����
DEC: my message%  

我知道我不应该尝试将结果打印为字符串,但无法弄清楚如何使用 tiny-AES-c API 以及当我尝试使用时获得类似的(与 JS)结果更长的消息我得到了奇怪的结果,让我认为我使用这个库的方式是错误的。

:与上述 JS 等价的 C 代码是什么?

javascript c api encryption aes
4个回答
1
投票

我是您引用的 AES 库的原作者。

当使用ECB和CBC操作模式时,您需要确保您的密钥、iv和输入/输出块都是16字节长。您还需要决定要使用哪种填充方案。

您可以使用 CTR 模式来避免填充并不再担心块大小。这通常使得 AES 算法更容易使用,因为需要处理的边缘情况更少。

顺便说一句,这在项目自述文件中也有说明:

未提供填充,因此对于 CBC 和 ECB,所有缓冲区都应为 16 字节的倍数。对于填充,建议使用 PKCS7。

ECB 模式对于大多数用途来说被认为是不安全的,并且不在流模式下实现。如果您需要此模式,请为需要加密的每个 16 字节块调用该函数。有关更多详细信息,请参阅维基百科有关欧洲央行的文章。

编辑:

如果您扩展数组,使其长度为 16 个字节并用零填充它们(或者将它们声明为静态,以便它们自动零初始化),我认为它应该适合您:)


1
投票

正如 @Morten Jensen 建议的那样,您可以使用 CTR 模式 IE:

AES_CTR_xcrypt_buffer

int main()
{
    uint8_t key[] = "secret key 123";
    uint8_t in[]  = "my message";
    uint8_t iv[16] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };

    printf("Length: %lu",strlen((char*)in));

    struct AES_ctx ctx;
    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, strlen((char*)in));
    printf("\nENC: %s",(char*) in); // don't use this string as an input

    AES_init_ctx_iv(&ctx, key, iv);
    AES_CTR_xcrypt_buffer(&ctx, in, strlen((char*)in));
    printf("\nDEC: %s",(char*) in);
    return 0;
}

记住,打印加密数据是错误的,如果你想匹配你的JS示例,你应该检查输出并将其转换为base64。


0
投票
uint8_t in[16]  = "my message";

您的缓冲区需要是 16 的倍数。


0
投票

非常感谢您在帖子中的回答,这已经非常有帮助了!我是一名仍在学习 C 的网络安全学生,所以我为发布一个可能愚蠢的问题的答案而道歉:

我正在开发一个 micro:bit 项目,并尝试使用tinyAES ECB 模式通过无线电将加密消息发送到另一个 micro:bit。我确信我的缓冲区和密钥的大小正确,并且其余的实现都是正确的。但是,接收 microbit 不会解密收到的密文(加密和解密函数分别在单独的设备中调用,所有相关库和所需的代码都已就位)。我一直错误地打印密文来检查/排除故障,并且输出看起来与原始问题中的类似。

根据上面的讨论,我说的对吗?我们需要以 Base64 发送密文,这可能是一个可靠的潜在解决方案?

© www.soinside.com 2019 - 2024. All rights reserved.