【问题标题】:QT OpenSSL AES 256 CBC Encryption program crashes when try to write to fileQT OpenSSL AES 256 CBC 加密程序在尝试写入文件时崩溃
【发布时间】:2019-04-18 08:49:35
【问题描述】:

我正在编写一个小程序来使用 OpenSSL AES 256 CBC 算法加密文件。 我在输入自己的文本上尝试了加密和解密部分,它工作正常。现在我尝试打开文件进行加密,然后保存加密的文件,我在写入函数调用或之后根据密钥或之后出现运行时错误我认为的文件大小。我不知道我做错了什么,请您看一下代码并指出错误。 提前致谢。

加密类:

    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];

  /*
   * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
   * nrounds is the number of times the 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) {
    qDebug()<<"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;
}

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 -1 bytes */
  int c_len = *len + AES_BLOCK_SIZE, f_len = 0;
  unsigned char *ciphertext = (unsigned char*)malloc(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 */
  EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, *len);
  /* update ciphertext with the final remaining bytes */
  EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len);

  *len = c_len + f_len;
  return ciphertext;
}

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, f_len = 0;
  unsigned char *plaintext = (unsigned char*)malloc(p_len);
  EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);
  EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len);
  EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len);


  *len = p_len + f_len;
  return plaintext;
}

unsigned char *Encryption::ReadFile(QString fileName)
{
    QByteArray data;
    QFile file(fileName);
    if(!file.open(QFile::ReadOnly))
    {
        qCritical() << file.errorString();
        return (unsigned char*) (data.constData());
    }

    data = file.readAll();
    file.close();
    return (unsigned char*) (data.constData());
}

void Encryption::WriteFile(QString fileName, unsigned char* data)
{
    QFile file(fileName);
    if(!file.open(QFile::WriteOnly))
    {
        qCritical() << file.errorString();
        return;
    }

    file.write((const char*)data,strlen((const char*)data));
    file.close();
}

主窗口:

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    QString Extension;
    qint64 size;
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
        size = QFileInfo(fileName).size();
        Extension = QFileInfo(fileName).suffix();
        ui->label->setText(fileName);
        ui->label_2->setText(QString::number(size)+" Bytes");
        ui->label_3->setText(Extension);
    }


}

void MainWindow::on_pushButton_2_clicked()
{
    Encryption AES;
    unsigned char* plaintext;
    QString SavedfileName = QFileDialog::getSaveFileName(this,
            tr("Save Encryption file"), "",
            tr("All Files (*)"));

    if(!fileName.isEmpty())
    {
        plaintext = AES.ReadFile(fileName);
        EVP_CIPHER_CTX *en, *de;
        en = EVP_CIPHER_CTX_new();
        de = EVP_CIPHER_CTX_new();

        unsigned int salt[] = {12345, 54321};
        unsigned char *key_data;
        int key_data_len, i;

        key_data = (unsigned char*)ui->lineEdit->text().constData();
        key_data_len = strlen((const char*)key_data);



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

          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);

          if (SavedfileName.isEmpty()){
              QMessageBox::information(this, tr("Unable to open encryption file!"),tr("Please enter a name to the encryption file."));
                  return;}
          else {
              QFile file(SavedfileName);
              if (!file.open(QIODevice::WriteOnly)) {
                  QMessageBox::information(this, tr("Unable to open file"),
                      file.errorString());
                  return;
              }
              else{
                  AES.WriteFile(SavedfileName,ciphertext);
              }
          }


          free(ciphertext);
          free(plaintext);

        EVP_CIPHER_CTX_free(en);
        EVP_CIPHER_CTX_free(de);



    }

}

void MainWindow::on_pushButton_3_clicked()
{
    //plaintext = AES.Decrypt(de, ciphertext, &len);
}

有一次程序在 free(ciphertext) 调用时崩溃了:

Debug info

Another crash debug info

【问题讨论】:

    标签: c++ qt encryption openssl


    【解决方案1】:

    如果您在 free(char*) 期间遇到段错误,则表示您没有正确分配内存。在调用 aes 函数之前,您需要为明文和密文分配内存

    plaintext=(char *) malloc(sizeof(char)); 
    
    ciphertext= (char *) malloc(sizeof(char)); 
    

    【讨论】:

    • 谢谢我确实忘记添加这两行了。现在它不会崩溃,但程序在代码中的这一行出现另一个错误退出: EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL);带有错误消息:crypto\evp\evp_enc.c:157:OpenSSL 内部错误:断言失败:ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 || ctx->cipher->block_size == 16
    【解决方案2】:

    QTextStream 是文件操作的明智选择。

    void Encryption::WriteFile(QString fileName, unsigned char* data)
    {
        QFile file(fileName);
        if(!file.open(QFile::WriteOnly))
        {
            qCritical() << file.errorString();
            return;
        }
        QTextStream outSt(&file);
    
        outSt<< data;
    
    
    
        //file.write((const char*)data,strlen((const char*)data));
        file.close();
    }
    

    【讨论】:

    • 我不能使用 QTextStream,因为我想加密所有类型的文件,甚至二进制文件,也许我可以使用 QDataStream,但崩溃仍在继续,令我困惑的是它有时会发生在文件中。 close() 调用,有时发生在 writeFile 函数之后,我不知道它是否取决于密钥大小或什么。
    • 有一次程序在 free(ciphertext) 时因分段错误而崩溃。
    猜你喜欢
    • 2019-04-14
    • 2013-08-11
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 2022-08-17
    • 1970-01-01
    • 2017-08-28
    相关资源
    最近更新 更多