Crash in d2i_RSAPrivateKey_fp() - c++

I have a small VC++ code to load an ASN.1 .der file and read its private key. It compiles and runs fine, but it crashes at function d2i_RSAPrivateKey_fp.
Tools Used:
Visual Studio 2008 [V90]
OpenSSL 1.0.2d 9 Jul 2015
I have also tested the certificate to check if it was corrupted
Testing certificate:
C:\OpenSSL-Win32\bin>openssl rsa -in private.der -check -inform DER
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC/4V4jxRYeFBDh8XBNq2EMs3hXWW5IIN51lM/Oyz0U/Bw8HF0m
/VBJU3SCy2FzoYPa2o3HHYWDMnjmOlXb9aXR3hyLHnvgvE/0YkMXlxh58H1srjw4
FL7cLXe+lwFbZYtxRaHyn/3U3NIkZkCzR74oxHwyWJ1/zz+TzpmNx8AfyQIDAQAB
AoGAMn+9puxXxdLCHrTMOaTBBfa11UdUHueHpKplhqc2jC9NvwQ3/+rrFmFAaKve
GfCIIzEh3yWF3eGKsAzqS9l6qiyAT+LaCPcn7FbAsaMdVGPc4G290/3maASjQMj6
YfNTcmvPaqfq2+B+aNunS0pi6XGv3917KdGo4hTa2xFXwAECQQDfm5Rh0CjDwhjh
urghbvBgGVRJiAFowgp9xdJj8Hm/U+zXK9Tz2SwVcbEKbcqSVZqB8Keb11TEfF3W
JGIHGdOJAkEA260wKNAdWxgEXiSCEx/tSV3bcRQg4ypTqODc0cWtM295/lhV2Hgx
3zWQ5NiBYZsU104DLWlxnqulJKyBECmaQQJAFAjskpcEEAYkFJWWSeiWwQWD99Kn
zasVJY/D+hBh2DK81cqnmfGrcYBuTHDp5ZKl9V6Kpfv1LGW4Qqef4OL/gQJAb1Mp
IMW22r8lF4Bw2rhHS/LgjkGhGP4OP3sU7Mm8qGBJ9ndVqcnfnDpNH2wIxSoOOb4z
JgRVrA9YNWmmTkaHAQJBANiY3RDyEouYoNKN0oWXsZ/N6BwSFOYAAknmdY5uRwu2
tUQHFiW7u2wZCFmIZVqSBZc5XBdZcmffZeEiO1nVYH4=
-----END RSA PRIVATE KEY-----
C:\OpenSSL-Win32\bin>
Below is the code for the project.
Thing I have tried:
Win32OpenSSL-0_9_8zg (but same issue), OpenSSL 1.0.1
Tried linking libeay to MD, MDd, MT
Set flags to Generate /MAP, /MAPINFO:EXPORTS ,/ASSEMBLYDEBUG
exported to VS2010 project and compiled with openssl32 for VS2010
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <stdio.h>
int main()
{
int ret;
RSA *pkey=NULL;//RSA_new();
RSA *rsa =NULL;//RSA_new();
unsigned char text[2048/8] = "this is a test string";
unsigned char encrypted[4098]={};
unsigned char decrypted[4098]={};
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
ERR_load_ERR_strings();
FILE *fp;
fp = fopen("C:/Users/Public/private.der","rb");
if (fp != NULL)
{
rsa = d2i_RSAPrivateKey_fp(fp, &pkey); // <<< CRASH
}
else
{
//return "Error::Unable to read private key file";
}
if (rsa)
{
// RSA is good
ret = RSA_private_encrypt(RSA_size(pkey), text, encrypted, pkey, RSA_NO_PADDING);
if (ret == -1)
{
fclose(fp);
//return "Error::Failed to encrypt the data";
}
}
else
{
fclose(fp);
//return "Error::Failed to get *RSA Handle1";
}
fclose(fp);
}
Second attempt
I am facing issue with importing private key from ASN.1 .der file to a .pem file.
C:\OpenSSL-Win32\bin>openssl rsa -in private.der -inform DER -out privatepem.pem -outform PEM
writing RSA key
Now, I have .PEM file which have private key in Base64 Form which i will convert it to RSA *rsa; structure.
int main()
{
int ret;
RSA *pkey=NULL;//RSA_new();
RSA *rsa =NULL;//RSA_new();
FILE *fp;
fp = fopen("C:/Users/Public/privatepem.pem","r");
if(PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL) == NULL) // <<<CRASH
{
printf("\n%s\n", "Error Reading public key");
}
else
{
printf("\n%s\n", "Private key Imported");
}
return 0;
}
But the new code operating on .pem files has a crash while copying to RSA structure at PEM_read_RSAPrivateKey.
Why am I getting the crash? Is there something I am missing to do, may be initialization of some sort or something wrong with the key?

