PKCS12 containing only encrypted RSA private key

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

PKCS12 containing only encrypted RSA private key

Giacomo Boccardo
Hi,

    what I need is to create a PKCS#12 containing an encrypted PKCS#8
RSA private key using a store password different from the key password.
I'd prefer avoiding to alter the JDK adding policy files.

I produced the following code using a JDK8 without any additional policy
and BC 1.57 but I have some issues:

1) the code fails at (B) with an error which suggests I should add
policies to the JDK...but I created the P12 without those policies, so I
don't understand why I can't read it back...

java.lang.ExceptionInInitializerError
    at javax.crypto.Mac.getInstance(Mac.java:176)
    at
sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2039)
    at java.security.KeyStore.load(KeyStore.java:1445)
[OMISSIS]
Caused by: java.lang.SecurityException: Can not initialize cryptographic
mechanism
    at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:88)
    ... 27 more
Caused by: java.lang.SecurityException: Cannot locate policy or
framework files!
    at
javax.crypto.JceSecurity.setupJurisdictionPolicies(JceSecurity.java:255)
    at javax.crypto.JceSecurity.access$000(JceSecurity.java:48)
    at javax.crypto.JceSecurity$1.run(JceSecurity.java:80)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:77)
    ... 27 more

2) if I try to read the p12 using OpenSSL and the import password
"storePassword" the result is

$ /usr/local/Cellar/openssl/1.0.2l/bin/openssl pkcs12 -info -in /tmp/a.p12
Enter Import Password:
MAC Iteration 1024
MAC verified OK
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024
Bag Attributes: <Empty Attributes>
Error outputting keys and certificates
140736555361288:error:06065064:digital envelope
routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:531:
140736555361288:error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12
cipherfinal error:p12_decr.c:108:
140736555361288:error:2306A075:PKCS12
routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:p12_decr.c:139:

3) if I change at (A) the password to "storePassword" I can read the p12
properly using OpenSSL using "storePassword" both for "Import password"
and "PEM pass phrase" but the JUnit still fails as in 1).


What's wrong with this approach?


    @Test
    public void testPKCS12() throws Exception {
        final String keyPassword = "keyPassword";
        final String storePassword = "storePassword";

        final KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        final KeyPair keyPair = keyPairGenerator.genKeyPair();

        final ByteArrayOutputStream pkcs12OS = new ByteArrayOutputStream();

        // (A)
        final PKCS12SafeBagBuilder keyBagBuilder = new
JcaPKCS12SafeBagBuilder(keyPair.getPrivate(),
                new
BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
new CBCBlockCipher(new DESedeEngine())).build(keyPassword.toCharArray()));

        final PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
        pfxPduBuilder.addData(keyBagBuilder.build());

        final PKCS12PfxPdu pkcs12PfxPdu = pfxPduBuilder.build(new
BcPKCS12MacCalculatorBuilder(), storePassword.toCharArray());
        pkcs12OS.write(pkcs12PfxPdu.getEncoded(ASN1Encoding.DL));
        pkcs12OS.close();
        final byte[] pkcs12BA = pkcs12OS.toByteArray();

        FileUtils.writeByteArrayToFile(new File("/tmp/a.p12"), pkcs12BA);

        final KeyStore ks = KeyStore.getInstance("PKCS12");

        // (B)
        ks.load(new ByteArrayInputStream(pkcs12BA),
storePassword.toCharArray());

        final String alias = ks.aliases().nextElement();

        final RSAPrivateKey privateKey = (RSAPrivateKey)
ks.getKey(alias, keyPassword.toCharArray());

        System.out.println(privateKey.getPrivateExponent());
    }


Thanks in advance,

    Giacomo


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: PKCS12 containing only encrypted RSA private key

Giacomo Boccardo
Oops, forget about the error related to point 1): when I restored JDK
policies to the default ones I made a terrible mistake :-)

So the only issue is that I can't read the P12 using OpenSSL when the
key password differs from the store password.

Is it an OpenSSL limit or I created something strange considering that
usually a P12 with a private key requires a certificate chain?


Giacomo Boccardo wrote on 10/07/2017 23:31:

