Reading public / private key from memory using OpenSSL

I use Public / Private Keys in my project to encrypt / decrypt some data.

I host the public key ("public.pem") on the server.

"public.pem" is as follows:

-----BEGIN PUBLIC KEY-----
.....
.....
-----END PUBLIC KEY-----

I wrote a client side that downloads this public key and saves it to disk, and then calls OpenSSL PEM_read_RSA_PUBKEY () with a file descriptor for this file. This operation works fine, and the result is an RSA object ready for encryption.

I would like to avoid writing the public key to the disk every time (since I already have a buffer in memory).

How can I perform the same operation without saving the buffer to disk? I noticed a function called: PEM_read_bio_RSAPublicKey (), but I'm not sure about its use in the BIO structure. Am I on the right track?

So the real question is: how can I read the public / private key for the RSA object directly from memory, and not from the file descriptor.

+5
source share
3 answers

You are on the right track. You must wrap the PEM key already in memory using the BIO buffer through 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 applies to the RSA private key (via PEM_read_bio_RSAPrivateKey), but in this case, you certainly need to serve the missing phrase. See the man page for more information .

+14
source

SquareRootOfTwentyThree . .

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);
+3

Using C ++ 11 to manage OpenSSL resources:

#include <string>
#include <iostream>
#include <memory>

#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#include <assert.h>
#include <string.h>

namespace std
{

/* Custom deletors for OpenSSL resources */

template<>
struct default_delete <EVP_PKEY>{
  void operator()(EVP_PKEY* p) {
    if (p)
      EVP_PKEY_free(p);
  }
};

template<>
struct default_delete <BIO>{
  void operator()(BIO* p) {
    if (p)
      BIO_free(p);
  }
};

}

/* Smart pointers wrapping OpenSSL resources */
using evp_key_ptr = std::unique_ptr<EVP_PKEY>;
using bio_ptr = std::unique_ptr<BIO>;

/* Capture OpenSSL error code */
void throw_on_error(const char* func) {
  unsigned long e = ERR_get_error();
  char detail[256] = {0};
  ERR_error_string_n(e, detail, sizeof(detail)-1); // dumps hex code also
  char buf[512] = {0};
  assert(sizeof(buf) > sizeof(detail) + strlen(func) + 20);
  snprintf(buf, sizeof(buf)-1, "%s failed, %s", func, &detail[0]);
  throw std::runtime_error(buf);
}

/* Create key based on memory contents */
std::unique_ptr<EVP_PKEY> load_public_key(const char* buf, size_t len)
{
  std::unique_ptr<BIO> 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);
  if (!kp)
    throw_on_error("PEM_read_bio_PUBKEY");

  return std::unique_ptr<EVP_PKEY>{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();

  try {
    auto pubkey = load_public_key(RSA_PUBLIC_KEY, strlen(RSA_PUBLIC_KEY));
    std::cout << "load_public_key success" << std::endl;
  } catch (const std::exception & e) {
    std::cout << "load_public_key failed, " << e.what() << std::endl;
  }
}
0
source

All Articles