简体   繁体   English

如何使用OpenSSL API从其PEM格式字符串中读取RSA公钥?

[英]How to read an RSA public key from a its PEM format string using the OpenSSL API?

I could use the PEM_read_RSA_PUBKEY function to easily read a PEM file . 我可以使用PEM_read_RSA_PUBKEY函数轻松读取PEM 文件 However, I have a public key that I have built into the executable and I would prefer not to make a temporary file. 但是,我有一个公钥,我已经内置到可执行文件中,我宁愿不制作一个临时文件。 Reading on this example/tutorial: http://hayageek.com/rsa-encryption-decryption-openssl-c/ I came up with the following solution: 阅读这个示例/教程: http//hayageek.com/rsa-encryption-decryption-openssl-c/我提出了以下解决方案:

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>

#include <QFile>
#include <QByteArray>

#include <stdexcept>
#include <cassert>
#include <cstring>

RSA* createRSA(const char* key)
{
    RSA *rsa = nullptr;
    BIO *keybio ;
    keybio = BIO_new_mem_buf(key, -1); // !!!
    if (!keybio)
    {
        throw std::runtime_error("Failed to create key BIO");
    }
    rsa = PEM_read_bio_RSA_PUBKEY(keybio, nullptr, nullptr, nullptr);  // !!!
    if(!rsa )   
    {
        throw std::runtime_error("Failed to create RSA");
    }
    BIO_free(keybio); // !!!
    return rsa;
}

int main()
{
    QFile publicKeyFile(":/public.pem");
    publicKeyFile.open(QIODevice::ReadOnly);
    auto data = publicKeyFile.readAll();

    RSA* rsa = createRSA(data.data());

    EVP_PKEY* verificationKey = EVP_PKEY_new();
    auto rc = EVP_PKEY_assign_RSA(verificationKey, RSAPublicKey_dup(rsa));
    assert(rc == 1);

    if(verificationKey)
        EVP_PKEY_free(verificationKey);

    return 0;
}

However I have a lot of doubts: 但是我有很多疑问:

  1. The BIO_new_mem_buf takes a const void* parameter, can I just pass a const char* ? BIO_new_mem_buf采用const void*参数,我可以只传递一个const char*吗? I did not figure it out even from the docs . 我甚至没有从文档中弄明白。
  2. When calling the PEM_read_bio_RSA_PUBKEY function, the original example calls it like this: rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); 在调用PEM_read_bio_RSA_PUBKEY函数时,原始示例将其调用如下: rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); which I do not understand even after reading the docs . 即使在阅读完文档后我也听不懂。 I believe that I should pass nullptr as the second argument. 我相信我应该将nullptr作为第二个参数传递。
  3. Should I call RSA_free on the returned RSA pointer? 我应该在返回的RSA指针上调用RSA_free吗? valgrind does not see a memory leak whether I do it or not. 无论我是否这样做, valgrind都没有看到内存泄漏。
  4. Should I call BIO_free(keybio); 我应该打电话给BIO_free(keybio); after I am done with the BIO ? 在我完成BIO valgrind sees a memory leak if I do not, and in the tutorial this call was missing. 如果我不这样做, valgrind看到内存泄漏,并且在教程中这个调用丢失了。 If I call BIO_free(keybio); 如果我打电话给BIO_free(keybio); it would imply that PEM_read_bio_RSA_PUBKEY copied the data from the BIO rather than just linking to it. 这意味着PEM_read_bio_RSA_PUBKEYBIO复制数据而不是仅仅链接到它。 But if that were the case, shouldn't I free the RSA ? 但如果是这样的话,我不应该释放RSA吗?

Any advice is warmly appreciated. 任何建议都热烈赞赏。 I do not know what is real anymore. 我不知道什么是真实的。

Answers to each of your questions: 您的每个问题的答案:

  1. Yes, you can pass a const char* , it is cast. 是的,你可以传递一个const char* ,它是强制转换的。
  2. PEM_read_bio_RSA_PUBKEY creates allocates the RSA structure for you. PEM_read_bio_RSA_PUBKEY创建为您分配RSA结构。 The argument (if not null) is used to store the pointer to it, which will be the same as the return value. 参数(如果不为null)用于存储指向它的指针,该指针与返回值相同。 It is used for simplified coding: if (!PEM_read_bio_RSA_PUBKEY(keybio, &rsa, nullptr, nullptr)) { /* error */ } 它用于简化编码: if (!PEM_read_bio_RSA_PUBKEY(keybio, &rsa, nullptr, nullptr)) { /* error */ }

  3. Yes, you have to release it using RSA_free . 是的,你必须使用RSA_free释放它。

  4. Yes, you have to release it too. 是的,你也必须释放它。

PS: OpenSSL documentation is a bit tricky because there are many similar functions that only vary in algorithm, structures or data format. PS:OpenSSL文档有点棘手,因为有许多类似的函数只在算法,结构或数据格式上有所不同。 At the end of the man page there is a Description section where they are explained, removing the specifics of each variation. 手册页的末尾有一个描述部分,在这里解释它们,删除每个变体的细节。 But yes, it is quite difficult to find it out with out a good tutorial or examples. 但是,是的,通过一个很好的教程或例子很难找到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM