Monday, May 21, 2012

RSA Public, Private, and PKCS #8 key parser

OpenSSLKey.cs is a .NET Framework 2.0 console utility which parses either PEM or DER RSA public keys, private keys in both traditional SSLeay and PKCS #8 (both encrypted and unencrypted) forms. Successfully parsed RSA public or private keys are used to create a .NET RSACryptoServiceProvider instance and optionally export to a PKCS #12 file. These RSA key formats are commonly created using OpenSSL and Java 2. This utility is intended to help with RSA asymmetric key interoperability between OpenSSL, .NET and Java environments.
PEM encoded keys must be in one of the following formats:
 -----BEGIN PUBLIC KEY-----
 MIIBIjANBgkqhkiG9w0BAQEF...
 -----END PUBLIC KEY-----

 -----BEGIN RSA PRIVATE KEY-----
 MIICXAIBAAKBgQDfnaXDy9v4q8PfV ...
 -----END RSA PRIVATE KEY-----

 -----BEGIN RSA PRIVATE KEY-----
 Proc-Type: 4,ENCRYPTED
 DEK-Info: DES-EDE3-CBC,379AB79E55059F9A

 gaakm48Y8qYA997fJREN4JtfVkfTdnVzaZK2 ....
 -----END RSA PRIVATE KEY-----

 (PKCS #8 formats)

 -----BEGIN PRIVATE KEY-----
 MIICeAIBADANBgkqhkiG9w0BA ....
 -----END PRIVATE KEY-----

 -----BEGIN ENCRYPTED PRIVATE KEY-----
 MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG .....
 -----END ENCRYPTED PRIVATE KEY-----
Binary DER keys are obtained by removing the header/footer lines and b64 decoding the inner content. (Note that the SSLeay encrypted private key contains the encryption details at the PEM level and therefore cannot be represented in binary DER format). For the SSLeay format, the only supported encryption this utility provides is DES-EDE3-CBC. For the PKCS #8 format, the only algorithm currently supported by this utility is PBEWithHmacSHA1AndDESede (PKCS #5, v 2.0). No assumptions of key size for the RSA keypair are made. The utility was tested with key sizes in the range 1024 to 16,384 bits, the maximum size RSA key supported by the Microsoft RSA Cryptographic Service Providers. The maximum size RSA key supported by Sun's Java 2 JCE provider implementation is only 2048 bits. (Note that currently Java 2 (v 1.5.0_06) does not support PKCS #5 v2 algorithms, but only PBEWithMD5AndDES (PKCS #5, v 1.5) and PBEWithSHA1AndDESede (PKCS#12) )
          Usage:       opensslkey.exe   [V]   
where the V indicates verbose output (all key details for both public and private keys are printed). The application prompts the user for an RSA key file (which can be in either PEM or binary DER formats). The beginning of the file is checked to determine if it is PEM encoded. If PEM encoded, Opensslkey determines if the key is a public or private key based on the header/footer lines. If binary DER encoded, Opensslkey sequentially tries to asn.1 parse the binary content until a match with a supported RSA key format is found (in the order SubjectPublicKeyInfo, RSAPrivateKey, PKCS #8 unencrypted and PKCS #8 encrypted). For PEM RSA Private Key formats, the PEM content is checked for the encryption specifiers "Proc-Type:" and "DEK-Info".
  • For PEM public keys, the key is b64 decoded and the resulting X509 SubjectPublicKeyInfo binary key is asn.1 parsed directly to recover the modulus and exponent data which is used to instantiate a .NET RSACryptoServiceProvider. The public XML key string is then exported and displayed.
  • For the PEM RSA Private Key (RSAPrivateKey format), content between the header/footer lines is checked to see if there is encryption information. If so, the salt is extracted from the "DEK-Info" specifier. The user is prompted for the password used to encrypt the RSA private key. Password data is acquired via keystrokes into a .NET 2 SecureString object. This data is used to derive the 3DES key using the SSLeay implemention of PBKD (using an interation count of 1 and the salt value). The b64 encrypted RSA key is b64 decoded, and decrypted using the recovered 3DES key and salt (used as the IV). Finally, the recovered RSA private key binary is directly asn.1 parsed to recover the RSA key components, MODULUS, E, D, P, Q, DP, DQ, InverseQ. These RSA private key components are used to instantiate an RSACryptoServiceProvider. The XML key is then exported and displayed. Finally, the user is prompted to export the .NET imported private key to a PKCS #12 file. If selected, this process generates a dummy unsigned certificate to encapsulate with the RSA keypair in the PKCS #12 file. The user is prompted for a password to protect the PKCS #12 export.
  • The PKCS #8 unencrypted private key (PrivateKeyInfo format) is simply an asn.1 wrapper around the unencrypted RSA private key above.
    For PKCS #8 encrypted keys (EncryptedPrivateKeyInfo) format, the outer sequences are scanned for the supported format, parsing asn.1 content sequentially to recover the salt, iteration count and IV data. Next, the encrypted PKCS #8 octet blob is recovered, the 3DES key recovered using and .NET 2 support for PBKDF2 in the Rfc2898DeriveBytes class and finally the blob is decrypted with EDE3CBC. In verbose mode, the key parameters are listed. An option to export to a password protected PKCS #12 file concludes the parsing.

Sample console output for 1024 bit RSA key in Encrypted RSAPrivateKey formatSample asn.1 dumps for different RSA keys (dumpasn1.exe) :
PEM formats cheat-sheet
 Download Opensslkey.exe v 1.3.0.0 (40,088 bytes) (.NET 2, Digitally Signed)

No comments: