how to convert a plain text public key to der in openssl - c++

how to convert the the following pubkey to der encoded public key?
thanks, I saw i2d_PUBKEY maybe for it, but I don't know how to.
#include <openssl/evp.h>
#include <openssl/x509.h>
uint8_t *pubkey = NULL;
size_t len = 0;
get_pubkey_function(&pubkey, &len);
printf(pubkey);
/* this step will print out
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+GmnZ1UZqKfa81Yh0CG6huQPhYON
Q0W7AE4whuX+oUOg+BewYSOLUwj5zfwRB3i7T07HoltPfAOYeHI57Oe7jA==
-----END PUBLIC KEY-----
*/

EVP_PKEY *public_key = NULL;
BIO *bio = NULL;
bio = BIO_new_mem_buf((void *)pubkey, -1);
PEM_read_bio_PUBKEY(bio, &public_key, NULL, NULL);
EXPECT_TRUE(public_key);
am I right?

Related

Loading certificates from string buffers into chain for client verification using OpenSSL

I am trying to use SSL client verification to connect to a remote AWS IoT endpoint. I have three files:
- CA Root Certificate File
- Certificate File
- Private Key
The connection to the endpoint is successful if I use SSL_CTX_load_verify_locations, SSL_CTX_use_certificate_chain_file and SSL_CTX_use_PrivateKey_file.
if (!SSL_CTX_load_verify_locations(p_ssl_context_, root_ca_location_.c_str(), NULL)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Root CA Loading error");
return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR;
}
// TODO: streamline error codes for TLS
if (0 < device_cert_location_.length() && 0 < device_private_key_location_.length()) {
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device crt : %s", device_cert_location_.c_str());
if (!SSL_CTX_use_certificate_chain_file(p_ssl_context_, device_cert_location_.c_str())) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Certificate Loading error");
return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR;
}
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device privkey : %s", device_private_key_location_.c_str());
if (1 != SSL_CTX_use_PrivateKey_file(p_ssl_context_,
device_private_key_location_.c_str(),
SSL_FILETYPE_PEM)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Private Key Loading error");
return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR;
}
}
certificates_read_flag_ = true;
However, the call doesn't work if I construct the chain manually by adding the certificates using string buffers. The error returned is "An unknown occurred while waiting for the TLS handshake to complete.".
X509_STORE* store = SSL_CTX_get_cert_store(p_ssl_context_);
X509 *rootCACertificate, *deviceCertificate;
RSA *privateKey;
BIO *bio;
std::string rootCACertificateBuffer;
std::string deviceCertificateBuffer;
std::string privateKeyBuffer;
rootCACertificateBuffer =
"-----BEGIN CERTIFICATE-----\n"
"-----END CERTIFICATE-----\n";
deviceCertificateBuffer =
"-----BEGIN CERTIFICATE-----\n"
"-----END CERTIFICATE-----\n";
privateKeyBuffer =
"-----BEGIN RSA PRIVATE KEY-----\n"
"-----END RSA PRIVATE KEY-----\n";
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, rootCACertificateBuffer.c_str());
rootCACertificate = PEM_read_bio_X509(bio, NULL, 0, NULL);
X509_STORE_add_cert(store, rootCACertificate);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, deviceCertificateBuffer.c_str());
deviceCertificate = PEM_read_bio_X509(bio, NULL, 0, NULL);
X509_STORE_add_cert(store, deviceCertificate);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, privateKeyBuffer.c_str());
privateKey = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL);
SSL_CTX_use_RSAPrivateKey(p_ssl_context_, privateKey);
BIO_free(bio);
SSL_CTX_build_cert_chain(p_ssl_context_,SSL_BUILD_CHAIN_FLAG_CHECK );
certificates_read_flag_ = true;

How to perform Public Key Encryption with RSA using C++

