RSA public/private keys only work when created programatically.

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

RSA public/private keys only work when created programatically.

David Henry-6
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;
}


Reply | Threaded
Open this post in threaded view
|

Re: RSA public/private keys only work when created programatically.

Mounir IDRASSI
Hi,

Your command line that create the public key is missing the -pubout
switch that tells the rsa utility to output a public key. So, this
command should look like : openssl rsa -in rsaprivatekey.pem -out
rsapublickey.pem -pubout . Without it, it will just output the private
key as is.

Moreover, the openssl rsa utility saves the public key using the
function PEM_write_bio_RSA_PUBKEY and not PEM_write_bio_RSAPubicKey. So,
if you want your program to be compatible with its output, then you
should use PEM_write_bio_RSA_PUBKEY and PEM_read_bio_RSA_PUBKEY for
saving/loading public key files.

I hope this will help,
--
Mounir IDRASSI
IDRIX
http://www.idrix.fr

On 2/18/2011 4:59 AM, David Henry wrote:

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

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: RSA public/private keys only work when created programatically.

David Henry-6
Thanks for the response, but adding the -pubout switch did not change anything. Actually, I had already been using it, but forgot to type it in my email. Just to make sure though, I recreated the keys and tried again with:

> openssl genrsa -out rsaprivatekey.pem 2048
> openssl rsa -in rsaprivatekey.pem -out rsapublickey.pem -pubout

I copied and pasted them from the command line this time to make sure I didn't miss anything. But the problem remains; my programatically-created keys work, but my command line-created keys do not. I don't understand how this can be.

Dave

On Thu, Feb 17, 2011 at 10:41 PM, Mounir IDRASSI <[hidden email]> wrote:
Hi,

Your command line that create the public key is missing the -pubout switch that tells the rsa utility to output a public key. So, this command should look like : openssl rsa -in rsaprivatekey.pem -out rsapublickey.pem -pubout . Without it, it will just output the private key as is.

Moreover, the openssl rsa utility saves the public key using the function PEM_write_bio_RSA_PUBKEY and not PEM_write_bio_RSAPubicKey. So, if you want your program to be compatible with its output, then you should use PEM_write_bio_RSA_PUBKEY and PEM_read_bio_RSA_PUBKEY for saving/loading public key files.

I hope this will help,
--
Mounir IDRASSI
IDRIX
http://www.idrix.fr


On 2/18/2011 4:59 AM, David Henry wrote:
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;
}



______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: RSA public/private keys only work when created programatically.

David Henry-6
Solved. Thanks, Mounir. Changing my PEM_read_bio_RSA_PublicKey() to PEM_read_bio_RSA_PUBKEY() did the trick. I don't understand why there are two of these, but I'm new to OpenSSL, so I won't complain about that which I don't sufficiently understand.

Dave

On Fri, Feb 18, 2011 at 10:15 AM, David Henry <[hidden email]> wrote:
Thanks for the response, but adding the -pubout switch did not change anything. Actually, I had already been using it, but forgot to type it in my email. Just to make sure though, I recreated the keys and tried again with:

> openssl genrsa -out rsaprivatekey.pem 2048

> openssl rsa -in rsaprivatekey.pem -out rsapublickey.pem -pubout

I copied and pasted them from the command line this time to make sure I didn't miss anything. But the problem remains; my programatically-created keys work, but my command line-created keys do not. I don't understand how this can be.

Dave


On Thu, Feb 17, 2011 at 10:41 PM, Mounir IDRASSI <[hidden email]> wrote:
Hi,

Your command line that create the public key is missing the -pubout switch that tells the rsa utility to output a public key. So, this command should look like : openssl rsa -in rsaprivatekey.pem -out rsapublickey.pem -pubout . Without it, it will just output the private key as is.

Moreover, the openssl rsa utility saves the public key using the function PEM_write_bio_RSA_PUBKEY and not PEM_write_bio_RSAPubicKey. So, if you want your program to be compatible with its output, then you should use PEM_write_bio_RSA_PUBKEY and PEM_read_bio_RSA_PUBKEY for saving/loading public key files.

I hope this will help,
--
Mounir IDRASSI
IDRIX
http://www.idrix.fr


On 2/18/2011 4:59 AM, David Henry wrote:
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;
}



______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]


Reply | Threaded
Open this post in threaded view
|

RE: RSA public/private keys only work when created programatically.

Dave Thompson-5
> From: [hidden email] On Behalf Of David Henry
> Sent: Friday, 18 February, 2011 11:51

> Solved. Thanks, Mounir. Changing my PEM_read_bio_RSA_PublicKey()
> to PEM_read_bio_RSA_PUBKEY() did the trick. I don't understand why
> there are two of these, but I'm new to OpenSSL, so I won't complain
> about that which I don't sufficiently understand.

PEM_write,read*_RSAPublicKey and also i2d,d2i_RSAPublicKey write and
read an encoding specific for and limited to RSA keys defined by PKCS#1.
Similarly *_DSAPublicKey use a specific encoding for DSA (and DH) and
*_ECPublicKey for EC(DSA/DH).

write,read,i2d,d2i_RSA,etc_PUBKEY use the generic encoding from X.509
for SubjectPublicKeyInfo, which combines an OID stating the algorithm,
an alg-dependent piece containing the key/algorithm 'parameters'
if separate from the key proper (e.g. for DSA/DH you can have P,Q,G
in parameters and only Y as the key) or NULL if no such parameters,
then the key (also alg-dependent). RSA has no parameters (NULL).

write,read,i2d,d2i_PUBKEY use the generic encoding to handle any
(supported) algorithm in a generic EVP_PKEY structure. Since your code
is using EVP_* (as recommended), you could support other algorithms
with I believe no code changes other than reading the key(s).
Plus generating/managing different keys but that can be external.

In fact d2i_RSA_PUBKEY just calls d2i_PUBKEY and if the result alg
is RSA returns the RSA 'part'. Similarly for other algs and PEM_read.

For PEM files you can see the difference in the label. The first form
are "BEGIN RSA PUBLIC KEY", "BEGIN DSA PUBLIC KEY" etc. The second form
are "BEGIN PUBLIC KEY" and if you asn1parse it you see it has near the
beginning an 'OBJECT' (OID) which is rsaEncryption or dsaEncryption etc.

There is a similar choice on the private-key side, where there are
specific encodings for each algorithm, and a PKCS#8 generic encoding.



______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [hidden email]
Automated List Manager                           [hidden email]