Thursday, March 2, 2017

DECRYPTING PKCS # 8 and OpenSSLPrivate Keys with Java

The code works with Java 1.3 (+JCE), 1.4, 5.0, 6.0, but not all of the ciphers and hashes are available until Java 5.0 (unless you use BouncyCastle). Fortunately the most common formats [OpenSSL MD5 with 3DES], [PKCS #8 V1.5 MD5 with DES], [PKCS #8 V2.0 HmacSHA1 with 3DES] work with all versions of Java, including Java 1.3.
pkcs8 example:

FileInputStream in = new FileInputStream( "/path/to/pkcs8_private_key.der" );

// If the provided InputStream is encrypted, we need a password to decrypt
// it. If the InputStream is not encrypted, then the password is ignored
// (can be null).  The InputStream can be DER (raw ASN.1) or PEM (base64).
PKCS8Key pkcs8 = new PKCS8Key( in, "changeit".toCharArray() );

// If an unencrypted PKCS8 key was provided, then this actually returns
// exactly what was originally passed in (with no changes).  If an OpenSSL
// key was provided, it gets reformatted as PKCS #8 first, and so these
// bytes will still be PKCS #8, not OpenSSL.
byte[] decrypted = pkcs8.getDecryptedBytes();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( decrypted );

// A Java PrivateKey object is born.
PrivateKey pk = null;
if ( pkcs8.isDSA() )
{
  pk = KeyFactory.getInstance( "DSA" ).generatePrivate( spec );
}
else if ( pkcs8.isRSA() )
{
  pk = KeyFactory.getInstance( "RSA" ).generatePrivate( spec );
}

// For lazier types:
pk = pkcs8.getPrivateKey();

Both RSA and DSA keys are supported. Here is a list of supported formats:
  • OpenSSL "Traditional SSLeay Compatible Format"
    • Unencrypted PEM or DER
    • Encrypted PEM:
      • des
      • des2
      • des3
      • blowfish
      • aes128
      • aes192
      • aes256
      • rc2-40
      • rc2-64
      • rc2-128

      Note:
      OpenSSL "traditional SSLeay" format does not allow encrypted keys to be encoded in DER. Only unencrypted keys can be encoded in DER.
  • PKCS #8 (Unencrypted)
    • PEM or DER
  • PKCS #8 with PKCS #5 Version 1.5 Encryption
    • PEM or DER: 
      • MD2 with DES
      • MD2 with RC2-64
      • MD5 with DES
      • MD5 with RC2-64
      • SHA1 with DES
      • SHA1 with RC2-64

  • PKCS #8 with PKCS #5 Version 1.5 Encryption and PKCS #12 Key Derivation
    • PEM or DER: 
      • SHA1 with 3DES
      • SHA1 with 2DES
      • SHA1 with RC2-128
      • SHA1 with RC2-40
      • SHA1 with RC4-128
      • SHA1 with RC4-40

  • PKCS #8 with PKCS #5 Version 2.0 Encryption and HmacSHA1
    • PEM or DER: 
      • DES
      • 3DES
      • Blowfish
      • AES-128
      • AES-192
      • AES-256
      • RC2-40
      • RC2-64
      • RC2-128


Here are links to the raw samples and test results:
  1. 2048 Bit RSA
  2. 2048 Bit DSA

The samples were all generated using OpenSSL's rsagenrsadsagendsadsaparam and pkcs8 commands. We're curious to know if PKCS #8 keys created by other programs will also work, but OpenSSL is all we have to play with at the moment.
The password to decrypt the samples is always "changeit", and they all have the same RSA or DSA key.

http://juliusdavies.ca/commons-ssl/pkcs8.html

No comments:

Man in the Rain