lbalmaceda / PemUtils.java
The PemUtils.java file contains a set of helper methods to read Pem Private or Public Keys from a given file. We make use of it in the tests of our Java-JWT library.
It only makes use of the Bouncy Castle (BC) library’s PemReader and some Security classes from Java 7.
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
Call the readPublicKeyFromFile method passing the path to the file and the algorithm. Algorithm can be one of «RSA» or «EC».
RSAKey pubRSA = (RSAKey) PemUtils.readPublicKeyFromFile("/path/to/rsa/key.pem", "RSA"))); ECKey pubEC = (ECKey) PemUtils.readPublicKeyFromFile("/path/to/ec/key.pem", "EC")));
Call the readPrivateKeyFromFile method passing the path to the file and the algorithm. Algorithm can be one of «RSA» or «EC».
RSAKey privRSA = (RSAKey) PemUtils.readPrivateKeyFromFile("/path/to/rsa/key.pem", "RSA"))); ECKey privEC = (ECKey) PemUtils.readPrivateKeyFromFile("/path/to/ec/key.pem", "EC")));
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//Copyright 2017 — https://github.com/lbalmaceda |
//Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the «Software»), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
//The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
//THE SOFTWARE IS PROVIDED «AS IS», WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
package com . auth0 . jwt ; |
import org . bouncycastle . util . io . pem . PemObject ; |
import org . bouncycastle . util . io . pem . PemReader ; |
import java . io . File ; |
import java . io . FileNotFoundException ; |
import java . io . FileReader ; |
import java . io . IOException ; |
import java . security . KeyFactory ; |
import java . security . NoSuchAlgorithmException ; |
import java . security . PrivateKey ; |
import java . security . PublicKey ; |
import java . security . spec . EncodedKeySpec ; |
import java . security . spec . InvalidKeySpecException ; |
import java . security . spec . PKCS8EncodedKeySpec ; |
import java . security . spec . X509EncodedKeySpec ; |
public class PemUtils |
private static byte [] parsePEMFile ( File pemFile ) throws IOException |
if (! pemFile . isFile () || ! pemFile . exists ()) |
throw new FileNotFoundException ( String . format ( «The file ‘%s’ doesn’t exist.» , pemFile . getAbsolutePath ())); |
> |
PemReader reader = new PemReader ( new FileReader ( pemFile )); |
PemObject pemObject = reader . readPemObject (); |
byte [] content = pemObject . getContent (); |
reader . close (); |
return content ; |
> |
private static PublicKey getPublicKey ( byte [] keyBytes , String algorithm ) |
PublicKey publicKey = null ; |
try |
KeyFactory kf = KeyFactory . getInstance ( algorithm ); |
EncodedKeySpec keySpec = new X509EncodedKeySpec ( keyBytes ); |
publicKey = kf . generatePublic ( keySpec ); |
> catch ( NoSuchAlgorithmException e ) |
System . out . println ( «Could not reconstruct the public key, the given algorithm could not be found.» ); |
> catch ( InvalidKeySpecException e ) |
System . out . println ( «Could not reconstruct the public key» ); |
> |
return publicKey ; |
> |
private static PrivateKey getPrivateKey ( byte [] keyBytes , String algorithm ) |
PrivateKey privateKey = null ; |
try |
KeyFactory kf = KeyFactory . getInstance ( algorithm ); |
EncodedKeySpec keySpec = new PKCS8EncodedKeySpec ( keyBytes ); |
privateKey = kf . generatePrivate ( keySpec ); |
> catch ( NoSuchAlgorithmException e ) |
System . out . println ( «Could not reconstruct the private key, the given algorithm could not be found.» ); |
> catch ( InvalidKeySpecException e ) |
System . out . println ( «Could not reconstruct the private key» ); |
> |
return privateKey ; |
> |
public static PublicKey readPublicKeyFromFile ( String filepath , String algorithm ) throws IOException |
byte [] bytes = PemUtils . parsePEMFile ( new File ( filepath )); |
return PemUtils . getPublicKey ( bytes , algorithm ); |
> |
public static PrivateKey readPrivateKeyFromFile ( String filepath , String algorithm ) throws IOException |
byte [] bytes = PemUtils . parsePEMFile ( new File ( filepath )); |
return PemUtils . getPrivateKey ( bytes , algorithm ); |
> |
> |
How can I export my private key from a Java Keytool keystore?
I would like to export my private key from a Java Keytool keystore, so I can use it with openssl. How can I do that?
5 Answers 5
Use Java keytool to convert from JKS to P12.
Export from keytool ‘s proprietary format (called «JKS») to standardized format PKCS #12:
keytool -importkeystore \ -srckeystore keystore.jks \ -destkeystore keystore.p12 \ -deststoretype PKCS12 \ -srcalias \ -deststorepass \ -destkeypass
. then use openssl to export from P12 to PEM
Export certificate using openssl :
openssl pkcs12 -in keystore.p12 -nokeys -out cert.pem
Export unencrypted private key:
openssl pkcs12 -in keystore.p12 -nodes -nocerts -out key.pem
I did as described in this answer, but somehow my exported private key is just an empty file? What gives?
key.pem starts with Bag Attributes. , which my appliances didn’t like. I had to add an extra command at the end: openssl rsa -in -key.pem -out key2.pem , so that the key would be in the PEM format my appliance required.
Since Java 6, you can import/export private keys into PKCS#12 ( .p12 ) files using keytool , with the option -importkeystore (not available in previous versions).
keytool -importkeystore -srckeystore existing-store.jks -destkeystore new-store.p12 -deststoretype PKCS12
The PKCS12 keystore type is also supported as a standard keystore type in the default Oracle/Sun security provider.
This feels a bit like the old regex adage, where you now have 2 problems. What do you do with this PCKS12 keystore you have? I’d prefer the below answer as it explains both how to export to PCKS12, and also how to actually get the private key from it.
Not entirely made clear elsewhere: convert your java keystore to the newer PKS12 format, instead of the older format. And then you can much more robustly deal with moving private keys around. keytool works fine with keystores in PKS12 format thereafter. Use the -importkeystore invocation given above, and then use the output file everywhere you used it with the original jks file. Or just copy it on top of your old (previously BACKED UP just in case) .jks file.
Try «Keystore Explorer»
I agree with Bruno. Keytool is ultimate tool when dealing with Java keystore, but there is one fancy and quite powerful free tool: Keystore explorer
I use it a lot and never had a need for something else.
Hmm, a Sourceforge site — aren’t they known for injecting malware into downloads? Not sure I’d use a tool from Sourceforge on my keys.
Wish it had a CLI (cmd line interf) thi. The author toyed w/ the idea, bu decided against it. Shame, it does solve many of «keytool»s shortcomings like additionally not supporting access/export of symmetric («secret») keys. These cannot be converted to PKCS12 (format doesn’t support symm keys). There is the JDK «KeyStore» API tho, as @cjbooms pointed out; heck, write ur own «keytool» (that’s what they did).
If anyone finds themselves here trying to get a private key out of a JCEKS type keystore, I found that the keytool and openssl instructions described in other answers did not work. I had to use the below Java class to get the key out.
import sun.misc.BASE64Encoder; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.security.*; public class ExportPrivateKey < private File keystoreFile; private String keyStoreType; private char[] keyStorePassword; private char[] keyPassword; private String alias; private File exportedFile; public void export() throws Exception < KeyStore keystore = KeyStore.getInstance(keyStoreType); BASE64Encoder encoder = new BASE64Encoder(); keystore.load(new FileInputStream(keystoreFile), keyStorePassword); Key key = keystore.getKey(alias, keyPassword); String encoded = encoder.encode(key.getEncoded()); FileWriter fw = new FileWriter(exportedFile); fw.write("---BEGIN PRIVATE KEY---\n"); fw.write(encoded); fw.write("\n"); fw.write("---END PRIVATE KEY---"); fw.close(); >public static void main(String args[]) throws Exception < ExportPrivateKey export = new ExportPrivateKey(); export.keystoreFile = new File(args[0]); export.keyStoreType = args[1]; export.keyStorePassword = args[2].toCharArray(); export.alias = args[3]; export.keyPassword = args[4].toCharArray(); export.exportedFile = new File(args[5]); export.export(); >>
javac ExportPrivateKey.java java ExportPrivateKey JCEKS “”
For any keytool command to use a format other than JKS you must specify it; for -importkeystore add -srcstoretype jceks .
That did exactly what I wanted. Thank you. I created the key: keytool -v -keystore output.p12 -genseckey -storetype PKCS12 -keyalg AES -alias new_aes_key -keysize 256 then I was able to extract the key: java ExportPrivateKey output.p12 pkcs12 password new_aes_key password new.pem
There is a format that allows the moving of private keys is called PKCS#12. This format came later in the evolution of PKI certificates and related keystores as the need evolved. If you consider the chain of trust issues created by accessing and transporting the private key you can see why it was not included in the initial features but rather came after pressure by operational need. This is the core reason for the challenge.
Java keystores were one of the initial users of the PKCS#12 format but as importers not exporters. It appears the security design of Java keystores still does not support exporting private keys as a standard feature. Again, there are good security reasons for this fact. That said, private routines have been written as referenced here: http://www.startux.de/index.php/java/44-dealing-with-java-keystoresyvComment44
If at all possible I would consider creating a new keystore in OpenSSL and new keys rather than trying to pry out the private key from the Java keystore. By opening the Java keystore and extracting the private key one is moving beyond the designed security features. The export PKCS#12 feature has been desired for many years but still is not supported in Java. My thinking is that is for very good cryptologic reasons thus I would be leary of taking that step unless it was absolutely necessary.