Reputation: 6546
Goal: Extract an RSA private key from an encrypted PEM file. The private key will be used to programmatically sign certs.
Environment: Java 8 and Bouncy Castle 1.52
//Register BC as a crypto provider
Security.addProvider(new BouncyCastleProvider());
//Get file handle
String caPrivateKeyFname = "cakey.pem";
FileInputStream fis = null;
try {
fis = new FileInputStream(caPrivateKeyFname);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//Load and parse PEM object
PEMParser pemRd = new PEMParser(new InputStreamReader(fis));
Object objectInPemFile = pemRd.readObject();
//I do not know why BC loads the file as a PKCS8 object. OpenSSL does not recognize it as such.
PKCS8EncryptedPrivateKeyInfo keyInfo = (PKCS8EncryptedPrivateKeyInfo) objectInPemFile;
//Decrypt the private key
String pwd = "secret";
InputDecryptorProvider pkcs8Prov = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(pwd.toCharArray());
//Next statement raises an exception.
PrivateKeyInfo privateKeyInfo = keyInfo.decryptPrivateKeyInfo(pkcs8Prov);
Exception in thread "main" org.bouncycastle.pkcs.PKCSException: unable to read encrypted data: 1.2.840.113549.1.5.13 not available: Illegal key size
at org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(Unknown Source)
at org.codice.ddf.certificate.SignedCertificate.main(SignedCertificate.java:67)
Caused by: org.bouncycastle.operator.OperatorCreationException: 1.2.840.113549.1.5.13 not available: Illegal key size
at org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder$1.get(Unknown Source)
... 2 more
Caused by: java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1060)
at javax.crypto.Cipher.implInit(Cipher.java:809)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1539)
at javax.crypto.Cipher.init(Cipher.java:1470)
... 3 more
openssl asn1parse -in cakey.pem
PBES2
PBKDF2
des-ede3-cbc
If I understand correctly, DES key length is 64 bits, so 3DES is 192 bit keys. However, Java policy limits the length of DES keys to 56 bits, so maximum key length for 3DES is 168 bits.
Switching out the jurisdiction policy files is not an option for me. I think there is a way to decrypt a PKCS8 encrypted private key with Bouncy Castle, but the solution is more involved than setting the provider to BC.
Can anyone point me to an example or provide some reference code?
(Thanks to dave_thompson_085 for his help).
Upvotes: 2
Views: 8229
Reputation: 39000
Yes, a file that begins with the line "-----BEGIN ENCRYPTED PRIVATE KEY-----" is a PEM format PKCS#8 encrypted private key. I don't know why your comment says "OpenSSL does not recognize it"; the fact that openssl rsa
reads it successfullly proves OpenSSL does recognize it.
BC PKCSException
is just a wrapper; your actual problem is java.security.InvalidKeyException: Illegal key size
. This occurs if you try to use better than 128-bit symmetric encryption or (as here) decryption in a JRE that has the default shipped-by-Sun-now-Oracle crypto policy which is limited to 128-bit symmetric. I'll bet you a dollar that openssl asn1parse <cakey.pem
shows the file encrypted with PBES2
using PBKD2
(with some parameters) and aes-192-cbc
or aes-256-cbc
.
Download the "... (JCE) Unlimited Strength Jurisdiction Policy Files for JDK/JRE 8" from the "Additional Resources" section of http://www.oracle.com/technetwork/java/javase/downloads/index.html then unzip and place the two *policy.jar files in the JREHOME/lib/security directory of the JRE you are using. (Assuming you are not under US sanctions because you're in the North Korea, Iran or Syria governments etc.)
Upvotes: 3