【问题标题】:How do I use AES_CBC_Encrypt 128 openssl properly in Ubuntu?如何在 Ubuntu 中正确使用 AES_CBC_Encrypt 128 openssl?
【发布时间】:2015-02-17 22:49:55
【问题描述】:

仍然发现很难在 C 中使用内存。我正在读取一个文本文件,其中我将包含名称和 40 个字符的随机字符串的每一行文本存储到 2 个缓冲区中,char buffer1[128] 和char buffer2[128] 使用人们似乎不喜欢的 fscanf() ,后来我需要只取字符串(在缓冲区的其余部分没有任何填充或空白)并使用 AES-CBC-128 加密它然后稍后在解密它。我在名称上使用 md5 来生成一个 16 字节的密钥,我在加密过程中使用它,并再次生成一个 16 字节的随机初始化向量。现在,加密/解密几乎可以正常工作,如果我自己在 AES 加密函数中键入 40 个字符的字符串(即字符串稍后被正确解密,但事先出现了一些额外的乱码),但如果我传递包含字符串进入函数,解密出来的都是乱码(换句话说,它不起作用)。如果我尝试使缓冲区足够小以准确包含字符串(字符缓冲区 [40]),则加密/解密不起作用。如果我尝试将其作为 C 中字符串中的终止符的 char buffer[41],则会出现 Core Dump 错误。 我仍然是一个 C 菜鸟,无法弄清楚我做错了什么! 注:如果我使用 48 字节作为加密长度(AES BLOCK SIZE 的倍数,即 16 字节),则它不起作用。当我使用 40 字节作为加密长度(与要加密的数据相同)时,它几乎就像我上面所说的那样工作。请解释我如何可以一次且永久地正确使用 AES_CBC_Encrypt!我正在使用openssl,测试代码是:

void alice() {
    FILE *fp=fopen("alice.txt","r"); //read mode
    int j;
    char buffer1[128], buffer2[128]; //buffer1->names, buffer2->data
    unsigned char h_j[SHA_DIGEST_LENGTH];
    unsigned char k_j[MD5_DIGEST_LENGTH];

    //loops over the 25 lines in alice.txt file
    for (j=0; j<n_alice; j++) {
        //read a_j data_j into addresses of buffer1 and buffer2
        fscanf(fp,"%s %s\n",(char*)&buffer1, (char*)&buffer2); //buffer1=names, buffer2=data
        if (dbg) printf("Reading %s %40s\n", buffer1, buffer2);

        //Calculate h_j=SHA1(a_j)
        SHA1((unsigned char*)&buffer1, strlen(buffer1),(unsigned char*)h_j);

        //Calculate k_j=MD5(a_j)
        MD5((unsigned char*)&buffer1, strlen(buffer1), (unsigned char*)k_j);

        //Encrypt c_j=AES-CBC-ENC(k_j,data_j)
        //using MD5 digest as the key for the AES CBC
        //initialization vector
        unsigned char init_vector[AES_BLOCK_SIZE];
        RAND_bytes(init_vector, AES_BLOCK_SIZE); //16 bytes

        const size_t encslength = 48;//((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
        unsigned char enc_out[encslength];
        unsigned char dec_out[40];
        memset(enc_out, 0, sizeof(enc_out));
        memset(dec_out, 0, sizeof(dec_out));

        AES_KEY enc_key, dec_key;
        AES_set_encrypt_key(k_j, sizeof(k_j), &enc_key);
        AES_cbc_encrypt(buffer2, enc_out, strlen(buffer2), &enc_key, init_vector, AES_ENCRYPT);

        AES_set_decrypt_key(k_j, sizeof(k_j), &dec_key);
        AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, init_vector, AES_DECRYPT);

        printf("original:\t %s\n", buffer2);
        printf("encrypt:\t %s\n", enc_out);
        printf("decrypt:\t %s\n", dec_out);
    }
    fclose(fp);
}

Alice.txt 包含:

伊夫 E9D0EEFC4C6DD81F2A7BDE99CCE833FB7B2BDD6D 亚当 D6C33F73EC7175AEA67DEC98427B42AAF6E5E04C 大卫 F58EEB1DDB9511A3F220A4B10F01F88260BC99AB F6A6127E6562C5816433FB3B7C341C45A8805DCB 维多利亚 CCF10AA4A4725C964FFF78BA3694393ADE1D7B6C 尼克 C8030118EB5E037F6131D9BB5B1BEF0A3F2AC458 晓峰E9B45ECAE2F42D59B90EACB2CA8E75A969A7EFAB 夏娃 D8DA8BC812D9CD72B91EB7AF49D099A9BE85AB43 鲍勃 CC039D2746A3C55E4BA1DCEE46F329E4CA7E0A1A 佛罗伦萨 C2DFD6650343659BFB530FE719139AB4D3F2BEDC 赫伯特CDCB4196E8CA9002219EC7A8F372911501BD1BBD 常春藤 E53BC8DF9A81BDD881E5352BCE11A2BF0F33236B 千斤顶 C5213B5F8DC334010586FB094A63D50A7572470E 奥斯瓦尔德 D0FBD9B2102DF6C41C8B26F25AF3E18ACF2BD27C 史蒂文 C9A3AB53FAA9E8243A63EBDC3257D1C8CCEC7D1C 凯文 D7C6774E65DBB8F312F50183C87D67BC6FBF7BED 加文 F4C1945162294DD902C6BC11EE23BF8B682AC6C9 卢克 DF2FD780E13F9511411EC92B476D167A6D9F334A 马丁 FE6D5175D3B6E49B6649DBD6F21559F15847CA31 pippo DA908468DBE291E4DDEB082E36E9F5BB316A3C3C 理查德 EC26FF6B364C51DCA5A7CB5D711BCC85946D2517 特洛伊 F1165BE81E08B38A42C582A8F25C2CC382233F3D 扎克 EF19BED4FD6732C92437A3F65C4BE69A5010994D 威廉 EC74AA8C93AA32EFF85EC4437F50F1F86AECAC29 查理 C86D2F8A3EF1F03127628C7CF9C6D9FB730DACBF

我只是从 main 调用 alice() 来测试这个。

【问题讨论】:

  • 除了实际代码之外,您的问题还缺少您使用的加密库的信息。请同时添加。
  • 由于您仍在学习 C,您可能需要先完成学习方面。编写没有所有加密内容的代码,看看您是否可以正确使用字符串。并且您完全了解如何使用数组和指针。然后回到这个加密/解密练习!
  • 注意:' ''\n' 不是必需的。在fscanf(fp,"%s %s\n",.... 也许fscanf(fp,"%127s%127s",.... 除非你需要128 个字符串,在这种情况下char buffer1[128+1], buffer2[128+1]; fscanf(fp,"%128s%128s",....
  • 我设法找出了我的严重错误。该行:AES_set_encrypt_key(k_j, sizeof(k_j), &enc_key);应该是:AES_set_encrypt_key(k_j, sizeof(k_j)*8, &enc_key); AES_CBC_Encrypt() 函数中的 enclength 和 declength 显然应该相同。所以我用 48bytes 加密和解密,否则对我不起作用。我可能是错的,但是当我使用 strlen(buffer2) 进行加密(即 40 字节)时,解密只能正确解密部分字符串,其余部分仍然是乱码。

标签: c string openssl aes encryption-symmetric


【解决方案1】:

我设法找出了我的严重错误。行:

AES_set_encrypt_key(k_j, sizeof(k_j), &enc_key);

应该是:

AES_set_encrypt_key(k_j, sizeof(k_j)*8, &enc_key);

AES_CBC_Encrypt() 函数中的enclengthdeclength 显然应该相同。所以我用 48bytes 加密和解密,否则对我不起作用。我可能是错的,但是当我使用strlen(buffer2) 进行加密(即 40 字节)时,解密只能正确解密部分字符串,其余部分仍然是乱码。 --val37

【讨论】:

    【解决方案2】:

    我自己也为 OpenSSL 的文档记录不佳而苦苦挣扎。函数本身在 Assembler 中实现确实无济于事,因此即使是源代码也无济于事。但我能够识别出你犯的一些错误:

    1. 正如您所说,AES_set_encrypt_keybit-size 作为第二个参数,而不是字节。
    2. 密钥必须的大小正好为 16、24 或 32 字节。
    3. 给定的init_vector必须在加密和解密开始时相同。

    因为 2. 您的整个示例不适用于 sha1。 MD5_DIGEST_LENGTH 恰好有 16 个字节(128 位)。初始化向量也会被加密操作改变,所以你可以一次又一次地向区块链添加额外的数据。但是由于您没有遵循 3. 并且使用更改后的向量进行解密而不先重置它,这就是您的解密返回“乱码”的原因。

    作为一个例子,我拿了你的代码,扔掉了所有不必要的东西,并提取了加密/解密操作以清除重要部分:

    void encrypt(unsigned char* buf, size_t length, const AES_KEY* const enc_key, const unsigned char* iv)
    {
      unsigned char local_vector[AES_BLOCK_SIZE];
      memcpy(local_vector, iv, AES_BLOCK_SIZE);
    
      AES_cbc_encrypt(buf, buf, length, enc_key, local_vector, AES_ENCRYPT);
    }
    

    我正在开发用于阅读和写作的 buf。如您所见,init_vector 被复制到本地以保持原始不变。我做了类似的解密。

    void decrypt(unsigned char* buf, size_t length, const AES_KEY* const dec_key, const unsigned char* iv)
    {
      unsigned char local_vector[AES_BLOCK_SIZE];
      memcpy(local_vector, iv, AES_BLOCK_SIZE);
    
      AES_cbc_encrypt(buf, buf, length, dec_key, local_vector, AES_DECRYPT);
    }
    

    这就是我对您的代码所做的。我没有更改 fscanf,因为我们应该专注于被问到的问题而不是让人们感到困惑:

    void tst_function()
    {
      FILE *fp=fopen("alice.txt","r"); //read mode
      char buffer1[128], buffer2[128]; //buffer1->names, buffer2->data
      memset(buffer1, 0, sizeof(buffer1));
      memset(buffer2, 0, sizeof(buffer2));
      // remember, this won't work with any other size
      unsigned char k_j[AES_BLOCK_SIZE];
    
      //until end of file
      while(fscanf(fp,"%s %s\n",(char*)&buffer1, (char*)&buffer2) > 0)
      {
         printf("Reading %s %40s\n", buffer1, buffer2);
         printf("original:\t%s\n", buffer2);
    
         unsigned char init_vector[AES_BLOCK_SIZE];
         RAND_bytes(init_vector, AES_BLOCK_SIZE);
    
         // PKCS 5 Padding
         // ((inputs_length + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
         const size_t encslength = 48;
         unsigned char enc_out[encslength];
         memset(enc_out, 0, sizeof(enc_out));
         strncpy(enc_out, buffer2, sizeof(enc_out));
    
         AES_KEY enc_key, dec_key;
         AES_set_encrypt_key(k_j, sizeof(k_j)*8, &enc_key);
         AES_set_decrypt_key(k_j, sizeof(k_j)*8, &dec_key);
    
         encrypt(enc_out, encslength, &enc_key, init_vector); //see above
         printf("encrypted:\t%s\n", (char*)enc_out);
    
         decrypt(enc_out, encslength, &dec_key, init_vector); //see above
         printf("decrpyted:\t%s\n", (char*)enc_out);
       }
       fclose(fp);
    }
    

    它现在做了人们期望它做的事情。您必须非常小心密钥大小。由于我不知道的悬挂零(来自字符串),我崩溃了很多。此外,您可以查看EVP Symmetric Encryption and Decryption 和 XTS 以获取高达 512 位的密钥。

    【讨论】:

    • 整件事与 Ubuntu 无关,顺便说一句。
    • AES 支持三种密钥大小:128、192 和 256 位。
    猜你喜欢
    • 2015-10-03
    • 2012-06-08
    • 2012-09-06
    • 2022-07-09
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    相关资源
    最近更新 更多