RSA encryption with OpenSSL using char array public key - c++

I have a public key stored in a variable like so:
static const char publicKey[] =
"-----BEGIN PUBLIC KEY-----\n\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCKFctVrhfF3m2Kes0FBL/JFeO\
cmNg9eJz8k/hQy1kadD+XFUpluRqa//Uxp2s9W2qE0EoUCu59ugcf/p7lGuL99Uo\
SGmQEynkBvZct+/M40L0E0rZ4BVgzLOJmIbXMp0J4PnPcb6VLZvxazGcmSfjauC7\
F3yWYqUbZd/HCBtawwIDAQAB\n\
-----END PUBLIC KEY-----";
I would like to encrypt with PKCS #1 v1.5 padding (RSA_PKCS1_PADDING) but I can't figure out how to load the key from memory instead of a file:
void init()
{
RSA* rsa = RSA_new();
//what now?
//rsa = PEM_read_RSA_PUBKEY(file, &rsa, NULL, NULL); //requires a file
}
void encrypt(unsigned char* data, int length)
{
//can input buffer and output buffer be the same?
RSA_public_encrypt(length, data, data, rsa, RSA_PKCS1_PADDING);
}
Also, do I need to call any cleanup code?

You need to create bio and use functions that work with them:
BIO *mem = BIO_new_mem_buf(publicKey, -1);
RSA *rsa = PEM_read_bio_RSA_PUBKEY( mem, nullptr, nullptr, nullptr );
BIO_free( mem );
... // using rsa
error handling is ommited obviously.
Also, do I need to call any cleanup code?
Yes you always should. I would use RAII with smart pointers:
using BIO_ptr = std::unique_ptr<BIO,int(BIO *)>;
BIO_ptr createMemBio( const char *str )
{
return BIO_ptr{ BIO_new_mem_buf(str, -1), BIO_free };
}
and so on

Related

Trouble loading RSA public key from file

