【问题标题】:C - Encrypt and decrypt a string with AESC - 使用 AES 加密和解密字符串
【发布时间】:2018-05-09 13:32:21
【问题描述】:

我正在尝试了解如何使用 this c library (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 获得类似的(与 JS 相同的)结果API,加上当我尝试使用更长的消息时,我得到了奇怪的结果,让我认为我使用这个库的方式有误。

:C代码相当于上面的JS是什么?

【问题讨论】:

  • 您想使用 AES 加密字符串?这就是整个问题吗? (很抱歉无法理解)
  • 不,问题是特定于库的。谢谢。
  • 我明白了,哦,我不知道那个图书馆
  • 如果您正在寻找良好的安全性,请使用经过严格审查的实现,例如由语言或平台提供商提供的。虽然结果相同,但可能存在时间缺陷或其他边信道漏洞。此外,缺乏对 ECB 和 CBC 模式的填充支持是有问题的,并且空填充不是一个好的解决方案。许多解决方案使用速度快几个数量级的处理器 AES 指令。
  • 谢谢@zaph,重点是我在 WebAssembly 模型中使用此代码,使用 3rd 方库令人头疼。我正在尝试仅提取必要的代码。

标签: javascript c api encryption aes


【解决方案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。

【讨论】:

  • 谢谢,按预期工作。 @Morten Jensen 这是一种公认​​的用法吗?
  • 当使用 CTR 模式时,必须注意不要多次使用相同的计数器初始值和组合键。事实证明,这是一个常见的缺陷,即使是主要参与者也失败了。
  • @RoniGadot 看起来确实像 :) 请注意 zaph 的建议:切勿在 CTR 模式下重复使用 IV + 反组合。
【解决方案2】:

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

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

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

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

没有提供填充,因此对于 CBC 和 ECB,所有缓冲区都应该是 16 字节的倍数。对于填充 PKCS7 是推荐的。

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

编辑:

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

【讨论】:

  • 非常感谢您的回复,如果您能提供一个简短的代码示例,那就太好了(请?)。
  • @RoniGadot The test code 演示了用法。这周我没有太多空闲时间,所以这几天我将无法提供帮助。
  • 再次感谢,对不起,我是个新手,但我可以用字符串替换 { 0x87, 0x4d, 0x61, 0x91... 吗?
  • @RoniGadot 不用担心 :) 是的,您可以,但数据仍将被视为二进制数组,因此请确保长度都是 16 字节的倍数并相应地填充(例如用零) .也许用字符替换每个十六进制值更容易,所以输入变成这样:{ 'm','y',' ','m','e','s','s','a','g','e',0,0,0,0,0,0}
  • CryptoJS 代码使用 PBKDF(基于密码的密钥派生函数)来创建密钥和 IV。所以你仍然不会得到相同的结果。
【解决方案3】:
uint8_t in[16]  = "my message";

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多