I could use the PEM_read_RSA_PUBKEY
function to easily read a PEM file. 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:
#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:
BIO_new_mem_buf
takes a const void*
parameter, can I just pass a const char*
? I did not figure it out even from the docs.PEM_read_bio_RSA_PUBKEY
function, the original example calls it like this:
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.RSA_free
on the returned RSA
pointer? valgrind
does not see a memory leak whether I do it or not.BIO_free(keybio);
after I am done with the BIO
? valgrind
sees a memory leak if I do not, and in the tutorial this call was missing. If I call BIO_free(keybio);
it would imply that PEM_read_bio_RSA_PUBKEY
copied the data from the BIO
rather than just linking to it. But if that were the case, shouldn't I free the RSA
?Any advice is warmly appreciated. I do not know what is real anymore.
Answers to each of your questions:
const char*
, it is cast.PEM_read_bio_RSA_PUBKEY
creates allocates the RSA structure for you. The argument (if not null) is used to store the pointer to it, which will be the same as the return value. It is used for simplified coding: if (!PEM_read_bio_RSA_PUBKEY(keybio, &rsa, nullptr, nullptr)) { /* error */ }
Yes, you have to release it using RSA_free
.
P.S.: OpenSSL documentation is a bit tricky because there are many similar functions that only vary in algorithm, structures or data format. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With