rsa_private_decrypt返回 -1,错误0x0306B067

rsa_private_decrypt returns -1, error 0x0306B067

本文关键字:错误 0x0306B067 返回 private decrypt rsa      更新时间:2023-10-16

我想在C++中使用OpenSSL测试RSA密钥对。我加密文本并立即解密。加密成功完成,但解密始终返回 -1。错误号为:

0306B067:lib(3):func(107):reason(103)

我找不到原因...代码为:

char* text = "hello!!!";
unsigned char * cipher ;
unsigned char * decipher ;
int size = RSA_size(prvKey);
cipher = (unsigned char *)malloc(size);
decipher = (unsigned char *)malloc(size);
int cipherres = RSA_public_encrypt(size - 11/*strlen(text)*/,(unsigned char*)text,cipher,pubKey,RSA_PKCS1_PADDING);
int decipherres = RSA_private_decrypt(size,cipher,decipher,prvKey,RSA_PKCS1_PADDING);
if (decipherres == -1)

RSA 密钥对是为使用该函数生成的RSA_generate_key_ex()其密钥对位于 pubKey 和 prvKey 中。

我不喜欢这一行的外观:

int cipherres = RSA_public_encrypt(size - 11/strlen(text)/,...

您应该使用文本的长度,这似乎是您以前所做的。我不知道你从哪里得到 11,但代码中的幻数闻起来很糟糕。

尝试:

int cipherres = RSA_public_encrypt(strlen(text),...

另外,参考此处RSA_public_encrypt的文档,以下行看起来是错误的:

int size = RSA_size(prvKey);

根据定义,prvKey 和 pubKey 的大小是否相同?如果没有,请尝试在加密之前使用公钥获取大小:

int size = RSA_size(pubKey);

然后,您可能需要单独获取 prvKey 的大小,并将解密缓冲区 malloc 设置为该大小。

您的程序存在几个问题。@Resource指出了其中一些问题。由于您将其标记为C++,因此这是执行这些操作C++方法。它与您编写的基本程序相同,但解决了许多问题。

答案还使用如何使用OpenSSL生成RSA私钥?来生成RSA密钥对。

OpenSSL 建议您使用 EVP 接口,而不是 RSA_public_encryptRSA_private_decrypt 。另请参阅 OpenSSL wiki 上的 EVP 非对称加密和解密。

#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <string>
#include <memory>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <cassert>
#define ASSERT assert
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
int main(int argc, char* argv[])
{   
    ////////////////////////////////////////////////////////////
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    ////////////////////////////////////////////////////////////
    RSA_ptr privKey(RSA_new(), ::RSA_free);
    RSA_ptr pubKey(RSA_new(), ::RSA_free);
    BN_ptr bn(BN_new(), ::BN_free);
    int rc;
    // Set exponent
    rc = BN_set_word(bn.get(), RSA_F4);
    ASSERT(rc == 1);
    if (rc != 1)
    {
        std::ostringstream msg;
        msg << "BN_set_word failed. Error 0x" << std::hex << ERR_get_error();
        throw std::runtime_error(msg.str());
    }
    // Generate private key
    rc = RSA_generate_key_ex(privKey.get(), 2048, bn.get(), NULL);
    ASSERT(rc == 1);
    if (rc != 1)
    {
        std::ostringstream msg;
        msg << "RSA_generate_key_ex failed. Error 0x" << std::hex << ERR_get_error();
        throw std::runtime_error(msg.str());
    }
    // Create a public key from private key
    pubKey.reset(RSAPublicKey_dup(privKey.get()));
    ////////////////////////////////////////////////////////////
    std::string text = "Yoda said, Do or do not. There is no try.";
    std::string cipher, decipher;
    int size = RSA_size(privKey.get());
    ASSERT(size >= 0);
    if (size < 0)
    {
        std::ostringstream msg;
        msg << "RSA_size failed. Error 0x" << std::hex << ERR_get_error();
        throw std::runtime_error(msg.str());
    }
    // 41 due to RSA_PKCS1_OAEP_PADDING
    ASSERT(text.length() + 41 < size);
    if (text.length() + 41 >= size)
    {
        std::ostringstream msg;
        msg << "Plain text length is too long for modulus and padding";
        throw std::runtime_error(msg.str());
    }
    // Resize to maximum size
    cipher.resize(size);
    decipher.resize(size);
    rc = RSA_public_encrypt(text.length(),(unsigned char*)&text[0],
            (unsigned char*)&cipher[0], pubKey.get(), RSA_PKCS1_OAEP_PADDING);
    ASSERT(rc >= 0);
    if (rc < 0)
    {
        std::ostringstream msg;
        msg << "RSA_public_encrypt failed. Error 0x" << std::hex << ERR_get_error();
        throw std::runtime_error(msg.str());
    }
    // Resize now that we know the size
    cipher.resize(size);
    rc = RSA_private_decrypt(cipher.length(), (unsigned char*)&cipher[0],
            (unsigned char*)&decipher[0], privKey.get(), RSA_PKCS1_OAEP_PADDING);
    ASSERT(rc >= 0);
    if (rc < 0)
    {
        std::ostringstream msg;
        msg << "RSA_private_decrypt failed. Error 0x" << std::hex << ERR_get_error();
        throw std::runtime_error(msg.str());
    }
    std::cout << "Message: " << text << std::endl;
    std::cout << "Recovered: " << decipher << std::endl;
    return 0;
}

该程序只需要库的加密部分。该程序是从OpenSSL 1.0.2源目录构建的,具有:

$ g++ -std=c++11 -DNDEBUG -I ./include test.cxx ./libcrypto.a -ldl -o test.exe
$ ./test.exe
Message: Yoda said, Do or do not. There is no try.
Recovered: Yoda said, Do or do not. There is no try.

关于这一点:

0306B067:lib(3):func(107):reason(103)

尝试:

$ openssl errstr 0306B067
error:0306B067:bignum routines:BN_div:div by zero

我的猜测是,pubKeyprivKey有问题.