如何在Ubuntu中正确使用AES_CBC_Encrypt 128 openssl?

时间:2014-12-19 01:41:49

标签: c string openssl aes encryption-symmetric

仍然发现在C中使用内存很难。我正在阅读一个文本文件,其中我将包含名称和40个字符的随机字符串的每行文本存储到2个缓冲区中,char buffer1 [128和char buffer2 [128]使用人们似乎不喜欢的fscanf(),后来我需要把JUST字符串(在缓冲区的其余部分没有任何填充或空格)并使用AES-CBC-128加密它然后在解密它。我在名称上使用md5生成一个16字节的密钥,我在加密过程中使用它,随机初始化向量再次为16字节。现在,加密/解密几乎可以正常工作,如果我自己输入40个字符串到AES加密函数中(即字符串后来正确解密,但事先出现了一些额外的乱码字符),但如果我通过包含字符串的缓冲区进入函数,解密出来所有带有乱码的字符(换句话说它不起作用)。如果我尝试使缓冲区足够小以完全包含字符串(char buffer [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包含:

yves E9D0EEFC4C6DD81F2A7BDE99CCE833FB7B2BDD6D 亚当D6C33F73EC7175AEA67DEC98427B42AAF6E5E04C 大卫F58EEB1DDB9511A3F220A4B10F01F88260BC99AB umbert F6A6127E6562C5816433FB3B7C341C45A8805DCB 维多利亚CCF10AA4A4725C964FFF78BA3694393ADE1D7B6C nick C8030118EB5E037F6131D9BB5B1BEF0A3F2AC458 小峰E9B45ECAE2F42D59B90EACB2CA8E75A969A7EFAB 前夕D8DA8BC812D9CD72B91EB7AF49D099A9BE85AB43 所属分类:CC039D2746A3C55E4BA1DCEE46F329E4CA7E0A1A 佛罗伦萨C2DFD6650343659BFB530FE719139AB4D3F2BEDC 赫伯特CDCB4196E8CA9002219EC7A8F372911501BD1BBD 常春藤E53BC8DF9A81BDD881E5352BCE11A2BF0F33236B 插孔C5213B5F8DC334010586FB094A63D50A7572470E osvald D0FBD9B2102DF6C41C8B26F25AF3E18ACF2BD27C 史蒂文C9A3AB53FAA9E8243A63EBDC3257D1C8CCEC7D1C 凯文D7C6774E65DBB8F312F50183C87D67BC6FBF7BED 加文F4C1945162294DD902C6BC11EE23BF8B682AC6C9 卢克DF2FD780E13F9511411EC92B476D167A6D9F334A 马丁FE6D5175D3B6E49B6649DBD6F21559F15847CA31 pippo DA908468DBE291E4DDEB082E36E9F5BB316A3C3C 理查德EC26FF6B364C51DCA5A7CB5D711BCC85946D2517 特洛伊F1165BE81E08B38A42C582A8F25C2CC382233F3D zach EF19BED4FD6732C92437A3F65C4BE69A5010994D 威廉EC74AA8C93AA32EFF85EC4437F50F1F86AECAC29 查理C86D2F8A3EF1F03127628C7CF9C6D9FB730DACBF

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

2 个答案:

答案 0 :(得分:0)

我设法弄清楚了我的严重错误。这一行:

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

应该是:

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

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

答案 1 :(得分:-1)

我自己也在努力解决OpenSSL的错误记录API。功能本身在Assembler中实现真的无济于事,所以即使是源代码也无济于事。但我能够发现你犯过的一些错误:

  1. 如您所述,AES_set_encrypt_key位大小作为第二个参数,而不是字节。
  2. 必须正好是16,24或32字节的大小。
  3. 在加密和解密开始时,给定的init_vector 必须相同。
  4. 因为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);
    }
    

    我正在努力阅读和写作。如您所见,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位的密钥。