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

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

我可以使用 PEM_read_RSA_PUBKEY 函数轻松读取 PEM 文件。但是,我在可执行文件中内置了一个 public 键,我不想创建临时文件。阅读此 example/tutorial: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;
}

然而我有很多疑惑:

  1. BIO_new_mem_buf需要一个const void*参数,我可以只传一个const char*吗?我什至从 docs.
  2. 都没有弄清楚
  3. 在调用PEM_read_bio_RSA_PUBKEY函数时,原来的例子是这样调用的: rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); 即使在阅读 docs 之后我也不明白。我认为我应该将 nullptr 作为第二个参数传递。
  4. 我应该在返回的 RSA 指针上调用 RSA_free 吗? valgrind 无论我是否这样做,都没有发现内存泄漏。
  5. 我应该在完成 BIO 后调用 BIO_free(keybio); 吗? valgrind 如果我不这样做,就会发现内存泄漏,并且在教程中缺少此调用。如果我调用 BIO_free(keybio);,则意味着 PEM_read_bio_RSA_PUBKEYBIO 复制了数据,而不仅仅是链接到它。但如果是这样的话,我不应该释放 RSA 吗?

非常感谢任何建议。我不知道什么是真实的了。

每个问题的答案:

  1. 是的,你可以传一个const char*,就是投。
  2. PEM_read_bio_RSA_PUBKEY为您创建分配RSA结构。参数(如果不为空)用于存储指向它的指针,这将与 return 值相同。用于简化编码:if (!PEM_read_bio_RSA_PUBKEY(keybio, &rsa, nullptr, nullptr)) { /* error */ }

  3. 是的,你必须使用RSA_free来释放它。

  4. 是的,你也得发布。

P.S.: OpenSSL 文档有点棘手,因为有许多类似的功能,只是算法、结构或数据格式不同。在 man page 的末尾有一个 Description 部分,其中对它们进行了解释,删除了每个变体的细节。但是,是的,如果没有好的教程或示例,很难找到它。