I am trying to implement asymmetrc encryption into a project. My end goal is to implement EVP Asymmetric Encryption and Decryption of an Envelope but for now I am going to stick with the basics. I am rather new to openssl so please forgive me if there is an obvious answer to this question.
Currently I am following this tutorial here: Simple Public Key Encryption with RSA and OpenSSL
I plan to transmit the RSA public key over a network to a seperate client which will encrypt a message with the generated public key. The encrypted message will then be sent back to the server for decryption.
I am having trouble with encrypting only using the public key instead of using the keypair. For obvious reasons, I don't want to transmit the keypair over the network.
Here is the code that I have so far:
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include <string.h>
#define KEY_LENGTH 2048
#define PUB_EXP 3
#define PRINT_KEYS
#define WRITE_TO_FILE
int main(void) {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key
char *pub_key; // Public key
char msg[KEY_LENGTH/8]; // Message to encrypt
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
char *err; // Buffer for any error messages
// Generate key pair
printf("Generating RSA (%d bits) keypair...", KEY_LENGTH);
fflush(stdout);
RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);
// To get the C-string PEM form:
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
//SEND KEY TO CLIENT HERE
//FAKE CLIENT RECIEVE
RSA *keypair2 = NULL;
PEM_read_bio_RSAPublicKey( pub, &keypair2, NULL, NULL);
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, KEY_LENGTH-1, stdin);
msg[strlen(msg)-1] = '\0';
// Encrypt the message using public key only
encrypt = malloc(RSA_size(keypair2));
int encrypt_len;
err = malloc(130);
if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt,
keypair2, RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
goto free_stuff;
}
#ifdef WRITE_TO_FILE
// Write the encrypted message to a file
FILE *out = fopen("out.bin", "w");
fwrite(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
printf("Encrypted message written to file.\n");
free(encrypt);
encrypt = NULL;
// Read it back
printf("Reading back encrypted message and attempting decryption...\n");
encrypt = malloc(RSA_size(keypair));
out = fopen("out.bin", "r");
fread(encrypt, sizeof(*encrypt), RSA_size(keypair), out);
fclose(out);
#endif
//SEND MESSAGE BACK TO CLIENT FOR DECRYPT
// Decrypt it
decrypt = malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt,
keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
goto free_stuff;
}
printf("Decrypted message: %s\n", decrypt);
free_stuff:
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
free(encrypt);
free(decrypt);
free(err);
return 0;
}
How could I achieve encrypting data only using the public key rather than the whole keypair?
Thanks

OpenSSL RSA Public/Private Encryption/Decryption with pkcs12 file

I am porting a service from C# to C++ - which involves RSA encryption. Using OpenSSL 1.0.2. (I wrote my first line of C++ two weeks ago - so please bear with me.)
I am trying to encrypt/decrypt data - using RSA. Encryption uses a public key which is retrieved by invoking a server via HTTPS (The public key of the SSL certificate is used).
Decryption happens on the server - which loads the private key from a PFX file (PKCS12).
I am having problems with decryption - error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error
What am I doing wrong?
Encryption - getting public key from server (HTTPS)
int MyUtil::EncryptWithPublicKeyRetrievedFromServer(int length, unsigned char* bytesToEncrypt, unsigned char* output){
//Get Certificate from server
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
boost::asio::io_service io_service;
ctx.set_default_verify_paths();
client myClient = client(io_service, ctx);
auto cert = myClient.GetX509Certificate("www.myHttpsDomain.com");
//Get public key
auto key = X509_get_pubkey(cert);
auto rsa = EVP_PKEY_get1_RSA(key);
//Encrypt
return RSA_public_encrypt(length, bytesToEncrypt, output, rsa, RSA_PKCS1_PADDING);
}
Decryption - using private key
int MyUtil::DecryptWithPrivateKey(int length, unsigned char* bytesToDecrypt, unsigned char *output){
auto filePath = "C:\\myCertificateWithPrivateAndPublicKey.pfx";
auto pass = "MySecretPassword";
FILE *fp;
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
#pragma warning (disable : 4996) //MS complains about fopen
if (!(fp = fopen(filePath, "rb"))) {
fprintf(stderr, "Error opening file %s\n", filePath);
exit(1);
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit(1);
}
//Parse PKCS12 (PFX) file in order to get private key
if (!PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit(1);
}
PKCS12_free(p12);
//Decrypt
auto rsa = EVP_PKEY_get1_RSA(pkey);
int sizeOfDecryptedData;
if (sizeOfDecryptedData = RSA_private_decrypt(length, bytesToDecrypt, output, rsa, RSA_PKCS1_PADDING) == -1)
{
auto err = new char;
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
//--> error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error
delete err;
}
sk_X509_pop_free(ca, X509_free);
X509_free(cert);
EVP_PKEY_free(pkey);
fclose(fp);
return sizeOfDecryptedData;
}
I also tried loading the private key through the PEM format and then decrypt
int MyUtil::DecryptWithPrivateKey(int length, unsigned char* bytesToDecrypt, unsigned char *output){
char *private_key_file_name = "C:\\privatekey.cer";
#pragma warning (disable : 4996) //MS complains about fopen
FILE *fp = fopen(private_key_file_name, "r");
RSA *rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if (sizeOfDecryptedData = RSA_private_decrypt(length, bytesToDecrypt, output, rsa, RSA_PKCS1_PADDING) == -1)
{
auto err = new char;
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
//--> error:0407109F:rsa routines:RSA_padding_check_PKCS1_type_2:pkcs decoding error
delete err;
}
return decryptedBytes;
}

BIO to EVP_PKEY (Public and Private)

