I've written a bare bones enveloping example that takes a string, seals it in an envelope, and then goes about opening it. Everything works just fine if I generate my RSA keys programatically. Unfortunately, it does not work if I encrypt the session keys with an RSA public key that was created on the command line like:
> openssl genrsa -out rsaprivatekey.pem > openssl rsa -in rsaprivatekey.pem -out rsapublickey.pem I would greatly appreciate if someone could explain why my programatically-created keys work, but the command-line ones do not. The code that generates usable keys looks like this: int main() { // generate & check keys ---- RSA* rsa = RSA_generate_key(2048, RSA_F4, NULL, 0); int check_key = RSA_check_key(rsa); while (check_key <= 0) { cerr << "error generating keys -- regenerating..."; rsa = RSA_generate_key(2048, RSA_F4, NULL, 0); check_key = RSA_check_key(rsa); } RSA_blinding_on(rsa, NULL); // write out pem-encoded public key ---- BIO* rsaPublicBio = BIO_new_file("rsapublickey.pem", "w"); PEM_write_bio_RSAPublicKey(rsaPublicBio, rsa); // write out pem-encoded encrypted private key ---- BIO* rsaPrivateBio = BIO_new_file("rsaprivatekey.pem", "w"); PEM_write_bio_RSAPrivateKey(rsaPrivateBio, rsa, NULL, NULL, 0, NULL, NULL); BIO_free(rsaPublicBio); BIO_free(rsaPrivateBio); RSA_free(rsa); ... return 0; } The program that uses the keys is: #include <cstdio> #include <cstring> #include <openssl/ssl.h> #include <openssl/rand.h> #include <openssl/ecdsa.h> #define BUF_SIZE 4096 #define BLOCK_SIZE 32 int main() { // uninitialized symmetric cipher context ---- EVP_CIPHER_CTX* ctx = new EVP_CIPHER_CTX; // symmetric cipher ---- const EVP_CIPHER* type = EVP_aes_256_cbc(); unsigned char message[BUF_SIZE] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; printf("Unencoded string = {%s}\n", message); int npubk = 1; unsigned char** ek = new unsigned char*[npubk]; int* ekl = new int[npubk]; EVP_PKEY** pubk = new EVP_PKEY*[npubk]; // read in pem-encoded public key ---- BIO* rsa_pub_bio = BIO_new_file("rsapublickey.pem", "r"); RSA* rsa_pub = RSA_new(); PEM_read_bio_RSAPublicKey(rsa_pub_bio, &rsa_pub, NULL, NULL); BIO_free(rsa_pub_bio); // encrypt symmetric session keys ---- for (int i = 0; i < npubk; i++) { pubk[i] = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pubk[i], rsa_pub); ek[i] = new unsigned char[EVP_PKEY_size(pubk[i])]; ekl[i] = EVP_PKEY_size(pubk[i]); } // random initialization vector ---- unsigned char* iv = new unsigned char[EVP_MAX_IV_LENGTH]; RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH); int message_len; // initialized by EVP_SealUpdate & EVP_SealFinal unsigned char encrypt_buf[BUF_SIZE + BLOCK_SIZE]; EVP_SealInit(ctx, type, ek, &ekl[0], &iv[0], &pubk[0], npubk); // EVP_SealUpdate changes message_len to # bytes in message ---- EVP_SealUpdate(ctx, encrypt_buf, &message_len, message, strlen((const char*) message)); printf("buf_len: %d\n", message_len); int total_len = message_len; // line must be between SealUpdate & SealFinal // EVP_SealFinal changes message_len value to # bytes of encryption overhead ---- EVP_SealFinal(ctx, &encrypt_buf[message_len], &message_len); int i; printf("Encoded string = {"); for (i = 0; i < message_len; i++) { printf("%02x", encrypt_buf[i]); } for (i = 0; i < message_len; i++) { printf("%02x", encrypt_buf[i + total_len]); } printf("}\n"); unsigned char decrypt_buf[BUF_SIZE]; int decrypt_len; // initialized by EVP_OpenUpdate & EVP_OpenFinal // read in pem-encoded encrypted private key ---- BIO* rsa_priv_bio = BIO_new_file("rsaprivatekey.pem", "r"); RSA* rsa_priv = RSA_new(); PEM_read_bio_RSAPrivateKey(rsa_priv_bio, &rsa_priv, NULL, NULL); BIO_free(rsa_priv_bio); EVP_PKEY* privk = EVP_PKEY_new(); EVP_PKEY_assign_RSA(privk, rsa_priv); EVP_OpenInit(ctx, type, *ek, ekl[0], &iv[0], privk); // EVP_OpenUpdate changes decrypt_len to # bytes in decrypted message ---- EVP_OpenUpdate(ctx, decrypt_buf, &decrypt_len, encrypt_buf, total_len + message_len); total_len = decrypt_len; // line must be between OpenUpdate & OpenFinal EVP_OpenFinal(ctx, &decrypt_buf[total_len], &decrypt_len); // EVP_OpenFinal changes decrypt_len value to # bytes of encryption overhead ---- decrypt_buf[total_len + decrypt_len] = '\0'; printf("Unencoded string = {%s}\n", decrypt_buf); delete ctx; EVP_PKEY_free(privk); for (int i = 0; i < npubk; i++) { EVP_PKEY_free(pubk[i]); delete ek[i]; } delete[] ek; delete[] ekl; delete[] pubk; delete[] iv; return 0; }