getting a segmentation fault with RSA_public_encrypt - c

Here's my code:
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <string.h>
int main (void)
{
char publicKey[] = "-----BEGIN RSA PUBLIC KEY-----\n"\
"MIIBCgKCAQEAqBa0jeqfHO8CFZuHyN5WgdTd3uThkU/I9lR+bb2R9khVU1tYhiyL\n"\
"Gfnm051K0039gCBAz9S7HHO2lqR/B1kiEGwBzg83N3tL2UzQXXbpxJz0b7vV8rXZ\n"\
"fB9j+FCAtD5znittXRjWrNqlEyJyxK+PuxNF3uPGWSjkYtRKv2f5HCXsfRJah40w\n"\
"5zU+OKZsZMrSSxweYN9Jwc++oMaSPCsGKog6NPbkbcTK8Akveof8v5rpG50I/zcQ\n"\
"9dCD69qJcmhm4ai4fAZFJlsFH2HmxV6DERFs3TNyzGlSQ1gd/XLER7U9nlrOUT87\n"\
"mXreUIXSkAFdCrlHXHOzj0eodfN8IfHjnQIDAQAB\n"\
"-----END RSA PUBLIC KEY-----\n";
char plaintext[] = "enp6";
// base64 decode plaintext
EVP_DecodeBlock(plaintext, plaintext, strlen(plaintext));
BIO* bo = BIO_new(BIO_s_mem());
BIO_write(bo, publicKey, strlen(publicKey));
EVP_PKEY* pkey = 0;
PEM_read_bio_PUBKEY(bo, NULL, NULL, NULL);
BIO_free(bo);
RSA* rsa = EVP_PKEY_get1_RSA(pkey);
char ciphertext[RSA_size(rsa)];
RSA_public_encrypt(strlen(plaintext), plaintext, ciphertext, rsa, RSA_NO_PADDING);
printf("%d\n", (int) strlen(ciphertext));
}
I'm trying to run it by doing gcc -x c test2.c -lcrypto && ./a.out. Any ideas as to what I'm doing wrong?

Your code contains several mistakes. The direct cause of the segfault is the fact that the variable pkey is never assigned any value after initializing it with 0. EVP_PKEY_get1_RSA(pkey) segfaults as a consequence. You probably intended to do
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bo, NULL, NULL, NULL);
However, with the PEM that you posted, that will not work. The header of the PEM indicates that this is an RSA key stored in "traditional" format. PEM_read_bio_RSAPublicKey is capable of reading such keys:
RSA *rsa = PEM_read_bio_RSAPublicKey(bo, NULL, NULL, NULL);
Then your choice of RSA_NO_PADDING when invoking RSA_public_encrypt is not right. In order to use that, the plaintext must be the exact same length as the key size. You could try using RSA_PKCS1_PADDING instead.
Finally, like mentioned in the comment section as well, using strlen on cipher text is incorrect, because it is not a 0-terminated string.
In general, you should check all return values for all OpenSSL functions invoked, to see when/if something went wrong.

Related

Writing PEM RSA private key in C

Hello i want my function to write a pem file from my RSA.
void write_privatekey(RSA *rsa, BIO *keybio)
{
EVP_PKEY *pkey;
BIO *bio_private;
pkey = PEM_read_bio_PrivateKey(keybio, &pkey, 0, 0);
bio_private = BIO_new_file("private_new.pem", "w+");
PEM_write_bio_PrivateKey(bio_private, pkey, NULL, NULL, 0, NULL, NULL);
}
but when i try to run this code it segfault
[1] 48767 segmentation fault ./corsair public.key
The OpenSSL APIs are not the most intuitive to use. However it should be a huge warning sign for you, that you passed a pointer to pkey to PEM_read_bio_PrivateKey and also assign its return value to it.
If you look at the reference manual the suggested stanza is
key = PEM_read_bio_PrivateKey(bp, NULL, pass_cb, …);
if( key == NULL ){
/* Error */
}
Your code snipped lacks a couple of things: It doesn't provide a pass phrase callback and it doesn't perform error checking. You absolutely must do both things.
After messing with the OpenSSL lib. and learned a way to dive into it documentation.
here it is the answer to write the PEM file from RSA object.
BIO *bio_private;
bio_private = BIO_new_file("private_new.pem", "w+");
PEM_write_bio_RSAPrivateKey(bio_private, rsa, 0, 0, 0, 0, 0);

