copensslrsa

Is it normal that public key generated from private key are different each time?


I have a C source code that generate a 2048 bit RSA key (it's working, no problem with it) :

int main(void)
{
    RSA *lptypRSA = NULL;
    BIGNUM *lptypBIGNUM = NULL;
    BIO *lptypBIOPublic = NULL;
    BIO *lptypBIOPrivate = NULL;

    lptypBIGNUM = BN_new();
    if (lptypBIGNUM == NULL) {
       exit(1);
    }

    if (BN_set_word(lptypBIGNUM, RSA_F4) != 1) {
       exit(2);
    }

    lptypRSA = RSA_new();
    if (lptypRSA == NULL) {
       exit(3);
    }
    
    if (RSA_generate_key_ex(lptypRSA, 2048, lptypBIGNUM, NULL) != 1) {
       exit(4);
    }

    /* Public key generation */
    lptypBIOPublic = BIO_new_file("/some/path/rsa_2048_public.key", "w");
    if (lptypBIOPublic == NULL) {
       exit(5);
    }
    
    if (PEM_write_bio_RSAPublicKey(lptypBIOPublic, lptypRSA) != 1) {
       exit(6);
    }

    /* Private key generation */
    lptypBIOPrivate = BIO_new_file("/some/path/rsa_2048_private.key", "w");
    if (lptypBIOPrivate == NULL) {
       exit(7);
    }
    
    if (PEM_write_bio_RSAPrivateKey(lptypBIOPrivate, lptypRSA, NULL, NULL, 0, NULL, NULL) != 1) {
       exit(8);
    }

    /* Free ressource */
    BIO_free_all(lptypBIOPrivate);
    BIO_free_all(lptypBIOPublic);
    BN_free(lptypBIGNUM);
    RSA_free(lptypRSA);

    exit(0);
}

(My libcrypto version is old (aix5.3) that's why I'm not using EVP_RSA_gen/PEM_write_PUBKEY/PEM_write_PrivateKey). I do a test and end up having those two files :

"/some/path/rsa_2048_private.key" :

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAt4LjnYKRabX6LfPfUi/vhXXJkPryKBtGxvODNkGXZCJViWg+
qmwdhplW0Zcj0hbKD3tscwKzhL/2ghSQcVZ72/PpWGwwHe6tAoSaA31qR6z3+zp3
s/3IFoOXnZa7enNtjZW5rcwxwRED1SZVAoFX3/TcemM8gWOtOMoUcfQjrN2GsonN
E9fO0rp0PQvewfnr6KoPI5jvFi8ssvKqWzzQZXNlpxTP4UlTfTJ+My2aVB1KJe6u
T6xsiQNQPWAu8F6TKrsgMllXh1tBou9X7i8UYEdabhu7kjAsX/V1HqfIJryNu/bM
/qtxAV1Tw0rIrb9shITP5xQDy+EIsjf7IIt1pQIDAQABAoIBAEXWdSMjZo2RaLWG
Qu33OjNTQTOAnRmwT741PDEwwxmji2PwnTCkVpQ71POMjmBMtfcwZHRcic8ycvDM
PLA1Vou9hodVHPa3N3Zm2moLl5/RbspYVOfV5AjVaaTakVyngwDIA1LmC+VKwWej
3+RFLxkXCbU2APfI5EphdWhsngsR2arQDaoUALPF/A0XsAX0QZ6qFKzY1xFBLl3b
gcleiLsBhDetq5a0ucNFQ2oAdMnLOAj7meLVdRTEhGe3gMaXAgt53uQ2bUPlbRT+
AcG2C5fMgIAMgbb4kZbxeUC8DJW3YVtTRA1APwCDZxYshyqOd+B/RjOgh7PbM801
BhH64Z0CgYEA7NXL7TvlJbFEZw8+1cPzzyuTIi/NpWcl1ZIJQT+4CKhBMH/g3YSj
rLQ+nOHOihpjC9cz37/S68RdeS9v8Yc3chGLmW0ifpl9YL40fbwteeR9raimczhA
Fz2A290gagzWefIfiTL37CXukbCD/29GDyZ/+d5Y9X+G/0LPZyaXQg8CgYEAxlxz
uIJ7KrVkcJuPFt+JSHxOCn5V1c9YgH40X7TsqdV1TXTx/xCtpx0ME382czNqOaqB
gMkRs1PRPER+ZPKVL6CnW4QdgqexgahgFp+r17311Bkhy70ePCoHobOHyP7FUCpm
ekh9mTFsEq7Bb1levsErdAMEKh7fNVoCZ7TtcQsCgYAbEwXRBPvZJz6umWuRfGku
0chsLBLSScxlceBk+SfMtY9eQAAw0qzzXVebD6VQ3FteSye++GrgUP5ukCG39sE7
5Q2UaIl894cBvDy78vsv6BMF+zWsDk4lWf6VI95EwVrzbd51DMKS2HNBbHBqjwnv
SXNv2R9KUV3ZaIXVQPAhuQKBgFzKKLPaDcWnvslSa3gWr0CCLXuJJ5vx94N8BgHz
P3YezVWjbASWB7WRx/Fi49S16234TcYxyJ7riYg4vit4ssLp0v/jaG6TBV0Sp4hN
vvQX/2PtMbr9x6P7QUCqG82xKBndC70OJfrAfL6skv4Ef2aaNDp7oroVYPKzHUbo
At6LAoGBAKrHtDG8NdQyCQ1bkI2gKoGrBnKLuR5X0G+k/mElD4V62aw2A03bBu95
TfqPIllJcxX/Zo/blKlNFFyWAKI67jDw5/HvOIckn1/YCwcWY+WJ+jY7pk5T2t03
yqVAiEeS6dynj2MFiN6E0C4YQqkAdCzaHlGYFLWHCGD+Vod1U9KA
-----END RSA PRIVATE KEY-----

"/some/path/rsa_2048_public.key"

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAt4LjnYKRabX6LfPfUi/vhXXJkPryKBtGxvODNkGXZCJViWg+qmwd
hplW0Zcj0hbKD3tscwKzhL/2ghSQcVZ72/PpWGwwHe6tAoSaA31qR6z3+zp3s/3I
FoOXnZa7enNtjZW5rcwxwRED1SZVAoFX3/TcemM8gWOtOMoUcfQjrN2GsonNE9fO
0rp0PQvewfnr6KoPI5jvFi8ssvKqWzzQZXNlpxTP4UlTfTJ+My2aVB1KJe6uT6xs
iQNQPWAu8F6TKrsgMllXh1tBou9X7i8UYEdabhu7kjAsX/V1HqfIJryNu/bM/qtx
AV1Tw0rIrb9shITP5xQDy+EIsjf7IIt1pQIDAQAB
-----END RSA PUBLIC KEY-----

Now, I want to test if I can get the public key from the private key if the public key is lost, so I use this shell command :

openssl rsa -in "/some/path/rsa_2048_private.key" -out "/some/path/rsa_2048_public.key" -pubout

I obtain this :

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt4LjnYKRabX6LfPfUi/v
hXXJkPryKBtGxvODNkGXZCJViWg+qmwdhplW0Zcj0hbKD3tscwKzhL/2ghSQcVZ7
2/PpWGwwHe6tAoSaA31qR6z3+zp3s/3IFoOXnZa7enNtjZW5rcwxwRED1SZVAoFX
3/TcemM8gWOtOMoUcfQjrN2GsonNE9fO0rp0PQvewfnr6KoPI5jvFi8ssvKqWzzQ
ZXNlpxTP4UlTfTJ+My2aVB1KJe6uT6xsiQNQPWAu8F6TKrsgMllXh1tBou9X7i8U
YEdabhu7kjAsX/V1HqfIJryNu/bM/qtxAV1Tw0rIrb9shITP5xQDy+EIsjf7IIt1
pQIDAQAB
-----END PUBLIC KEY-----

What surprise me is that the file content is different, but I still can decrypting with the new public key data that have been encrypted with the original (and now lost) public key.

I don't fully understand how RSA work (I'm not that good with math), but I read that one private key can only have one public key. Yet, I have what appear to be two different public key working with one private key.

Is it normal to not get the exact public key ? If I redo the shell command, I end up with a third public key different from the two first yet still working. I did my test wrong : If I redo a third public file with the shell command, it end up different from the first (generated via C code) but identical to the second (generated via shell)


Solution

  • PEM_write_bio_RSAPublicKey() writes the key in PKCS#1 format:

    -----BEGIN RSA PUBLIC KEY-----
    

    This contains just the modulus (n) and exponent (e);

    openssl rsa -pubout or PEM_write_bio_PUBKEY() writes the key in X.509 SubjectPublicKeyInfo format:

    -----BEGIN PUBLIC KEY-----
    

    This wraps the PKCS#1 blob inside an ASN.1 structure that also includes info about the key algorithm (here, RSA). The base64 blobs differ because their ASN.1 structures differ, but they both contain the same modulus and exponent values. If you decode both, you'll find the same n and e inside.