See the warnings at d2i_X509. This code will attempt to free (or reuse parts of) the pkey object:
if (fp != NULL)
rsa = d2i_RSAPrivateKey_fp(fp, &pkey); /* CRASH */
OpenSSL is not exactly known for validating parameters before taking actions on them :)
Instead, use:
if (fp != NULL)
rsa = d2i_RSAPrivateKey_fp(fp, NULL);
Or:
RSA* pkey = RSA_new();
...
if (fp != NULL)
rsa = d2i_RSAPrivateKey_fp(fp, &pkey);
Also see Seg fault from d2i_RSAPrivateKey_fp on the OpenSSL Users mailing list.
As for the crash after using the API as directed, then it sounds like you have other issues. Since OpenSSL is cross-platofrm, its "write once, run everywhere". Port the OpenSSL-based TLS logic to Linux, and get a memory checker like Valgrind on it.

Problem was solved by replacing the OpenSSL binaries.
Code worked without any changes.
Project had prebuild dependencies of OpenSSL which was from unknown source.
So just by replacing dependencies from "https://slproweb.com/products/Win32OpenSSL.html" it worked like a charm.
:)
Thanks guys

Related

How do I generate a DER encoded public key with OpenSSL in C/C++?

I have been developing a Minecraft server software and having some trouble generating a DER encoded public key with OpenSSL in C/C++.
https://wiki.vg/Protocol_Encryption (The documentation of making a server software) says this:
The server generates a 1024-bit RSA keypair on startup.
The public key is sent in the Encryption Request packet in DER encoding format.
More technically, it is in ASN.1 format as defined by x.509 with the structure looking as follows.
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm SEQUENCE {
algorithm OBJECT IDENTIFIER
parameters ANY OPTIONAL
}
subjectPublicKey BITSTRING
}
SubjectPublicKey ::= SEQUENCE {
modulus INTEGER
publicExponent INTEGER
}
Here is my current code:
RSA* rsa = RSA_new();
if (!rsa)
return false;
BIGNUM* exponent = BN_new();
if (!exponent)
{
RSA_free(rsa);
return false;
}
EVP_PKEY* pkey = EVP_PKEY_new();
if (!pkey)
{
RSA_free(rsa);
BN_free(exponent);
return false;
}
BN_set_word(exponent, 65537);
RSA_generate_key_ex(rsa, 1024, exponent, NULL);
EVP_PKEY_set1_RSA(pkey, rsa);
// Write the DER encoded public key
std::vector<uint8_t> derPublicKey;
{
derPublicKey.resize(1024);
X509* x509 = X509_new();
X509_set_pubkey(x509, pkey);
uint8_t* keyPtr = derPublicKey.data();
int keyLength;
if (!(keyLength = i2d_X509(x509, &keyPtr)))
{
RSA_free(rsa);
BN_free(exponent);
return false;
} derPublicKey.resize(keyLength);
X509_free(x509);
}
// Free everything
RSA_free(rsa);
BN_free(exponent);
EVP_PKEY_free(pkey);
This code compiles, but the client connecting still says in the log "Public key reconstitute failed" with no further information. Can someone explain how this can be done? Thanks.
PS: I have very little knowledge about cryptography. I am only doing this project for fun.

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.

Boost.Asio SSL context load_verify_paths not loading certificate(s)

