Could anyone share a simple example to generate key pairs using openssl 3.0 c++ library? The official site is no good, a lot of functions are deprecated but still listed there, and gpt generated code failed at EVP_PKEY_copy_parameters
. This is the code I got from gpt, which doesn't work.
#include <iostream>
#include <memory>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <string>
#include <vector>
// Custom deleter for EVP_PKEY
struct EVP_PKEY_Deleter {
void operator()(EVP_PKEY *pkey) const { EVP_PKEY_free(pkey); }
};
// Type alias for unique_ptr with EVP_PKEY and custom deleter
using Key = std::unique_ptr<EVP_PKEY, EVP_PKEY_Deleter>;
std::pair<Key, Key> generate_rsa_keys() {
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
if (!ctx) {
throw std::runtime_error("Failed to create context");
}
EVP_PKEY *pkey_raw = EVP_RSA_gen(2048);
if (!pkey_raw) {
EVP_PKEY_CTX_free(ctx);
throw std::runtime_error("Key generation failed");
}
EVP_PKEY *public_key_raw = EVP_PKEY_new();
if (!public_key_raw) {
EVP_PKEY_free(pkey_raw);
EVP_PKEY_CTX_free(ctx);
throw std::runtime_error("Failed to create public key");
}
if (EVP_PKEY_copy_parameters(public_key_raw, pkey_raw) <= 0) {
EVP_PKEY_free(pkey_raw);
EVP_PKEY_free(public_key_raw);
EVP_PKEY_CTX_free(ctx);
throw std::runtime_error("Failed to copy parameters");
}
Key pkey(pkey_raw);
Key public_key(public_key_raw);
return {std::move(pkey), std::move(public_key)};
}
int main() {
auto [pkey, public_key] = generate_rsa_keys();
}
edit: For any rookie still looking, here's another alternative beside accepted answer. https://github.com/leventkaragol/libcpp-crypto
OpenSSL's document surely didn't help...
It's a bit tricky to find everything in the documentation but in the end new API requires slightly less coding than deprecated one. You can e.g. follow these steps:
EVP_RSA_gen(unsigned int bits);
to generate RSA key pairEVP_PKEY_print_public
(or any other version: private, params) to print public key into BIO
I/O structureBIO_read
to copy the human-readable information into some char*
bufferComplete example (without errors checks):
constexpr size_t kBits = 1024;
int main() {
EVP_PKEY* key = EVP_RSA_gen(kBits);
BIO* bio = BIO_new(BIO_s_mem());
EVP_PKEY_print_public(bio, key, 4, nullptr);
// I hardcoded 2056, because I'm lazy, but probably there is some way to query the number of available bytes from BIO
std::string keyStr(2056, 0);
std::cout << "num bytes read: " << BIO_read(bio, keyStr.data(), keyStr.size()) << std::endl;
std::cout << "keyStr: " << keyStr << std::endl;
BIO_free_all(bio);
EVP_PKEY_free(key);
}