I've been using openssl library in my C++ project recently, and I'm facing an issue that i can't fix by myself.
I'm actually trying to load an RSA public key stored in a file and encrypt 64 bytes.
My code works when it uses a public key generated using the function RSA_generate_key, but when i'm using my own public key, it won't work anymore for some reason.
I've suspected key format from pkcs1 pkcs8, tried both PEM_read_RSAPublicKey and PEM_read_RSA_PUBKEY, still not working for some reason...
This is my public key :
-----BEGIN RSA PUBLIC KEY-----
MEYCQQDE91cW7INdIyVon5H/he2b/DIR25wWT0GFLiZOVp0oAgCAVKDvRZ5+Pqu4
f65XbnNUNNHRJLMLEb1t4JgUhgFVAgER
-----END RSA PUBLIC KEY-----
The key from RSA_generate_key function from Openssl library, which is working :
-----BEGIN RSA PUBLIC KEY-----
MEYCQQDsg/4Qm153/Pr8JRruC0SnVvTrWg/lIPheezIpkwVeWjNz9lMDXNUjdK8v
QgfNUCRJYbnxYIeruAdwTzS/bDXbAgER
-----END RSA PUBLIC KEY-----
And here's my code :
RSA.h :
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <string>
#ifndef RSA_ALGORITHM_H
#define RSA_ALGORITHM_H
#define KEY_LENGTH 512
#define PUBLIC_EXPONENT 17
#define PUBLIC_KEY_PEM 1
#define PRIVATE_KEY_PEM 0
#define LOG(x) \
std::cout << x << std::endl; \
/*
* #brief create_RSA function creates public key and private key file
*
*/
RSA* create_RSA(RSA* keypair, int pem_type, char* file_name);
/*
* #brief public_ecrypt function encrypts data.
* #return If It is fail, return -1
*/
int public_encrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding);
/*
* #brief private_decrypt function decrypt data.
* #return If It is fail, return -1
*/
int private_decrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding);
/*
* #brief create_ecrypted_file function creates .bin file. It contains encrypted data.
*/
void create_encrypted_file(char* encrypted, RSA* key_pair);
#endif //RSA_ALGORITHM_H
RSA.cpp :
#include "RSA.h"
#include <iostream>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <sstream>
#include <iomanip>
int public_encrypt(int flen, unsigned char* from, unsigned char* to, RSA* key, int padding) {
int result = RSA_public_encrypt(flen, from, to, key, padding);
return result;
}
void create_encrypted_file(char* encrypted, RSA* key_pair) {
FILE* encrypted_file = fopen("encrypted_file.bin", "w");
fwrite(encrypted, sizeof(*encrypted), RSA_size(key_pair), encrypted_file);
fclose(encrypted_file);
}
RSA* createRSA(int pem_type, char* file_name) {
RSA* rsa = NULL;
FILE* fp = NULL;
if (pem_type == PUBLIC_KEY_PEM) {
fp = fopen(file_name, "rb");
PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL);
fclose(fp);
}
else if (pem_type == PRIVATE_KEY_PEM) {
fp = fopen(file_name, "rb");
PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);
fclose(fp);
}
return rsa;
}
int main() {
LOG("RSA has been started.");
char public_key_pem[11] = "public_key";
RSA* public_key = createRSA(PUBLIC_KEY_PEM, public_key_pem);
LOG("Public key pem file has been created.");;
char message[KEY_LENGTH] = "\xc8\xcd\x21\x74\xb9\x84\x33\xb9\x30\x94\xb3\x60\x26\xde\x12\x5a\x7f\x5e\xd8\x5e\xc2\x7e\xe6\xbb\x9e\x99\x6c\xb3\xb9\x38\xe9\xc6\x23\x8c\xc6\x5d\x36\x15\xfb\x63\x5f\x6f\x08\x0f\x6d\xda\x06\x31\x59\x28\xbc\xae\x4c\xcf\x80\x2f\x96\x80\x54\x7d\xb5\x7b\x82\x83";
char* encrypt = NULL;
LOG(KEY_LENGTH);
LOG(PUBLIC_EXPONENT);
encrypt = (char*)malloc(RSA_size(public_key));
int encrypt_length = public_encrypt(RSA_size(public_key), (unsigned char*)message, (unsigned char*)encrypt, public_key, RSA_NO_PADDING);
if (encrypt_length == -1) {
LOG("An error occurred in public_encrypt() method");
}
LOG("Data has been encrypted.");
create_encrypted_file(encrypt, public_key);
LOG("Encrypted file has been created.");
free(public_key);
free(encrypt);
LOG("RSA has been finished.");
return 0;
}
I've seen many posts and haven't found any fix, even though that this one was extremely similar to my issue
.
Load public key to create rsa object for public encryption
Both keys are public RSA keys with a size of 512 bits and an exponent of 17, specified in PKCS1-PEM format.
The message m, the modulus n_fail of the not working key and the modulus n_ok of the working key are:
m = 0xc8cd2174b98433b93094b36026de125a7f5ed85ec27ee6bb9e996cb3b938e9c6238cc65d3615fb635f6f080f6dda06315928bcae4ccf802f9680547db57b8283
n_fail = 0xc4f75716ec835d2325689f91ff85ed9bfc3211db9c164f41852e264e569d2802008054a0ef459e7e3eabb87fae576e735434d1d124b30b11bd6de09814860155
n_ok = 0xec83fe109b5e77fcfafc251aee0b44a756f4eb5a0fe520f85e7b322993055e5a3373f653035cd52374af2f4207cd50244961b9f16087abb807704f34bf6c35db
A comparison shows that
n_fail < m < n_ok
For RSA the condition m < n must apply. This condition is violated for n_fail, which is the cause of the issue. This also means that the corresponding key itself is not invalid. It can be used to encrypt messages that do not violate m < n. For the posted message, however, its modulus is too small.
Regarding security: Nowadays the key should have a size of 2048 bits and one of the paddings specified in RFC8017 (RSAES-PKCS1-v1_5 or RSAES-OAEP) should be used.
The error is actually mathematically related. Neither the key nor the the code is causing the issue. If you change the key or the data to encrypt, it'll work fine for some reason. So i guess something is happening during RSA calculation, but no smart enough to figure out what.

