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