I have code to retrieve all root certificates in the Windows certificate store for the current user:
#include <windows.h>
#include <Wincrypt.h>
inline std::vector<std::string> system_root_certificates()
{
std::vector<std::string> certs;
HCERTSTORE hStore;
PCCERT_CONTEXT pCertContext = NULL;
if (!(hStore = ::CertOpenStore(
CERT_STORE_PROV_SYSTEM_A,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
"Root")))
return certs;
do
{
if (pCertContext = ::CertFindCertificateInStore(
hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_ANY,
NULL,
pCertContext))
{
certs.push_back("-----BEGIN CERTIFICATE-----\n" +
Base64::encode_copy(std::string((char *) pCertContext->pbCertEncoded, (size_t) pCertContext->cbCertEncoded), true) +
"\n-----END CERTIFICATE-----\n");
}
} while (pCertContext);
if (!pCertContext)
::CertFreeCertificateContext(pCertContext);
::CertCloseStore(
hStore,
CERT_CLOSE_STORE_FORCE_FLAG);
return certs;
}
Then I write the certificates out to a file:
...
for (size_t i = 0; i < certs.size(); ++i)
certFile << certs[i];
...
I have verified that the file is being written correctly.
A sample of the first two certificates from the file:
-----BEGIN CERTIFICATE-----
MIIFMIIDoAMCAgIQrRahoKWtc1j0Ey5lDQYJhkiGDQEBBQAwMRMwBgoJJomTLGQBFgNjbTEZFwYK
kiaJ8ixkGRYJaWNyc29mMS0wBgNVAxMkaWNyc29mIFJvdCBDcnRpaWNhZSBBdGhvaXR5HhcNMTA1
OTIzOTIyFw0yMDUwMjMyMTNaXzETEQYKkiaJ8ixkGRYDb20xMBcGCZImk/IsARkWbWljb3NvdDEt
KwYDBAMTTWljb3NvdCBSb3QgZXJ0ZmljdGUgdXRocml0MIICMA0GKoZI9w0BAQUAggIPMIICAoIC
APNdgGfUp6kMkCDQCDx1zbcHnInazsNgkWhalHEpdnzCyCV2Dlj6NDbmr/eA6VgLk+Wd43ci9zRk
IpEd4QmQFP78WBnhtweSrohZ2J8HA1j8KW0y0qjL/OELMk/muK1PXG8TmduVdduot5SRd1v1DI9q
fRRwfW2v9dpwR7e/L2znt+ERrHmRfMXW5OF+w37l0jwANoLe4W3zbvifyctSc5g2i6FrlZeb3sJN
/waWJQbIrOTuM5UxyDUINMp51bW+MllAwKVOTT3bBzPkv+8/ZNhCNVf9RXwkTZ7WdBGXkM5odJJv
S2+w48c2oND8wFr5YbkwcZYKsJHAle8QKGrjH7HkAz93BMcgSQ8diKTXfoitLexFxFEEKvzsnpoR
W97OiObi/ayVKEDbBJDfMznZRaUjBqVVMbsGYA5BfR8ul8sRFdUklO8Vif1L+jJb0TMAWWJwMuou
QC173SFnMJmPqiOo0bBumzbEQHScWGXBHnpbyI+7JnzUQOW2bKqGAL/ONQIDAAGjME8wBgNVDwQE
AgHGDwYDHRMB/wQFAwEBMB0GVR0OFgQUrIJgVieXJRP84QpTWeSkEAYJBgEEgjcVBAMCADANCSqG
hvcNAQUFA4ICAMURAzpgXVIRj7K7yLIFtLeoIJ1cA7Yc+gYTtshjmkdvV9JVBLEm1qlQoLzSbszD
rN8ZeKxZrGY0xBs+OEwzMBINJv5RAP+vToQNH+RtLk6FjWwzVNJkv1Cvejmg7WMD/BMGFjbUO5Ub
YjrlF9QFkponW6q9u77jiWBxVrOl0G0OfpUDaD3yY7hrtugw4cqU96KqmTCyp8JRKCABJytLt50R
cL6ygrwMaNCNJIeqKHKdX1mQ9d6TOmJaOeKIHbkGwYlr12nDEjaEyaDaL2l45Xra1wzAvWMXORM4
Nlt7hVZqZGLB4qq/ZqKUEpxmEGvyMJItKfA9FENo8Zwpy844JW18834kJAMIR+yll/UYz7vVdpbv
zttWlaBCl1jhMSLTWeY+IgDqhLYl2fMIaMBkHXzsk6Jibi7YWI/ESSbdKTWHMHFwFDxpiRJ9LqP+
f56CUgorQyvZiJ/I+4mNoYV1fmyecxNkaaUvypZt+ARNkj1uFCHJ4MP9a51K0aGdQ3c/2g==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICMIICoAMCAgIBMA0GKoZI9w0BBAUAgYsxMAkGVQQGAlpBFTATA1UEEwxXc3RlbiBDcGUxMBIG
VQQHC0R1YmFuaWxsMQ8wBgNVChMGaGF3ZTEdGwYDBAsTVGhhdGUgZXJ0ZmljdGlvMR8wBgNVAxMW
aGF3ZSBUbWVzYW1wbmcgQTAeDTk3MTAxMDAwMFoXMjAxMzEyNTk1WjCBMQswBgNVBhMCQTEVEwYD
BAgTV2VzZXJuQ2FwMRQwBgNVBxMLdXJibnZpbGUxMA0GVQQKBlRod3RlHTAbA1UEExRUYXd0IENl
dGlmY2F0b24xMB0GVQQDFlRod3RlVGltc3RhcGluIENBgZ8wBgkqSIb3AQEBAAOBADCBAoGB1itY
YUWG6jR7nO2wLhgO4F+o07TJfFlODnNUwX/2Luk6JBU8RwRjnsSUWt9M89lDPBB6JduQ8FHn1kEA
nyjfvpS7thTjhdep4EyksCsa8vg7PkWskgC0QZj77fq3iviIAgMBAaMTETAPA1UdAQH/BTADAf8w
BgkqSIb3AQEEAAOBAGfbwuaHQIOGNX0fmsMMIKi6BImG9RAIv8uiitBNPvTXacZesJRvuefeiLZ7
4yflw/A1y7UnM3ncpgCe+vzNlEIW0xxov1zdqXsQMnRUMYuFhJG3ATAUryjKsVAZCayJ0w==
-----END CERTIFICATE-----
I then close the file, and call
sslContext->load_verify_file(filename);
The load_verify_file function fails with error too long. The function also fails if I only write one certificate to the file, with the same error code.
openssl verify <cert_filename> returns the following (complete) output:
unable to load certificate
2404:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:.\crypto\asn1\asn1_lib.c:142:
2404:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:.\crypto\asn1\tasn_dec.c:1303:
2404:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:380:Type=X509
2404:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:.\crypto\pem\pem_oth.c:83:
Is the error caused by the format that I am writing to the file in? What else could cause this error?
Use base64 -d to decode the certificate, it shows der formatted binary, but the length is not correct, e.g. the first certificate's der format indicates 0x0530 + 4 bytes. The der file shall have 1332 bytes, but actually it's only 1078 bytes.
So it indicates that the certificate is corrupted.
Google this topic, it's found that CryptBinaryToString() is a better option to convert the pbCertEncoded, instead of directly calling Base64 function to get the string.

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