I am stuck on how to convert a BIO* to its EVP_PKEY counterparts so that i can later use it in encryption. Currently my keygen routine looks like this:
bool SecureCrypto::GenerateRSAKeys()
{
BIGNUM* BigNum = nullptr;
BIGNUM* BigNum2 = nullptr;
BigNum = BN_new();
if (BN_set_word(BigNum, RSA_F4) <= 0)
return false;
BigNum2 = BN_new();
if (BN_set_word(BigNum2, RSA_F4) <= 0)
return false;
m_ServerKeyPair = RSA_new();
m_ClientKeyPair = RSA_new();
RSA_generate_key_ex(m_ServerKeyPair,RSA_KeyLen, BigNum, NULL);
RSA_generate_key_ex(m_ClientKeyPair,RSA_KeyLen, BigNum2, NULL);
PEM_write_bio_RSAPublicKey(m_ServerPublicKeyBIO, m_ServerKeyPair);
PEM_write_bio_RSAPrivateKey(m_ServerPrivateKeyBIO,
m_ServerKeyPair,EVP_aes_256_cbc(), (unsigned char*)RSA_PrivKeyPassPhrase.c_str(),
RSA_PrivKeyPassPhrase.size(), NULL, NULL);
PEM_write_bio_RSAPublicKey(m_ClientPublicBIO, m_ClientKeyPair);
PEM_write_bio_RSAPrivateKey(m_ClientPrivateBIO, m_ClientKeyPair, EVP_aes_256_cbc(),
(unsigned char*)RSA_PrivKeyPassPhrase.c_str(), RSA_PrivKeyPassPhrase.size(), NULL,
NULL);
BN_free(BigNum);
BN_free(BigNum2);
return true;
}
Later on i need to convert m_ServerPrivateKeyBIO into a EVP_PKEY for use with EVP_SealInit.
I only know of PEM_read_bio_PrivateKey(), but everytime i call it i get a return value of 0 (fail).I call it as such:
PEM_read_bio_PrivateKey(m_ServerPrivateKeyBIO, NULL, NULL, "Enc Key");
I plan on the server doing encryption with its private key then sending data to client and client decrypting it with the servers public key, i would appreciate any help here, as the OpenSSL docs don't help at all.
P.S i have client and server keys being generated for a test, obviously this would not happen in final code.

How do I get the RSA* object from a char array that contains the public key in OpenSSL?

Im trying to encrypt and decrypt messages while storing the private and public keys on char vectors. I have tried d2i_PublicKey(...) and using EVP_PKEY objects in EVP_set1_RSA(...). I also do not know what are all the parameters in EVP_set1_RSA(...). Please help. Here is my code:
#include <stdio.h>
//RSA
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <arpa/inet.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#define RSA_KEY_LENGTH 2048
#define PUB_EXP 3
#define PRINT_KEYS
//RSA
int main()
{
printf("\ngenerating keys...\n");
RSA *keypair = RSA_generate_key(RSA_KEY_LENGTH, PUB_EXP, NULL, NULL);
// ---------
printf("Converting Keys to char array..\n");
char *pri_key = NULL; // Private key
char *pub_key = NULL; // Public key
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
pri_key = (char*)malloc(pri_len + 1);
pub_key = (char*)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
// ---------
char msg[RSA_KEY_LENGTH/8] = "HOLA, ESPERO QUE ME ENCRIPTES";
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
printf("encrypting: %s\n", msg);
/*
* Here I want to obtain an RSA *PublicKey to use it for the encryption
*/
int encrypt_len;
err = (char*)malloc(130);
printf("++++\n");
if((encrypt_len = RSA_public_encrypt(strlen(msg), (unsigned char*)msg, (unsigned char*)encrypt, PublicKey, RSA_PKCS1_OAEP_PADDING)) == -1) {
printf("err++++\n");
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
return 0;
}
I've found a solution to this issue among other Stack-Overflow posts and namely here :Reading Public/Private Key from Memory with OpenSSL
The answer you waere looking for is answered by #SquareRootOfTwentyThree is his last line of code,
After extracting the Public key into a BIO variable called pub:
PEM_write_bio_RSAPublicKey(pub, keypair);
create a RSA variable and put pub inside it:
RSA *keypair2 = NULL;
PEM_read_bio_RSAPublicKey( pub, &keypair2, NULL, NULL);
After you've done this you can successfully encrypt the message as usual, using keypair2:
Encryption:
encrypt = (char*)malloc(RSA_size(keypair));
int encrypt_len;
err = (char*)malloc(130);
if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt, keypair2 ,RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
you can then decrypt it as usual, using the original keypair, without having to use it at your first encryption
Decryption:
decrypt = (char*)malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt, keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
}
This might help if you want to transfer the "pub" variable over a network, use it to encrypt a message, then send the encrypted data back to the original machine to get it decrypted.
If you really want to use char variables, as you said in your question, you can of course copy the memory as raw to a char variable (from the BIO one) using memcpy, but don't forget to add the "\0" at the end, here, this post should help: Separating public and private keys from RSA keypair variable