> Hi,
>
>     what I need is to create a PKCS#12 containing an encrypted PKCS#8
> RSA private key using a store password different from the key password.
> I'd prefer avoiding to alter the JDK adding policy files.
>
> I produced the following code using a JDK8 without any additional policy
> and BC 1.57 but I have some issues:
>
> 1) the code fails at (B) with an error which suggests I should add
> policies to the JDK...but I created the P12 without those policies, so I
> don't understand why I can't read it back...
>
> java.lang.ExceptionInInitializerError
>     at javax.crypto.Mac.getInstance(Mac.java:176)
>     at
> sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2039)
>     at java.security.KeyStore.load(KeyStore.java:1445)
> [OMISSIS]
> Caused by: java.lang.SecurityException: Can not initialize cryptographic
> mechanism
>     at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:88)
>     ... 27 more
> Caused by: java.lang.SecurityException: Cannot locate policy or
> framework files!
>     at
> javax.crypto.JceSecurity.setupJurisdictionPolicies(JceSecurity.java:255)
>     at javax.crypto.JceSecurity.access$000(JceSecurity.java:48)
>     at javax.crypto.JceSecurity$1.run(JceSecurity.java:80)
>     at java.security.AccessController.doPrivileged(Native Method)
>     at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:77)
>     ... 27 more
>
> 2) if I try to read the p12 using OpenSSL and the import password
> "storePassword" the result is
>
> $ /usr/local/Cellar/openssl/1.0.2l/bin/openssl pkcs12 -info -in /tmp/a.p12
> Enter Import Password:
> MAC Iteration 1024
> MAC verified OK
> PKCS7 Data
> Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024
> Bag Attributes: <Empty Attributes>
> Error outputting keys and certificates
> 140736555361288:error:06065064:digital envelope
> routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:531:
> 140736555361288:error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12
> cipherfinal error:p12_decr.c:108:
> 140736555361288:error:2306A075:PKCS12
> routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:p12_decr.c:139:
>
> 3) if I change at (A) the password to "storePassword" I can read the p12
> properly using OpenSSL using "storePassword" both for "Import password"
> and "PEM pass phrase" but the JUnit still fails as in 1).
>
>
> What's wrong with this approach?
>
>
>     @Test
>     public void testPKCS12() throws Exception {
>         final String keyPassword = "keyPassword";
>         final String storePassword = "storePassword";
>
>         final KeyPairGenerator keyPairGenerator =
> KeyPairGenerator.getInstance("RSA");
>         keyPairGenerator.initialize(1024);
>         final KeyPair keyPair = keyPairGenerator.genKeyPair();
>
>         final ByteArrayOutputStream pkcs12OS = new ByteArrayOutputStream();
>
>         // (A)
>         final PKCS12SafeBagBuilder keyBagBuilder = new
> JcaPKCS12SafeBagBuilder(keyPair.getPrivate(),
>                 new
> BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
> new CBCBlockCipher(new DESedeEngine())).build(keyPassword.toCharArray()));
>
>         final PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
>         pfxPduBuilder.addData(keyBagBuilder.build());
>
>         final PKCS12PfxPdu pkcs12PfxPdu = pfxPduBuilder.build(new
> BcPKCS12MacCalculatorBuilder(), storePassword.toCharArray());
>         pkcs12OS.write(pkcs12PfxPdu.getEncoded(ASN1Encoding.DL));
>         pkcs12OS.close();
>         final byte[] pkcs12BA = pkcs12OS.toByteArray();
>
>         FileUtils.writeByteArrayToFile(new File("/tmp/a.p12"), pkcs12BA);
>
>         final KeyStore ks = KeyStore.getInstance("PKCS12");
>
>         // (B)
>         ks.load(new ByteArrayInputStream(pkcs12BA),
> storePassword.toCharArray());
>
>         final String alias = ks.aliases().nextElement();
>
>         final RSAPrivateKey privateKey = (RSAPrivateKey)
> ks.getKey(alias, keyPassword.toCharArray());
>
>         System.out.println(privateKey.getPrivateExponent());
>     }
>
>
> Thanks in advance,
>
>     Giacomo
>
>


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: PKCS12 containing only encrypted RSA private key

Giacomo Boccardo
In reply to this post by Giacomo Boccardo
I managed to read the P12 produced using the two different passwords using OpenSSL adding the option "-twopass"

ijhack:security jhack$ /usr/local/Cellar/openssl/1.0.2l/bin/openssl pkcs12 -info -in /tmp/a.p12 -twopass
Enter MAC Password: <- storePassword
Enter Import Password: <- keyPassword
MAC Iteration 1024
MAC verified OK
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024
Bag Attributes: <Empty Attributes>
Key Attributes: <No Attributes>
Enter PEM pass phrase: <- keyPassword
Verifying - Enter PEM pass phrase: <- keyPassword
-----BEGIN ENCRYPTED PRIVATE KEY-----
[OMISSIS]
-----END ENCRYPTED PRIVATE KEY-----

I know this is BC mailing list and not OpenSSL's one, but I have to express my frustration (:D) because:
  • that option has a description — "prompt for separate integrity and encryption passwords: most software always assumes these are the same so this option will render such PKCS#12 files unreadable" — which seems related to the creation of a P12 while it's listed under "PARSING OPTIONS";
  • I don't understand why I need to pass that option (can't OpenSSL just prompt for passwords the same way it does without that option?);
  • I have to enter keyPassword three (3!) times, while just one time would be sufficient.

I hope this thread will help someone else :-)

Giacomo


Giacomo Boccardo wrote on 10/07/2017 23:48:
Oops, forget about the error related to point 1): when I restored JDK
policies to the default ones I made a terrible mistake :-)

So the only issue is that I can't read the P12 using OpenSSL when the
key password differs from the store password.

Is it an OpenSSL limit or I created something strange considering that
usually a P12 with a private key requires a certificate chain?


Giacomo Boccardo wrote on 10/07/2017 23:31:
Hi,

    what I need is to create a PKCS#12 containing an encrypted PKCS#8
RSA private key using a store password different from the key password.
I'd prefer avoiding to alter the JDK adding policy files.

I produced the following code using a JDK8 without any additional policy
and BC 1.57 but I have some issues:

1) the code fails at (B) with an error which suggests I should add
policies to the JDK...but I created the P12 without those policies, so I
don't understand why I can't read it back...

java.lang.ExceptionInInitializerError
    at javax.crypto.Mac.getInstance(Mac.java:176)
    at
sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2039)
    at java.security.KeyStore.load(KeyStore.java:1445)
[OMISSIS]
Caused by: java.lang.SecurityException: Can not initialize cryptographic
mechanism
    at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:88)
    ... 27 more
Caused by: java.lang.SecurityException: Cannot locate policy or
framework files!
    at
javax.crypto.JceSecurity.setupJurisdictionPolicies(JceSecurity.java:255)
    at javax.crypto.JceSecurity.access$000(JceSecurity.java:48)
    at javax.crypto.JceSecurity$1.run(JceSecurity.java:80)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.crypto.JceSecurity.<clinit>(JceSecurity.java:77)
    ... 27 more

2) if I try to read the p12 using OpenSSL and the import password
"storePassword" the result is

$ /usr/local/Cellar/openssl/1.0.2l/bin/openssl pkcs12 -info -in /tmp/a.p12
Enter Import Password:
MAC Iteration 1024
MAC verified OK
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024
Bag Attributes: <Empty Attributes>
Error outputting keys and certificates
140736555361288:error:06065064:digital envelope
routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:531:
140736555361288:error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12
cipherfinal error:p12_decr.c:108:
140736555361288:error:2306A075:PKCS12
routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error:p12_decr.c:139:

3) if I change at (A) the password to "storePassword" I can read the p12
properly using OpenSSL using "storePassword" both for "Import password"
and "PEM pass phrase" but the JUnit still fails as in 1).


What's wrong with this approach?


    @Test
    public void testPKCS12() throws Exception {
        final String keyPassword = "keyPassword";
        final String storePassword = "storePassword";

        final KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        final KeyPair keyPair = keyPairGenerator.genKeyPair();

        final ByteArrayOutputStream pkcs12OS = new ByteArrayOutputStream();

        // (A)
        final PKCS12SafeBagBuilder keyBagBuilder = new
JcaPKCS12SafeBagBuilder(keyPair.getPrivate(),
                new
BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,
new CBCBlockCipher(new DESedeEngine())).build(keyPassword.toCharArray()));

        final PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder();
        pfxPduBuilder.addData(keyBagBuilder.build());

        final PKCS12PfxPdu pkcs12PfxPdu = pfxPduBuilder.build(new
BcPKCS12MacCalculatorBuilder(), storePassword.toCharArray());
        pkcs12OS.write(pkcs12PfxPdu.getEncoded(ASN1Encoding.DL));
        pkcs12OS.close();
        final byte[] pkcs12BA = pkcs12OS.toByteArray();

        FileUtils.writeByteArrayToFile(new File("/tmp/a.p12"), pkcs12BA);

        final KeyStore ks = KeyStore.getInstance("PKCS12");

        // (B)
        ks.load(new ByteArrayInputStream(pkcs12BA),
storePassword.toCharArray());

        final String alias = ks.aliases().nextElement();

        final RSAPrivateKey privateKey = (RSAPrivateKey)
ks.getKey(alias, keyPassword.toCharArray());

        System.out.println(privateKey.getPrivateExponent());
    }


Thanks in advance,

    Giacomo




Loading...