RSA encryption change the data size

i used the example from the openssl demos for rsa encryption and decription , it work but the data after encryption was not the same as the text before encryption ., i need it to be the same .. so where can i modify the code so it can be return the same data size without any corruption of the encryption proccesss ., ?? Thanks in Advance ..
below is the code :
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include "loadkeys.h"
#define PUBFILE "cert.pem"
#define PRIVFILE "privkey.pem"
#define STDIN 0
#define STDOUT 1
int main()
{
char *ct = "This the clear text";
char *buf;
char *buf2;
EVP_PKEY *pubKey;
EVP_PKEY *privKey;
int len;
ERR_load_crypto_strings();
privKey = ReadPrivateKey(PRIVFILE);
if (!privKey)
{
ERR_print_errors_fp (stderr);
exit (1);
}
pubKey = ReadPublicKey(PUBFILE);
if(!pubKey)
{
EVP_PKEY_free(privKey);
fprintf(stderr,"Error: can't load public key");
exit(1);
}
/* No error checking */
buf = malloc(EVP_PKEY_size(pubKey));
buf2 = malloc(EVP_PKEY_size(pubKey));
len = RSA_public_encrypt(strlen(ct)+1, ct, buf, pubKey->pkey.rsa,RSA_PKCS1_PADDING);
if (len != EVP_PKEY_size(pubKey))
{
fprintf(stderr,"Error: ciphertext should match length of key\n");
exit(1);
}
printf("%d\n", strlen(buf));
printf("%d\n", strlen(ct));
RSA_private_decrypt(len, buf, buf2, privKey->pkey.rsa,RSA_PKCS1_PADDING);
printf("%s\n", buf2);
EVP_PKEY_free(privKey);
EVP_PKEY_free(pubKey);
free(buf);
free(buf2);
return 0;
}
I'm not sure you understand how RSA encryption works.
An RSA encryption produces a block of cipher text that is as wide as the modulus of the RSA key pair. This is not a negotiable attribute of the RSA encryption/decryption process. If you're using a 1024-bit RSA key, you're going to get a 128-byte cipher text for each "block" of cipher text input, and each block can range from 1 byte up to he size of the modulus (a little less, actually, read more about PKCS#1 standards here). Likewise, a 2048-bit key will generate a 256 byte cipher text .
RSA is expensive; indeed most-all asymmetric algorithms are. For this reason is is much more common to use RSA to encrypt a symmetric algorithm key (like a AES128 key), also called a "session" key, after using said key to encrypt your actual data, then sending both the encrypted session key and the encrypted data to the recipient. If the recipient has the proper private RSA key, they can decrypt the session key, then use that to symmetrically decrypt the actual data.
If you want small blocks of encrypted data, use symmetric encryption. You have much more flexibility in choices.
For more information on RSA Encryption, see here. For information on AES encryption, a standard for symmetric encryption, see here.