Verifying message signature produce HEADER TOO LONG error

Background
I am trying to verify signature of a given binary file using openssl. Actual signing of binary hash is done by a 3rd party. Both 3rd party and I have the same exact certificate - they sent me the certificate.
I have verified health of my certificate by running openssl x509 -noout -text -inform DER -in CERT_PATH. This displays contents of cert correctly.
Following is my code so far - I based it on openssl wiki example here:
static std::vector<char> ReadAllBytes(char const* filename){
std::ifstream ifs(filename, std::ios::binary|std::ios::ate);
std::ifstream::pos_type pos = ifs.tellg();
std::vector<char> result(pos);
ifs.seekg(0, std::ios::beg);
ifs.read(result.data(), pos);
return result;
}
int main(int ac, const char * av[]) {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
// most of error check omitted for brevity
auto foundBinBytes = ReadAllBytes("BINARY_PATH");
auto foundSgnBytes = ReadAllBytes("SIGNATURE_PATH");
auto foundCertBytes = ReadAllBytes("CERT_PATH");
ERR_clear_error();
BIO *b = NULL;
X509 *c;
b = BIO_new_mem_buf(reinterpret_cast<const unsigned char *>(foundCertBytes.data()), foundCertBytes.size());
c = d2i_X509_bio(b, NULL);
EVP_MD_CTX* ctx = NULL;
ctx = EVP_MD_CTX_create();
const EVP_MD* md = EVP_get_digestbyname("SHA256");
int rc = EVP_DigestInit_ex(ctx, md, NULL);
EVP_PKEY *k = NULL;
k = X509_get_pubkey(c);
rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, k);
rc = EVP_DigestVerifyUpdate(ctx, reinterpret_cast<const unsigned char *>(foundBinBytes.data()), foundBinBytes.size());
ERR_clear_error();
rc = EVP_DigestVerifyFinal(ctx, reinterpret_cast<const unsigned char *>(foundSgnBytes.data()), foundSgnBytes.size());
ERR_print_errors_fp( stdout );
// openssl free functions omitted
if(ctx) {
EVP_MD_CTX_destroy(ctx);
ctx = NULL;
}
return 0;
}
Issue
Running this code produces following errors:
4511950444:error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long:/.../crypto/asn1/asn1_lib.c:152:
4511950444:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:/.../crypto/asn1/tasn_dec.c:1152:
4511950444:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:/.../crypto/asn1/tasn_dec.c:314:Type=X509_SIG
Question
What is wrong with my setup/code? Did I miss something along the way?
You never check the errors when reading the files. You might have errors there (does the file "CERT_PATH" exist? Do you have read permissions? ...).
If "CERT_PATH" cannot be read, then foundCertBytes.data() is an empty byte array, and this explains the subsequent errors.
If you get these errors in a mosquitto secured server's log, check the config file.
My mosquitto.conf was containing :
require_certificate true
my meross device doesn't send certificate. Turning this to "false" solved my problem after restart

How to avoid SIGABRT when generating RSA Signature at EVP_SignFinal

