I am using Public/Private Keys in my project to encrypt/decrypt some data.
I am hosting a public key ("public.pem") on a server.
"public.pem" looks like this:
-----BEGIN PUBLIC KEY-----
.....
.....
-----END PUBLIC KEY-----
I wrote a client side that downloads this public key and save it to disk and then calls OpenSSL's PEM_read_RSA_PUBKEY() with a File descriptor to that file. This operation works great and the result is an RSA object that is ready for encryption.
I would like to avoid writing the public key to disk each time (since i have the buffer in memory already).
How can i do the same operation without saving the buffer to disk? I noticed a function called: PEM_read_bio_RSAPublicKey() but i am not sure of it's usage of BIO structure. Am I on the right path?
So the real question would be: How do I read a public/private key to an RSA object straight from memory and not from a file descriptor.
You are on the right track. You must wrap the PEM key already in memory by means of a BIO buffer via BIO_new_mem_buf()
. In other words, something like:
BIO *bufio;
RSA *rsa
bufio = BIO_new_mem_buf((void*)pem_key_buffer, pem_key_buffer_len);
PEM_read_bio_RSAPublicKey(bufio, &rsa, 0, NULL);
The same approach is valid for an RSA private key (via PEM_read_bio_RSAPrivateKey
), but in that case you most certainly need to cater for the pass phrase. Check the man page for details.
Here's complete example, showing embedded key, and how to use C++11 unique pointers to manage OpenSSL resources.
Updated: following on from comments by spectras. No longer using specialisation
of default_delete<T>.
/* compile with:
c++ -Wall -pedantic -std=c++17 main.cc -lssl -lcrypto -o main
*/
#include <memory>
#include <iostream>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <assert.h>
#include <string.h>
/* Custom deletors for use with unique_ptr */
struct EVP_PKEY_deleter {
void operator()(EVP_PKEY* p) const {
if (p)
EVP_PKEY_free(p);
}
};
struct BIO_deleter {
void operator()(BIO* p) const {
if (p)
BIO_free(p);
}
};
/* Smart pointers wrapping OpenSSL resources */
using evp_key_ptr = std::unique_ptr<EVP_PKEY, EVP_PKEY_deleter>;
using bio_ptr = std::unique_ptr<BIO, BIO_deleter>;
/* Create key based on memory contents */
evp_key_ptr load_public_key(const char* buf, size_t len)
{
bio_ptr bp (BIO_new_mem_buf((void*) buf, len));
if (!bp)
throw std::runtime_error("BIO_new_mem_buf failed");
EVP_PKEY * kp = nullptr;
kp = PEM_read_bio_PUBKEY(bp.get(), &kp, nullptr, nullptr);
ERR_print_errors_fp(stderr);
return evp_key_ptr{kp};
}
int main()
{
const char * RSA_PUBLIC_KEY=R"(
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA80ZqDPPW5eOH6TWdLsEJ
8qf6hoMJfFZ3BL9Fz+YNGeBpF3zxKmm8UuRrBHHVZZB2Gs1MTo06IU3fqDfFsOyh
J6pHeJF3wyUlYZuYbGAyMlZZ/+M5TOvo92f7lt/A40QThCVf1vS5o+V8sFkgnz3N
C7+VvC4dYrv+fwnmnWGxPy1qfp3orB+81S4OPRiaoy+cQBZs10KCQaNBI/Upzl2R
3dMkWKM+6yQViKTHavT4DRRZ1MKp9995qOR3XfhhJdWuDl4moXcU3RcX4kluvS5q
b8oTnVyd2QB1GkUw6OKLWB/5jN1V1WzeYK447x2h4aPmJfsn5gCFJs6deq2RFQBR
SQIDAQAB
-----END PUBLIC KEY-----
)";
ERR_load_crypto_strings();
ERR_free_strings();
auto pubkey = load_public_key(RSA_PUBLIC_KEY, strlen(RSA_PUBLIC_KEY));
if (pubkey)
std::cout << "load_public_key success" << std::endl;
}
SquareRootOfTwentyThree's method not work for me. Here is my solution.
BIO* bio = BIO_new(BIO_s_mem());
int len = BIO_write(bio, pem_key_buffer, pem_key_buffer_len);
EVP_PKEY* evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
RSA* rsa = EVP_PKEY_get1_RSA(evp_key);
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