Search code examples
javax509certificatekeystoreprivate-key

Two different Private Keys


I am trying to digitally sign and then validate an AuthnRequest. I've generated the private key and public key certificate using the following commands:

openssl genrsa -out privatekey.pem 2048
openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 365
openssl pkcs12 -export -out public_privatekey.pfx -inkey privatekey.pem -in publickey.cer

Converted the PFX to JKS by following command:

keytool -importkeystore -srckeystore public_privatekey.pfx -srcstoretype pkcs12 
-destkeystore clientcert.jks -deststoretype JKS

and I am accessing that private key entry and public key certificate using the following java code:

KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keystoreFile), "dps123!@#".toCharArray());

KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("1", new KeyStore.PasswordProtection("dps123!@#".toCharArray()));
java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) keyEntry.getCertificate();

I got to print the private key value to the console by following:

String key = Base64.encode(keyEntry.getPrivateKey().getEncoded());
System.out.println(key);

When I compare the contents of String "key" and the contents in "privatekey.pem" file, both are different. Is it something that I am not understanding correctly or there is a problem getting the private key value in the code?


Solution

  • There are several formats for private key storage. Among them are PKCS#1 and PKCS#8. They differ in encryption algorithms and ASN.1 structure. Also, PKCS#8 supports other key algorithms besides RSA.

    For example this is the ASN.1 dump of the first bytes of an unencrypted PKCS#8 file:

    0000  4BE: SEQUENCE {
    0004    1:   INTEGER 0
    0007    D:   SEQUENCE {
    0009    9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
             :       (PKCS #1)
    0014    0:     NULL
             :     }
    0016  4A8:   OCTET STRING, encapsulates {
    001A  4A4:     SEQUENCE {
    001E    1:       INTEGER 0
    0021  101:       INTEGER    
             :         00 B3 17 E6 31 3C 36 24    ....1<6$
    

    And the same key in PKCS#1 format (again only the first few bytes, the rest of the file is basically the raw key):

    0000  4A4: SEQUENCE {
    0004    1:   INTEGER 0
    0007  101:   INTEGER    
             :     00 B3 17 E6 31 3C 36 24    ....1<6$
    

    This website contains a more detailed explanation of the two formats: https://tls.mbed.org/kb/cryptography/asn1-key-structures-in-der-and-pem

    Java normally generates PKCS#8 format, while OpenSSL supports both formats and can convert between them: https://www.openssl.org/docs/apps/pkcs8.html

    KeyStore Explorer can also generate, process and convert both formats.

    So, if you convert privatekey.pem to PKCS#8 with OpenSSL or KSE, it should look identical to the output of System.out.println(key):

    openssl pkcs8 -topk8 -in privatekey.pem -out privatekey.pkcs8 -nocrypt