I'm trying to generate a RSA Signature with libopenssl for c++:
But when I run my code, I get a SIGABRT. I did some deep debugging into libopenssl internal stuff to see where the Segfault comes from. I'll come to this later on.
First I want to make clear, that the RSA PrivateKey was successfully loaded from a .pem file. So Im pretty sure that's not the problem's origin.
So my question is: How to avoid the SIGABRT and what is the cause of it ?
I'm doing this for my B.Sc. Thesis so I really appreciate your help :)
Signature Generation Function:
DocumentSignature* RSASignatureGenerator::generateSignature(ContentHash* ch, CryptographicKey* pK) throw(PDVSException) {
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
if(pK == nullptr)
throw MissingPrivateKeyException();
if(pK->getKeyType() != CryptographicKey::KeyType::RSA_PRIVATE || !dynamic_cast<RSAPrivateKey*>(pK))
throw KeyTypeMissmatchException(pK->getPem()->getPath().string(), "Generate RSA Signature");
//get msg to encrypt
const char* msg = ch->getStringHash().c_str();
//get openssl rsa key
RSA* rsaPK = dynamic_cast<RSAPrivateKey*>(pK)->createOpenSSLRSAKeyObject();
//create openssl signing context
EVP_MD_CTX* rsaSignCtx = EVP_MD_CTX_create();
EVP_PKEY* priKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(priKey, rsaPK);
//init ctxt
if (EVP_SignInit(rsaSignCtx, EVP_sha256()) <=0)
throw RSASignatureGenerationException();
//add data to sign
if (EVP_SignUpdate(rsaSignCtx, msg, std::strlen(msg)) <= 0) {
throw RSASignatureGenerationException();
}
//create result byte signature struct
DocumentSignature::ByteSignature* byteSig = new DocumentSignature::ByteSignature();
//set size to max possible
byteSig->size = EVP_MAX_MD_SIZE;
//alloc buffer memory
byteSig->data = (unsigned char*)malloc(byteSig->size);
//do signing
if (EVP_SignFinal(rsaSignCtx, byteSig->data, (unsigned int*) &byteSig->size, priKey) <= 0)
throw RSASignatureGenerationException();
DocumentSignature* res = new DocumentSignature(ch);
res->setByteSignature(byteSig);
EVP_MD_CTX_destroy(rsaSignCtx);
//TODO open SSL Memory leaks -> where to free open ssl stuff?!
return res;
}
RSA* rsaPK = dynamic_cast(pK)->createOpenSSLRSAKeyObject();
virtual RSA* createOpenSSLRSAKeyObject() throw (PDVSException) override {
RSA* rsa = NULL;
const char* c_string = _pem->getContent().c_str();
BIO * keybio = BIO_new_mem_buf((void*)c_string, -1);
if (keybio==NULL)
throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if(rsa == nullptr)
throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());
//BIO_free(keybio);
return rsa;
}
SigAbrt origin in file openssl/crypto/mem.c
void CRYPTO_free(void *str, const char *file, int line)
{
if (free_impl != NULL && free_impl != &CRYPTO_free) {
free_impl(str, file, line);
return;
}
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
if (call_malloc_debug) {
CRYPTO_mem_debug_free(str, 0, file, line);
free(str);
CRYPTO_mem_debug_free(str, 1, file, line);
} else {
free(str);
}
#else
free(str); // <<<<<<< HERE
#endif
}
the stacktrace
stacktrace screenshot from debugger (clion - gdb based)
I just found the Bug (and Im really not sure if this is a libopenssl bug..)
//set size to max possible
byteSig->size = EVP_MAX_MD_SIZE;
//alloc buffer memory
byteSig->data = (unsigned char*)malloc(byteSig->size);
The problem was when I set the buffer size to EVP_MAX_MD_SIZE!
The (in my opinion) very very strange thing is, that you have to keep the size uninitialized! (not even set to 0 - just "size_t size;" ).
Strange thing here is that then you also HAVE TO allocate memory just like I did. I dont understand this because then an undefined size of memory gets allocated..
What the really weird is that libopenssl internally sets the size back to 0 and allocates the memory itself.. (I detected this by browsing the libopenssl source code)

PEM_read_bio_RSAPrivateKey() difference on Windows

