【问题标题】:rsa_private_decrypt returns -1, error 0x0306B067rsa_private_decrypt 返回 -1,错误 0x0306B067
【发布时间】:2018-03-02 23:26:55
【问题描述】:

我想在 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中。

【问题讨论】:

    标签: c++ encryption openssl rsa


    【解决方案1】:

    我不喜欢这条线的样子:

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

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

    试试:

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

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

    int size = RSA_size(prvKey);

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

    int size = RSA_size(pubKey);

    然后您可能需要单独获取 prvKey 的大小并将解密缓冲区分配到该大小。

    【讨论】:

    • 首先,感谢您的快速回答。我之前用过 strlen(txt) 但结果是一样的。在您链接的 RSA_public_ecnrypt 文档中,它说“对于基于 PKCS #1 v1.5 的填充模式,flen 必须小于 RSA_size(rsa) - 11”,我使用这个大小。我认为 RSA_size() 返回 muduluse 大小并且公钥和私钥之间没有区别,你认为我错了吗?
    • 我自己没有使用过,但我在这里找到了一个类似的问题,并提供了一个有用的答案:stackoverflow.com/questions/426463/problem-with-openssl-library。看起来您应该将加密的返回值提供给解密。这是有道理的——它告诉解密它应该处理多少个字符。加密和解密缓冲区的大小适中,我认为应该是这样。
    • @Resource - 我欠你一个赞成票,但我现在不在。其中一些很好。
    【解决方案2】:

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

    答案还使用How to generate RSA private key using OpenSSL? 生成 RSA 密钥对。

    OpenSSL 建议您使用 EVP 接口而不是 RSA_public_encryptRSA_private_decrypt。另请参阅 OpenSSL wiki 上的 EVP Asymmetric Encryption and Decryption

    #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 有问题。

    【讨论】:

      猜你喜欢
      • 2010-09-30
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-25
      • 2013-02-14
      • 2015-10-05
      相关资源
      最近更新 更多