【问题标题】:error:FFFFFFFFFFFFFFFF:lib(255):func(4095):reason(4095) during RSA decyptionRSA解密期间错误:FFFFFFFFFFFFFFFF:lib(255):func(4095):reason(4095)
【发布时间】:2014-11-06 16:14:36
【问题描述】:

我正在尝试使用 Qt Gui 在 C++ 中创建一个混合加密工具。 (数据将使用 AES 256-CBC 加密,然后 AES 密钥 RSA 加密并保存。) 但是这个工具的 RSA 部分不起作用。 我写了好几次源代码,但我总是在解密时得到同样的错误。

error:FFFFFFFFFFFFFFFF:lib(255):func(4095):reason(4095)

我希望有人可以帮助我获得一个有效的 RSA 加密 + 解密实现。

您可以在此处查看源代码或从我的 Dropbox 下载测试 Qt 项目。

Dropbox 下载:https://db.tt/6HKsYRTa

源码1.实现:

void MainWindow::rsaEncrypt()
{
    EVP_PKEY *pk = NULL;
    EVP_PKEY_CTX *ctx = NULL;

    QByteArray encrypted = QByteArray();

    //------------------------------------------------
    //--- READ PUBLIC KEY ----------------------------
    FILE *pkFile = fopen(ui->publicKeyPath->text().toStdString().c_str(), "r");
    if(pkFile == NULL) throw NULL;

    pk = PEM_read_PUBKEY(pkFile, NULL, NULL, NULL);
    if(pk == NULL) throw NULL;
    fclose(pkFile);
    //------------------------------------------------
    ctx = EVP_PKEY_CTX_new(pk, NULL);


    //------------------------------------------------
    //--- ENCRYPT DATA -------------------------------
    int err;

    err = EVP_PKEY_encrypt_init(ctx);
    if(err <= 0) throw NULL;

    err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PADDING);
    if(err <= 0) throw NULL;

    size_t outLen = 0;
    err = EVP_PKEY_encrypt(
                            ctx,
                            NULL,
                            &outLen,
                            (uchar*) ui->plainTextEdit->document()->toPlainText().toStdString().c_str(),
                            ui->plainTextEdit->document()->toPlainText().size()
    );
    if(err <= 0) throw NULL;
    encrypted.resize(outLen);

    err = EVP_PKEY_encrypt(
                            ctx,
                            (uchar*) encrypted.data(),
                            &outLen,
                            (uchar*) ui->plainTextEdit->document()->toPlainText().toStdString().c_str(),
                            ui->plainTextEdit->document()->toPlainText().size()
    );
    //------------------------------------------------
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pk);

    if(err > 0) ui->encryptedTextEdit->document()->setPlainText(QString(encrypted));
    else {
            QByteArray errStr = QByteArray();
            errStr.resize(256);
            ERR_load_ERR_strings();
            ERR_error_string(err, errStr.data());
            ui->encryptedTextEdit->document()->setPlainText( QString(errStr) );
    }
}

void MainWindow::rsaDecrypt()
{
    EVP_PKEY *pk = NULL;
    EVP_PKEY_CTX *ctx = NULL;

    QByteArray decrypted = QByteArray();

    //------------------------------------------------
    //--- READ PRIVATE KEY ---------------------------
    FILE *pkFile = fopen(ui->privateKeyPath->text().toStdString().c_str(), "r");
    if(pkFile == NULL) throw NULL;

    pk = PEM_read_PrivateKey(pkFile, NULL, NULL, NULL);
    if(pk == NULL) throw NULL;
    fclose(pkFile);
    //------------------------------------------------
    ctx = EVP_PKEY_CTX_new(pk, NULL);


    //------------------------------------------------
    //--- DECRYPT DATA -------------------------------
    int err;

    err = EVP_PKEY_decrypt_init(ctx);
    if(err <= 0) throw NULL;

    err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PADDING);
    if(err <= 0) throw NULL;

    size_t outLen = 0;
    err = EVP_PKEY_decrypt(
                            ctx,
                            NULL,
                            &outLen,
                            (uchar*) ui->encryptedTextEdit->document()->toPlainText().toStdString().c_str(),
                            ui->encryptedTextEdit->document()->toPlainText().size()
    );
    if(err <= 0) throw NULL;
    decrypted.resize(outLen);

    err = EVP_PKEY_decrypt(
                            ctx,
                            (uchar*) decrypted.data(),
                            &outLen,
                            (uchar*) ui->encryptedTextEdit->document()->toPlainText().toStdString().c_str(),
                            ui->encryptedTextEdit->document()->toPlainText().size()
    );
    //------------------------------------------------
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(pk);

    if(err > 0) ui->decryptedTextEdit->document()->setPlainText(QString(decrypted));
    else {
            QByteArray errStr = QByteArray();
            errStr.resize(256);
            ERR_load_ERR_strings();
            ERR_error_string(err, errStr.data());
            ui->decryptedTextEdit->document()->setPlainText( QString(errStr) );
    }
}

源码2.实现:

void MainWindow::rsaEncrypt()
{
    RSA *rsa = createRSAFromFile(ui->publicKeyPath->text().toStdString().c_str(), 1);

    QByteArray encrypted = QByteArray();
    encrypted.resize(2048);

    int err = RSA_public_encrypt(
                    ui->plainTextEdit->document()->toPlainText().size(),
                    (uchar*) ui->plainTextEdit->document()->toPlainText().toStdString().c_str(),
                    (uchar*) encrypted.data(),
                    rsa,
                    RSA_PADDING
    );

    RSA_free(rsa);
    if(err > 0) ui->encryptedTextEdit->document()->setPlainText( QString(encrypted) );
    else {
            QByteArray errStr = QByteArray();
            errStr.resize(256);
            ERR_load_ERR_strings();
            ERR_error_string(err, errStr.data());
            ui->encryptedTextEdit->document()->setPlainText( QString(errStr) );
    }
}

void MainWindow::rsaDecrypt()
{
    RSA *rsa = createRSAFromFile(ui->privateKeyPath->text().toStdString().c_str(), 0);

    QByteArray decrypted = QByteArray();
    decrypted.resize(2048);

    int err = RSA_private_decrypt(
                    ui->encryptedTextEdit->document()->toPlainText().size(),
                    (uchar*) ui->encryptedTextEdit->document()->toPlainText().toStdString().c_str(),
                    (uchar*) decrypted.data(),
                    rsa,
                    RSA_PADDING
    );


    RSA_free(rsa);
    if(err > 0) ui->decryptedTextEdit->document()->setPlainText( QString(decrypted) );
    else {
            QByteArray errStr = QByteArray();
            errStr.resize(256);
            ERR_load_ERR_strings();
            ERR_error_string(err, errStr.data());
            ui->decryptedTextEdit->document()->setPlainText( QString(errStr) );
    }
}

RSA *MainWindow::createRSAFromFile(const char *keyPath, int pub)
{
    FILE *keyFile = fopen(keyPath, "rb");
    if(keyFile==NULL)
    {
            return 0;
    }
    RSA *rsa = RSA_new();

    if(pub)
    {
            rsa = PEM_read_RSA_PUBKEY(keyFile, &rsa, NULL, NULL);
    }
    else
    {
            rsa = PEM_read_RSAPrivateKey(keyFile, &rsa, NULL, NULL);
    }
    fclose(keyFile);
    return rsa;
}

包含并定义两种实现:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>
#include <QByteArray>

#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

#define RSA_PADDING RSA_PKCS1_OAEP_PADDING

【问题讨论】:

  • 你到底是从哪里得到错误的?
  • @Theolodis:错误是函数 EVP_PKEY_decrypt() 和 RSA_private_decrypt() 的返回值。
  • @DmitryLedentsov rsaEncrypt 在 MainWindow 中,因为这个源码只是一个小版本用于测试它,我稍后会写一个类(当加密和解密工作时)。
  • @H4ckHunt3r,我建议为此目的进行与 GUI 无关的单元测试

标签: c++ qt openssl rsa crypt


【解决方案1】:

尝试使用此代码创建 RSA 对象。它绝对有效。您应该先阅读 .pem 文件,然后调用此函数:

RSA *CryptClassRSA::createRSA(unsigned char *key, int isPublic){
    RSA *rsa = NULL;
    BIO *keybio;
    keybio = BIO_new_mem_buf(key, -1);
    if (keybio==NULL){
        printf( "Failed to create key BIO");
        return NULL;
    }
    if(isPublic){
        rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL);
    }
    else{
        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
    }
    if(rsa == NULL){
        printf( "Failed to create RSA");
    }

    return rsa;
}

【讨论】:

    【解决方案2】:

    C++ RSA 解密错误:FFFFFFFFFFFFFFFF:lib(255):func(4095):reason(4095)

    int err;
    ...
    err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PADDING);
    if(err <= 0) throw NULL;
    ...
    

    我不清楚在哪里错误发生或您如何获得error:FFFFFFFFFFFFFFFF:lib(255):func(4095):reason(4095)errstr输出/em>。我选择 EVP_PKEY_CTX_set_rsa_padding 作为 sn-p,因为我认为返回值为 -2(其意义如下所述)。

    err 只是一个返回码。要获得实际错误,您需要致电 ERR_get_error。可能是这样的:

    int rc;
    unsigned long err;
    ...
    
    rc = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PADDING);
    err = ERR_get_error();
    if(rc <= 0)
    {
        // err is valid
    }
    

    您还应该访问 EVP_PKEY_CTX_set_rsa_paddingERR_get_error 手册页。

    OpenSSL 通常会返回 0 表示成功,所以我不确定在某些地方是否有 err &lt;= 0。另外,由于您的错误是 0xffff...4095(而不是 4096),我认为您得到了手册页中讨论的 -2 返回值:

    EVP_PKEY_CTX_ctrl() 及其宏返回正值表示成功,0 或负值表示失败。特别是返回值 -2 表示公钥算法不支持该操作。


    另请注意...如果您收集错误并以十六进制打印:

    rc = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PADDING);
    err = ERR_get_error();
    if(rc <= 0)
    {
        // err is valid
        std::cerr << std::hex << err << std::endl;
    }
    

    然后你就可以用openssl errstr 0xNNNN来打印了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-08
      • 2018-10-27
      • 2018-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      相关资源
      最近更新 更多