I am writing some code to RSA sign data. I have gotten this code to work successfully on Ubuntu (OpenSSL version is 1.0.1f-1ubuntu2.7). The code takes the message, and produces the signed result with the private key, I can verify is correct using a separate program and the matching public key.
Under windows, the exact same code produces a different result, the signed data is different (And does not verify. I can't figure out why. I am using the OpenSSL distribution 'Win64OpenSSL-1_0_1j' from http://slproweb.com/products/Win32OpenSSL.html .
Here is the code:
const char * rsa_pri_key = "-----BEGIN RSA PRIVATE KEY-----\n"
"MII...L1t\n"
"yC0...+zk\n"
"c0...5Q\n"
"-----END RSA PRIVATE KEY-----\n";
BIO* bio = BIO_new_mem_buf( (void*)rsa_pri_key, -1 );
BIO_set_flags( bio, BIO_FLAGS_BASE64_NO_NL );
RSA* private_key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL ) ;
if( !private_key )
{
std::cout << "Key load failed" << std::endl;
}
BIO_free( bio ) ;
// Sign the data
signature = (unsigned char*) malloc(RSA_size(private_key));
RSA_sign(NID_md5, (unsigned char*) message, strlen(message), signature, &slen, private_key)
I think the issue might be related to the char type on Linux and windows differing in whether they're signed or not. You're casting to (unsigned char *) which might be where the issue arises.

Separating public and private keys from RSA keypair variable

