错误的加密(QT c++ OpenSSL AES 256 CBC)

Posted

技术标签:

【中文标题】错误的加密(QT c++ OpenSSL AES 256 CBC)【英文标题】:Wrong Encryption (QT c++ OpenSSL AES 256 CBC) 【发布时间】:2019-04-14 06:35:00 【问题描述】:

我编写了一个小程序来使用 OpenSSL AES 256 CBC 加密和解密数据,但在解密加密数据后,我最终得到了垃圾数据,所以代码中一定有问题,但我无法弄清楚你能不能看看代码,告诉我我做错了什么:

主要功能:

  /* Message to be encrypted */
    unsigned char* plaintext =
                (unsigned char*)"The quick brown fox jumps over the lazy dog";

  EVP_CIPHER_CTX *en, *de;
   en = EVP_CIPHER_CTX_new();
   de = EVP_CIPHER_CTX_new();

    /* 8 bytes to salt the key_data during key generation. This is an example of
       compiled in salt. We just read the bit pattern created by these two 4 byte
       integers on the stack as 64 bits of contigous salt material -
       ofcourse this only works if sizeof(int) >= 4 */
    unsigned int salt[] = 12345, 54321;
    unsigned char *key_data;
    int key_data_len, i;

    key_data = (unsigned char*)"01234567890123456789012345678901";
    key_data_len = strlen((const char*)key_data);

    Encryption AES;

    /* gen key and iv. init the cipher ctx object */
    if (AES.Init(key_data, key_data_len, (unsigned char *)&salt, en, de)) 
      qDebug() << "Couldn't initialize AES cipher ";
    

      unsigned char *ciphertext;
      int olen, len;

      /* The enc/dec functions deal with binary data and not C strings. strlen() will
         return length of the string without counting the '\0' string marker. We always
         pass in the marker byte to the encrypt/decrypt functions so that after decryption
         we end up with a legal C string */
      olen = len = strlen((const char*)plaintext)+1;



      ciphertext = AES.Encrypt(en, plaintext, &len);
      plaintext = (unsigned char*)"";
      plaintext = AES.Decrypt(de, ciphertext, &len);

      QString s;
      QString result = "";
      int rev = strlen((const char*)ciphertext);

      for ( int i = 0; i<rev; i++)
           
              s = QString("%1").arg(ciphertext[i],0,16);

              if(s == "0")
                s="00";
               
            result.append(s);

            

      ui->label_7->setText(result);

      rev = len;
      result = "";
      for ( int i = 0; i<rev; i++)
                     
                        s = QString("%1").arg(plaintext[i],0,16);

                        if(s == "0")
                          s="00";
                         
                      result.append(s);

                      

      ui->label_8->setText(result);

      free(ciphertext);
      free(plaintext);

    EVP_CIPHER_CTX_free(en);
    EVP_CIPHER_CTX_free(de);

初始化函数:

int Encryption::Init(unsigned char *key_data, int key_data_len, unsigned char *salt, EVP_CIPHER_CTX *e_ctx,
             EVP_CIPHER_CTX *d_ctx)

  int i, nrounds = 5;
  unsigned char key[32], iv[32];

  /*
   * Generate key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
   * nrounds is the number of times we hash the material. More rounds are more secure but
   * slower.
   */
  i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, key_data_len, nrounds, key, iv);
  if (i != 32) 
    QMessageBox::warning(this, tr("Error while generating the key"), tr("The key isn't 256 bit!"));
    return -1;
  

  EVP_CIPHER_CTX_init(e_ctx);
  EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
  EVP_CIPHER_CTX_init(d_ctx);
  EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv);

  return 0;

加密函数:

inline unsigned char* Encryption:: Encrypt(EVP_CIPHER_CTX *e, unsigned char *plaintext, int *len)

  // max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE bytes
  int c_len = *len + AES_BLOCK_SIZE, f_len = 0;
  ciphertext = new unsigned char[c_len];

  // allows reusing of 'e' for multiple encryption cycles
  EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);

  /* update ciphertext, c_len is filled with the length of ciphertext generated,
    *len is the size of plaintext in bytes */
  int encrypted_bytes = 0;

  for(int i=0;i<*len/AES_BLOCK_SIZE;++i)
  
      EVP_EncryptUpdate(e, ciphertext+encrypted_bytes, &c_len, plaintext+encrypted_bytes, AES_BLOCK_SIZE);
      encrypted_bytes += AES_BLOCK_SIZE;
      float counter = i , size = *len/AES_BLOCK_SIZE+1;
      emit Encryption_Percentage_Changed(counter/size * 100);
  
  // update ciphertext with the final remaining bytes
  EVP_EncryptFinal_ex(e, ciphertext+*len, &f_len);

  *len = *len + f_len;

  emit Encryption_Finished();

  return ciphertext;

解密函数:

inline unsigned char* Encryption::Decrypt(EVP_CIPHER_CTX *e, unsigned char *ciphertext, int *len)

  // plaintext will always be equal to or lesser than length of ciphertext
  int p_len = *len+AES_BLOCK_SIZE, f_len = 0;

  plaintext = new unsigned char[p_len];

  EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);

  int decrypted_bytes = 0;

  for(int i=0;i<*len/AES_BLOCK_SIZE;++i)
      EVP_DecryptUpdate(e, plaintext+decrypted_bytes, &p_len, ciphertext+decrypted_bytes, AES_BLOCK_SIZE);
      decrypted_bytes += AES_BLOCK_SIZE;
      float counter = i , size = *len/AES_BLOCK_SIZE;
      emit Decryption_Percentage_Changed(counter/size * 100);
  

  EVP_DecryptFinal_ex(e, plaintext+*len, &f_len);


  *len = *len + f_len;

  emit Decryption_Finished();

  return plaintext;

编辑:我现在已经用实际代码替换了图像。

任何帮助将不胜感激。 提前致谢。

【问题讨论】:

理想情况下,无论如何,您都应该在一个大块中提供代码,这样其他人就可以复制粘贴它,然后用最少的工作量编译和运行它。所以不要忘记添加编译所需的包含。顺便说一句,具有足够声誉的其他人可以编辑您的问题,因此如果您无法正确格式化问题,其他人可以为您解决。 @Eelke 非常感谢您提供的信息,但代码编译得很好,这不是我面临的编译错误,而是逻辑错误。因为当我加密文本并尝试解密它时,我不会't get the original text. 【参考方案1】:

当我尝试 result=QString::fromLocal8Bit((char*)ciphertext); 时,我终于意识到在显示加密和解密字符串时出现了什么问题。 它运行良好并显示了原始文本。

【讨论】:

以上是关于错误的加密(QT c++ OpenSSL AES 256 CBC)的主要内容,如果未能解决你的问题,请参考以下文章

OpenSSL AES_cfb128_encrypt C++

C++ 和 Qt 5 中的 AES 256 加密

如何在 Openssl 中使用 AES 进行加密

使用 OpenSSL/C++ 和 PHP/Mcrypt 的 AES-128-CBC 加密:仅解密第一个块

利用openSSL库AES模块加密

mbedtls 和 openssl 之间的不同 AES-256 加密输出