How to generate a DSA key pair using OpenSSL libcrypto?

I have the following code trying to generate a DSA key pair.
OpenSSL_add_all_algorithms();
ctx=EVP_PKEY_CTX_new_id(EVP_PKEY_DSA,NULL); EVP_PKEY_keygen_init(ctx);
if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx,1024)<=0) ERR_print_errors_fp(stderr);
and I get the following error
3073906944:error:06089094:digital envelope
routines:EVP_PKEY_CTX_ctrl:invalid operation:pmeth_lib.c:398:
Any clue on what I am doing wrong? thanks
You need two contexts; one for the params, and one for the actual keygen. You should do the following two sets of operations :
Parameter Generation
Create a param generator using EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL)
Set the bits in the param generator context using EVP_PKEY_CTX_set_dsa_paramgen_bits; not the keygen context (which, if you'r'e doing this right, doesn't even exist yet).
Initialize the param generator using EVP_PKEY_paramgen_init
Finally, generate the parameters using EVP_PKEY_paramgen. The result is a EVP_PKEY object (I'll call it pkey_params) that contains the input parameters for the upcoming key generation
Once the above is done, then you move on to the actual key generation, which is considerably simpler:
Key Generation
Create a new context using EVP_PKEY_CTX_new(pkey_params, NULL) Note the pkey_params is from the prior series of steps.
Initialize the generator context using EVP_PKEY_keygen_init
Generate the actual key using EVP_PKEY_keygen
Once done, all resources except the final pkey from above should be properly destroyed. Free the final key once done using it. That's it.
Example
This has no error checking whatsoever, but the order of operations is what is important here. So pay attention to that.
#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/dsa.h>
#include <openssl/pem.h>
// required for any BIO standard stream IO.
#include <openssl/applink.c>
int main()
{
OPENSSL_init();
OpenSSL_add_all_algorithms();
// build parameters first
EVP_PKEY_CTX *ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
EVP_PKEY_paramgen_init(ctx_params);
EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx_params, 1024);
EVP_PKEY* pkey_params = NULL;
EVP_PKEY_paramgen(ctx_params, &pkey_params);
// using parameters, build DSA keypair
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey_params, NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY* pkey = NULL;
EVP_PKEY_keygen(ctx, &pkey);
// cleanup everything but the final key
EVP_PKEY_free(pkey_params);
EVP_PKEY_CTX_free(ctx_params);
EVP_PKEY_CTX_free(ctx);
// TODO: whatever you want with the generator pkey. in this
// example we're just dumping the full unencrypted key to
// stdout.
DSA* dsa = EVP_PKEY_get1_DSA(pkey);
BIO* bio = BIO_new_fp(stdout, BIO_NOCLOSE);
PEM_write_bio_DSAPrivateKey(bio, dsa, NULL, NULL, 0, NULL, NULL);
BIO_flush(bio);
DSA_free(dsa);
EVP_PKEY_free(pkey);
return 0;
}
Output (varies, obviously)
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQDJ+NoL8SZeTcqVA83WI7CCO6INYLw18DiALLMewPqXEPm99mof
RX2693WJfpbWIjuHi/KXzH6vQ/0sQU+2z1CqgWhudVhQTofGNcsPrUbPpShTDMcP
OoTx9dRb8rXWbxg7dfhGZ9z2pEhzRtPWpI2y81VxYhGXzVSC3zqW6+ec2QIVALaE
fynSMqc56gPqDPZfRz1rlq3dAoGAL+vbbYu+gSy8zGqoLykqhG+Vl4/Eh/zQIWoB
t64bfh7GU6o0wvgTQgcdGZK3/laa9Msa6J3iEGZcP3dd9x4fTQ5vzxDGIYikcC8I
L8s2JbNi1Jxbr5dw3/sOKsdHIt95rFZ03+gMzaV+9pc8LpATnaXMtp5mmH+lRgsJ
SIEdLqcCgYAVGpwZHaFUnttqQAf3/ohMtqIQG+RBp/yUf2EA7rcoHpA7bCBADApx
mG5hH/F4dKjCSciKdHq4Ibf60ctAJNL2sobPKNArTMo/GNuzE+J79Wj6s/b7zwt7
AF+27H9PAiXB08ftMmCSesXkX7v926EHRxDgSlVAgCPSfkXKNQn1XwIVALF2MF2N
GRdMtFUxZFnIk2GnqC1R
-----END DSA PRIVATE KEY-----

Segmentation fault with generating an RSA and saving in ASN.1/DER?

#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#define RSA_LEN 2048
#define RSA_FACTOR 65537
int genRSA2048(unsigned char **pub,unsigned int *pub_l,unsigned char **priv,unsigned int *priv_l){
RSA *pRSA = NULL;
pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);
if (pRSA){
pub_l = malloc(sizeof(pub_l));
*pub_l = i2d_RSAPublicKey(pRSA,pub);
priv_l = malloc(sizeof(priv_l));
*priv_l = i2d_RSAPrivateKey(pRSA,priv);
return 0;
} else {
return 1;
}
}
int main(){
unsigned char *pub = NULL;
unsigned int publ;
unsigned char *priv = NULL;
unsigned int privl;
genRSA2048(&pub,&publ,&priv,&privl);
RSA *privrsa = NULL;
d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);
RSA *pubrsa = NULL;
d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);
unsigned char * data ="01234567890123456789012345678912";
unsigned char encrypted[256];
unsigned char decrypted[32];
int len = RSA_private_encrypt(32,data,encrypted,privrsa,RSA_PKCS1_PADDING);
RSA_public_decrypt(len,encrypted,decrypted,pubrsa,RSA_PKCS1_PADDING);
}
I've tried to find the bug by checking with gdb but as being fairly new to C I haven't find any clue to tell me what is happening but I believe it's an allocation problem, however according to the d2i_RSAPrivateKey and similar, they're supposed to allocate the space by itself.
Any help would be greatly appreciated.
compiled as cc foo.c -lcrypto
This is the follow up of this question:
Generate RSA public/private key with OpenSSL?
As I reference I used #WhozCraig example in the comments, which can be found here, even when it's quite different, it was a lot of help.
http://coliru.stacked-crooked.com/a/ae64a70076436165
pub_l = malloc(sizeof(pub_l)); is simply not needed. Nor is priv_l = malloc(sizeof(priv_l));. Remove them both from your function.
You should be populating your out-parameters; instead you're throwing out the caller's provided addresses to populate and (a) populating your own, then (b) leaking the memory you just allocated.
The result is the caller's privl and publ are untouched and thus the decoding back to RSA is dysfunctional, as both values are indeterminate.
pRSA = RSA_generate_key(RSA_LEN,RSA_FACTOR,NULL,NULL);
I think this is wrong. I know you are supposed to use RSA_generate_key_ex, and I think it needs a BIGNUM, not an integer. You should have gotten a warning. See RSA_generate_key(3) for details.
Your code should look something like:
BIGNUM* exp = BN_new();
ASSERT(exp != NULL);
int rc = BN_set_word(exp, RSA_F4);
ASSERT(rc == 1);
RSA* rsa = RSA_new();
ASSERT(rsa != NULL);
rc = RSA_generate_key_ex(rsa, 2048, exp, NULL);
ASSERT(rc == 1);
Be sure to call BN_free on the BIGNUM, and RSA_free on the RSA pointer.
RSA *privrsa = NULL;
d2i_RSAPrivateKey(&privrsa,(const unsigned char **)&priv,privl);
RSA *pubrsa = NULL;
d2i_RSAPublicKey(&pubrsa,(const unsigned char **)&pub,publ);
For this, it looks like you are trying to separate the public key and private key. For that, use RSAPublicKey_dup and RSAPrivateKey_dup. See Separating public and private keys from RSA keypair variable.
Its not clear to me what you are trying to do with the following. You should state what you are trying to do...
pub_l = malloc(sizeof(pub_l));
*pub_l = i2d_RSAPublicKey(pRSA,pub);
priv_l = malloc(sizeof(priv_l));
*priv_l = i2d_RSAPrivateKey(pRSA,priv);
I'm just guessing, but I'm going to say its all wrong. sizeof(priv_l) is the size of a pointer, so its 4 or 8 bytes. You're also overwriting the pointer passed in by the caller...
Also see OpenSSL's rsautl cannot load public key created with PEM_write_RSAPublicKey. It talks about saving the keys with SubjectPublicKeyInfo and PrivateKeyInfo in both ASN.1/DER and PEM formats.
By writing the {Public|Private}KeyInfo, the OID gets written to the key. That's important for interop. You also use the RSA* (and even an EVP_PKEY*), and not byte arrays.