As the title says, I have some code that generates a pair of RSA keys. I want to split them apart and use them individually to encrypt/decrypt, rather than use the variable "keypair" to encrypt, and decrypt.
I am working to transfer data across a network, and want to encrypt it using simple RSA encryption. Therefore i want to send the public key over to a different user, so he can use it to encrypt some data, and then send it back to me.
Here is the code that generates the keys:
//Generate key pair
RSA *keypair = RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);
I now want to separate the public from the private key, so i can use them independently to encrypt and decrypt data. How can i do that?
I've got some code that takes the "keypair" and extracts some information into some "BIO" variables, although i am not sure how that would help me:
// 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);
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';
#ifdef PRINT_KEYS
printf("\n%s\n%s\n", pri_key, pub_key);
#endif
printf("done.\n");
This code works, since i've tested it in visual studio 2012.
Any ideas on how to separate the keys, then maybe put them back together in a "keypair" or maybe how to use them separately to encrypt/decrypt some string variables?
Thank you
(FULL CODE)
#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() {
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
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);
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';
#ifdef PRINT_KEYS
printf("\n%s\n%s\n", pri_key, pub_key);
#endif
printf("done.\n");
// Get the message to encrypt
printf("Message to encrypt: ");
fgets(msg, KEY_LENGTH-1, stdin);
msg[strlen(msg)-1] = '\0';
// Encrypt the message
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, keypair, 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;
}
// Decrypt it
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);
goto free_stuff;
}
printf("Decrypted message: %s\n", decrypt);
getchar();
//printf("%s", pub_key);
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);
}
Found this code here : https://shanetully.com/2012/04/simple-public-key-encryption-with-rsa-and-openssl/
I want to split [the keypair] apart and use them individually to encrypt/decrypt
... Any ideas on how to separate the keys, then maybe put them back together in a "keypair" or maybe how to use them separately to encrypt/decrypt some string variables?
You can use RSAPublicKey_dup and RSAPrivateKey_dup, without the need to round trip them by ASN.1/DER or PEM encoding them. Here, round tripping consist of using a functions like PEM_write_bio_RSAPublicKey and PEM_read_bio_RSAPublicKey.
Below is a sample program that uses them. Its written in C++ (thanks for adding that tag).
While you can separate them, they both use the RSA structure. The public key has some members set to NULL, like the private exponent.
You can also print the keys with RSA_print, RSA_print_fp and friends. See RSA_print (3) or its use below.
// g++ -Wall -Wextra -std=c++11 -stdlib=libc++ -I/usr/local/ssl/macosx-x64/include \
// t.cpp -o t.exe /usr/local/ssl/macosx-x64/lib/libcrypto.a
#include <memory>
using std::unique_ptr;
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <cassert>
#define ASSERT assert
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
int main(int argc, char* argv[])
{
int rc;
RSA_ptr rsa(RSA_new(), ::RSA_free);
BN_ptr bn(BN_new(), ::BN_free);
rc = BN_set_word(bn.get(), RSA_F4);
ASSERT(rc == 1);
rc = RSA_generate_key_ex(rsa.get(), 2048, bn.get(), NULL);
ASSERT(rc == 1);
RSA_ptr rsa_pub(RSAPublicKey_dup(rsa.get()), ::RSA_free);
RSA_ptr rsa_priv(RSAPrivateKey_dup(rsa.get()), ::RSA_free);
fprintf(stdout, "\n");
RSA_print_fp(stdout, rsa_pub.get(), 0);
fprintf(stdout, "\n");
RSA_print_fp(stdout, rsa_priv.get(), 0);
return 0;
}
Here is the output:
$ ./t.exe
Public-Key: (2048 bit)
Modulus:
00:aa:5a:cc:30:52:f1:e9:49:3d:a6:25:00:33:29:
a6:fa:f7:53:e0:3c:73:4c:91:41:66:20:ec:62:1f:
27:2a:2a:6c:0f:90:f8:d9:7e:d5:ec:72:7b:38:8c:
ca:12:60:f8:d1:fb:f2:65:7c:b1:3a:b6:4e:26:ba:
5b:86:cc:30:f2:fc:be:c3:a2:00:b9:ea:81:fa:1c:
22:4e:f7:be:a1:1a:66:90:13:b6:12:66:26:23:6d:
22:15:7d:3b:a4:99:44:38:fa:1c:70:63:4e:50:6f:
66:38:6c:f6:1a:13:e1:c7:dc:a6:a1:eb:6f:f9:c9:
59:c8:30:dc:c2:1b:dc:6c:9d:ea:0c:3d:52:5a:00:
ea:c9:c9:85:51:21:9f:ec:95:b3:dc:c2:50:21:29:
c2:64:6c:1e:34:36:d8:61:59:ab:3c:a2:cc:e8:ef:
57:c3:7f:49:86:be:e3:42:88:1b:39:10:b8:2f:fa:
81:ef:a0:94:99:0c:71:ae:1e:82:7f:e3:6e:00:6e:
02:13:66:bb:a9:31:58:ec:90:39:9c:bc:9c:8c:90:
e9:20:f7:20:8e:d6:a3:a3:df:a2:4a:0f:0f:39:b5:
57:b9:ef:6a:27:e0:1a:ed:f6:ce:0d:87:cd:43:03:
bf:67:ef:ff:fd:da:98:cc:22:ab:5e:8d:7b:43:d3:
90:4d
Exponent: 65537 (0x10001)
Private-Key: (2048 bit)
modulus:
00:aa:5a:cc:30:52:f1:e9:49:3d:a6:25:00:33:29:
a6:fa:f7:53:e0:3c:73:4c:91:41:66:20:ec:62:1f:
27:2a:2a:6c:0f:90:f8:d9:7e:d5:ec:72:7b:38:8c:
ca:12:60:f8:d1:fb:f2:65:7c:b1:3a:b6:4e:26:ba:
5b:86:cc:30:f2:fc:be:c3:a2:00:b9:ea:81:fa:1c:
22:4e:f7:be:a1:1a:66:90:13:b6:12:66:26:23:6d:
22:15:7d:3b:a4:99:44:38:fa:1c:70:63:4e:50:6f:
66:38:6c:f6:1a:13:e1:c7:dc:a6:a1:eb:6f:f9:c9:
59:c8:30:dc:c2:1b:dc:6c:9d:ea:0c:3d:52:5a:00:
ea:c9:c9:85:51:21:9f:ec:95:b3:dc:c2:50:21:29:
c2:64:6c:1e:34:36:d8:61:59:ab:3c:a2:cc:e8:ef:
57:c3:7f:49:86:be:e3:42:88:1b:39:10:b8:2f:fa:
81:ef:a0:94:99:0c:71:ae:1e:82:7f:e3:6e:00:6e:
02:13:66:bb:a9:31:58:ec:90:39:9c:bc:9c:8c:90:
e9:20:f7:20:8e:d6:a3:a3:df:a2:4a:0f:0f:39:b5:
57:b9:ef:6a:27:e0:1a:ed:f6:ce:0d:87:cd:43:03:
bf:67:ef:ff:fd:da:98:cc:22:ab:5e:8d:7b:43:d3:
90:4d
publicExponent: 65537 (0x10001)
privateExponent:
66:a4:ce:e3:4f:16:f3:b9:6d:ab:ee:1f:70:b4:68:
28:4f:5d:fa:7e:71:fa:70:8b:37:3e:1f:30:00:15:
59:12:b6:89:aa:90:46:7c:65:e9:52:11:6c:c1:68:
00:2a:ed:c1:98:4d:35:59:2c:70:73:e8:22:ed:a6:
b8:51:d0:2c:98:9d:58:c3:04:2d:01:5f:cf:93:a4:
18:70:ae:2b:e3:fc:68:53:78:21:1d:eb:5c:ed:24:
dc:4d:d8:e2:14:77:46:dd:6c:c5:4b:10:a4:e6:7a:
71:05:36:44:00:36:ca:75:e8:f1:27:2b:11:16:81:
42:5e:2e:a5:c6:a3:c9:cd:60:59:ce:72:71:76:c8:
ca:ba:f0:45:c3:86:07:7b:22:20:c4:74:c6:a8:ab:
7c:2c:f8:de:ea:25:95:81:79:33:54:67:7b:61:91:
80:a8:1f:4c:38:32:d4:4d:2e:a8:7d:9b:d4:1a:3e:
6b:ca:50:3c:a0:61:0e:00:ad:f4:5c:0f:26:1a:59:
00:3c:bd:ee:c3:e8:d0:b8:9b:0e:44:89:49:d1:24:
a4:39:15:dc:0e:c5:d5:41:a2:4a:f4:e5:e3:23:c7:
98:8a:87:f7:18:a6:e2:7b:27:83:f6:fb:62:42:46:
ae:de:ba:48:ad:07:39:40:da:65:17:d1:d2:ed:df:
01
prime1:
00:dd:dc:70:b5:70:ea:10:20:28:40:a0:c3:b8:70:
6d:3d:84:c0:57:2d:69:fc:e9:d4:55:ed:4f:ac:3d:
c2:e9:19:49:f0:ab:c6:bd:99:9e:0f:e5:a4:61:d4:
b3:c5:c2:b1:e4:3a:10:ff:e6:cd:ce:6e:2d:93:bc:
87:12:92:87:7c:d3:dd:bc:32:54:9e:fa:67:b1:9d:
e2:27:53:e6:03:a7:22:17:45:63:0d:42:f3:96:5d:
a3:e0:9c:93:f0:42:8b:bb:95:34:e6:f6:0b:f7:b6:
c5:59:a0:b5:2a:71:59:c0:f2:7e:bf:95:2d:dd:6d:
94:23:2a:95:4a:4f:f1:d0:93
prime2:
00:c4:91:6a:33:1b:db:24:eb:fd:d3:69:e9:3c:e2:
a2:2d:23:7a:92:65:a8:a0:50:1d:0a:2b:b4:f0:64:
e4:40:57:f3:dc:f7:65:18:7d:51:75:73:b9:d6:67:
9b:0e:94:5f:37:02:6c:7f:eb:b9:13:4b:bf:8e:65:
22:0b:2c:c6:8d:2a:a2:88:ec:21:e3:f9:0b:78:b4:
1d:d0:44:e6:36:0d:ec:3c:8f:0a:c7:3b:0d:91:65:
b7:de:a3:c9:a3:2a:8c:7f:1f:a1:d2:6e:9b:ee:23:
78:c1:30:76:87:af:a8:11:a4:15:b4:54:16:d8:94:
71:5c:64:30:43:58:b5:07:9f
exponent1:
2f:91:e8:88:be:e1:30:fb:f4:25:87:52:ef:e5:0b:
47:39:83:94:2d:a4:a0:19:f2:f1:49:a4:df:a5:8e:
79:34:76:ea:27:aa:c1:54:82:d3:9d:c5:95:44:6a:
17:69:1b:83:77:ff:d5:1e:c3:da:13:3d:aa:83:ad:
e2:89:90:8b:6f:52:07:dc:32:d0:b3:98:30:39:4e:
18:68:a0:d4:ff:ad:0b:98:51:18:b2:d6:4f:d3:5c:
23:f8:ee:af:81:55:3c:af:4d:5c:88:3d:20:ac:0b:
bc:9f:fc:b8:50:fd:91:a5:6d:0f:df:08:aa:85:a8:
51:b1:fb:b8:a7:53:8e:09
exponent2:
7d:46:0b:7f:ad:06:19:de:c8:b2:7e:f2:25:5a:6e:
6f:04:08:6e:da:99:00:2a:6e:87:77:d9:65:c7:76:
ec:46:e1:64:f6:ca:18:34:6d:c0:c3:d3:31:00:70:
82:77:2e:c3:59:29:1a:d1:78:ef:02:3c:7f:9c:96:
78:b6:bd:87:64:1f:97:d1:9d:bb:b3:91:8b:08:87:
63:9f:35:74:47:a5:41:e7:0b:c0:73:33:2f:71:bb:
20:0a:14:4c:87:a6:68:b2:19:28:8a:53:98:0e:45:
3c:22:0d:b8:65:cb:60:0a:c9:c6:56:3d:05:24:7d:
a6:9b:37:63:04:5a:c3:13
coefficient:
00:cc:d7:5c:e6:0e:7b:79:d4:cb:4f:6d:82:a7:45:
90:67:90:dc:d3:83:62:f1:4b:17:43:5c:4a:ea:bf:
38:25:c3:6f:34:e2:05:91:5e:60:d6:de:6d:07:1a:
73:71:b3:1d:73:f2:3c:60:ed:ec:42:d4:39:f8:a4:
ae:d5:aa:40:1e:90:b1:eb:b1:05:a3:2f:03:5f:c6:
b7:07:4c:df:0f:c4:a9:80:8c:31:f5:e2:01:00:73:
8a:25:03:84:4e:48:7a:31:8e:e6:b8:04:4c:44:61:
7d:e4:87:1c:57:4f:45:44:33:bb:f3:ae:1c:d2:e1:
99:ed:78:29:76:4d:8c:6d:91
Related, you never ask how to encrypt or decrypt with a RSA key, yet you claim the answer to the encryption and decryption problems is shown in the code in your answer.
You seem to have made the question a moving target :) You should probably avoid that on Stack Overflow (I think its OK to do in those user thread forums). On Stack Overflow, you should ask a separate question.
You can extract the RSA public key from RSA keypair using d2i_RSAPublicKey and i2d_RSAPublicKey (link). Use i2d_RSAPublicKey to encode your keypair to PKCS#1 RSAPublicKey stucture, store it in a bytestring, then use d2i_RSAPublicKey to decode it back to RSA key struct.
I've found a solution to my question among other Stack-Overflow posts and namely Reading Public/Private Key from Memory with OpenSSL
The answer i was 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);
i can send the variable pub across the network, and after it reaches the other side create a RSA variable and put pub inside it:
SOLUTION:
RSA *keypair2 = NULL;
PEM_read_bio_RSAPublicKey( pub, &keypair2, NULL, NULL);
After i've done this i 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);
}
I can then send this encrypt variable back to the first machine, and decrypt it as usual, using my original keypair, without having to send it over the network.
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);
}
Thank you everyone for contributing to this post!!!
Reviewing your code, it appears that you successfully separated the public and private keys into the strings pub_key and pri_key, but then used printf to output them which pasted them back together. To just print the public key change the printf statement to:
printf("\n%s\n", pub_key);