OpenSSL 3.x.x
To serialize the public key:
// We assume the public and private keys have been already generated.
// EVP_PKEY* keyPair...
// Get the serialized public key length.
size_t serializedPublicKeyLen = 0;
if (EVP_PKEY_get_octet_string_param(keyPair, OSSL_PKEY_PARAM_PUB_KEY,
NULL, 0, &serializedPublicKeyLen) != 1) {
return;
}
// Allocate memory for the serialized public key.
unsigned char* serializedPublicKey = (unsigned char*)OPENSSL_malloc(serializedPublicKeyLen);
if (serializedPublicKey == NULL) {
return;
}
// Get the serialized public key.
if (EVP_PKEY_get_octet_string_param(keyPair, OSSL_PKEY_PARAM_PUB_KEY,
serializedPublicKey, serializedPublicKeyLen, &serializedPublicKeyLen) != 1) {
return;
}
// Deallocate the memory when you finish using the serialized public key.
OPENSSL_free(serializedPublicKey);
To deserialize the public key:
// A parameter build for the public key.
OSSL_PARAM_BLD* paramBuild = OSSL_PARAM_BLD_new();
if (paramBuild == NULL) {
return;
}
// This is just an example. Set the curve
// you used to generate the public and private keys.
const char curveName[] = "secp384r1";
// Set the curve name to the parameter build.
if (OSSL_PARAM_BLD_push_utf8_string(paramBuild,
OSSL_PKEY_PARAM_GROUP_NAME, curveName, 0) != 1) {
OSSL_PARAM_BLD_free(paramBuild);
return;
}
// Set the serialized public key.
if (OSSL_PARAM_BLD_push_octet_string(paramBuild, OSSL_PKEY_PARAM_PUB_KEY,
serializedPublicKey, serializedPublicKeyLen) != 1) {
OSSL_PARAM_BLD_free(paramBuild);
return;
}
// Convert the OSSL_PARAM_BLD to an OSSL_PARAM.
OSSL_PARAM* params = OSSL_PARAM_BLD_to_param(paramBuild);
if (params == NULL) {
OSSL_PARAM_BLD_free(paramBuild);
return;
}
// Create a EVP_PKEY context.
EVP_PKEY_CTX* publicKeyCtx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
if (publicKeyCtx == NULL) {
OSSL_PARAM_BLD_free(paramBuild);
OSSL_PARAM_free(params);
return;
}
// Initialize the EVP_PKEY context.
if (EVP_PKEY_fromdata_init(publicKeyCtx) <= 0) {
OSSL_PARAM_BLD_free(paramBuild);
OSSL_PARAM_free(params);
EVP_PKEY_CTX_free(publicKeyCtx);
return;
}
// Create the peer public key object.
EVP_PKEY* publicKey = NULL;
if (EVP_PKEY_fromdata(publicKeyCtx, &publicKey,
EVP_PKEY_PUBLIC_KEY, params) <= 0) {
OSSL_PARAM_BLD_free(paramBuild);
OSSL_PARAM_free(params);
EVP_PKEY_CTX_free(publicKeyCtx);
return;
}
// Free auxiliary things...
OSSL_PARAM_BLD_free(paramBuild);
OSSL_PARAM_free(params);
EVP_PKEY_CTX_free(publicKeyCtx);
// Now you can use publicKey for EVP_PKEY_derive_set_peer.
// Call EVP_PKEY_free when you finish using it.
To serialize the private key, you get BIGNUM instead:
BIGNUM* privateKey = NULL;
EVP_PKEY_get_bn_param(keyPair, OSSL_PKEY_PARAM_PRIV_KEY, &privateKey);
Then, you use one of the BIGNUM serialization function: https://www.openssl.org/docs/man3.0/man3/BN_bn2bin.html
To deserialize the private key, you use one of the BIGNUM deserialization function from the link above, then push it to the parameter build via OSSL_PARAM_BLD_push_BN with OSSL_PKEY_PARAM_PRIV_KEY.