Reading PEM-formatted RSA keyfile with the OpenSSL C API

I am trying to read in an AES-128-CBC encrypted PEM key file generated using Ruby with the OpenSSL API. The code that generated the PEM key is the following:
OpenSSL::PKey::RSA.new(2048).to_pem(OpenSSL::Cipher::AES.new('128-CBC'), "password")
Here's the code that reads the PEM file:
RSA *rsa;
BIO *pem = BIO_new(BIO_s_mem());
BIO_puts(pem, "-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-128-CBC,BB13D39833DD6ED1FF9843644E7981EE\n\n
"Eugt8JZNKQKErsabWkwfm3wQhU/Tmp9T0QaP5HM8VIWpZwKlDmRlSUDptADU6RPD\n"
"5VtG3DPieXcf+6deyARImid9sBBmQ9mK2omkNRcTMemqTOhAuaKBu78TMt9G4YSf\n"
"RjoXWSqu3jMwrlcGkpn7bIum8wImITRZ3p28oSzk9aDUNBrIU/2Si8DM4RYIZ/fK\n"
"Uvvgdok9dgcd0SjvucivX2HaGeg/IUz23q1jg9inDpimZvFJD1FJfGEUWDgyfJfa\n"
"M8JIxTKbWOPEopONDkT7u4dC5VcSjK29MVbfd7iCKFPMh5UN+c96rPxTng/OWyW5\n"
"0tvzHyyyvAG9p0Hx5Lr4pDbv21GHyu43sA6wbs9jWyqO3AB7CaoEEQhumwfLsdjj\n"
"YGrX6bWThpYv/XNBDmmvltHlKFfe01NCybivOb4KwBnvi45x21PBqaZCKDTFdEkL\n"
"iwDMTiG2iTxSUvPFLy30VFozE+pGyMcGDUyZDVqjsaqI/MRj8khnn5nyubXc27G3\n"
"8Kbsnlix2SW2M0VDxqiy9dyjcxXrkFRSnOFYVs1PFlgjFVTG4Mwh6CZxKw8mFVbi\n"
"EmLvUYwzoDZ1ve4VXSPp/vrKEh33JuHhM0vJOpqI6wqw0QR0I2o6etM1ZRJClPcw\n"
"VIcgcvwenEgLOkoHDqOr0IZQAtYWvAuqq822wKt258hc6z8+ALQf5iMroqk7ADd4\n"
"FlRLz4XTwqlg7pPtTde/emI1DT8dQWzq++QI0lr0CS/N1GXJKqTQDvauXLIiI3Qy\n"
"KfFYFpV9jyYfRfTjNtisI/edPtp98auK0mb9o/wS/hruFI9behgv63iW1IwAOXCW\n"
"ZlkWgobUH13gS864rL+AcrAXreo2j4dDQouTeRaJUEG0HoYTP65Zun/VsCi2aSOH\n"
"JwSnnmHz9OxvcGY80WJDN3kqOCBRIJoDKBv6jcOxGVCsVK+WSdGZ7cfb8lwp7aA8\n"
"8ND1bwL9FYkwkeIsoakj91iinqv4o3+3PUPgCU5oe68WYvAFjuU+criyf+EhmXJV\n"
"JQ1vFFZPrGzgntJz19uXXh1h2iwQPggRouJm2RozYwvv1nz4eQ40Y3eT1F9UOYJU\n"
"CKEhOtI2NpLeVOayqo8g9wO2oC+CQVhZhdYBE5o7pM7akFnYLvRg9s1UsWdcvT0G\n"
"IpFmejLSRJ/F954aQMHTUc6vBOJZH/VNC5Qt+ulFXl634Sr9wQQK2qlqSJyA04TR\n"
"1ixbCNOX71esvpFImsrlsO5oTA22T3h2GyJPUM10XhqGtDXtsTnal6smLna9U9B3\n"
"gTVxFWWukQOF5Lm8ZFQipo2loHWjkozTBc4REPYP44SoXJXstv7k4pt1cK7x6/2H\n"
"ElspXzjveqMhcrveWv1KaA2OGd+hGfUiNsCoIdapJjLz1Bd/+oIQ/ZWQeo0nRowE\n"
"R/HlbbED3V+fRIdJpgydFEAw6gK5E9sYJcgF7uf/n2NabFxxEZL3g6MJQ64Dtusg\n"
"DEH/MpvIYDSX4Navh1gTwCtOeG1CzW3diYaqbZK+UZCBLFU7j27YvVPSd6F2+Wud\n"
"WnAqU3S5BCPqk5OD3wqZv+sEcqJgGPGy1Gv0tl8ARJomdKAru03KsRn2eIWqR5/C\n"
"-----END RSA PRIVATE KEY-----\n");
// Retrieve RSA key from PEM file.
rsa = PEM_read_bio_RSAPrivateKey(pem, NULL, pem_password_callback, "password");
And here's a dummy password callback (not sure about this function's purpose, but I think it may return the length of the password):
int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
{
return 8;
}
Currently, the rsa = ... part does not throw an error, but doesn't return a well-formed result either.
And here's a dummy password callback (not sure about this function's
purpose, but I think it may return the length of the password):
int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
{
return 8;
}
No, its not a dummy. In your example, you just returned a buffer with 8 junk characters (whatever happened to be in buf).
The password callback is where you programmatically plug in your password. You are supplied with a buff of max_len, and you need to copy the password into the buffer and return the number of bytes copied.
int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
const char* PASSWD = "password";
int len = strlen(PASSWD);
if(len > max_len)
return 0;
memcpy(buf, PASSWD, len);
return len;
}
The flag is a read/write flag to denote if you are reading a key or writing a key. In practice, I have never used it.
You will use it similar to:
FILE* file = ...;
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, NULL);
Unlike the write routine (which needs an EVP_* cipher), the read routine knows what you used to encrypt the key with because its encoded in the private key.
In my systems, I actually use the context for a label to ensure the same passwords arrive at different derived keys:
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, "Some Context");
Then, in my password callback:
int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
// "Some Context" in the example above
char* label = (char*)ctx;
// Hash password and label
// ...
// Copy hash to buffer, return length
...
}

Reading Public/Private Key from Memory with OpenSSL

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.
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);
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;
}

Resources