I have a Java keystore file using the storetype JCEKS. It contains SecretKeyEntry entries. I would like to be able to dump, from the command line, the actual secret keys stored in this file. I tried this:
keytool -list -keystore secretkeys.jks -storetype JCEKS
which returned
Keystore type: JCEKS
Keystore provider: SunJCE
Your keystore contains 1 entry
secret1, May 27, 2016, SecretKeyEntry
But that does not show me the key itself. How can I extract and look at, from the command line, the secret key?
This is not possible with keytool.
Converting the keystore to PKCS#12 and then using OpenSSL to view the key doesn't work either, because this is a symmetric key (SecretKeyEntry).
If you are stuck with the command line, you could write a small Java program that does it. Something like this:
String fileName = "secretkey.ks";
char[] password = "mypassword".toCharArray();
String alias = "secret1";
KeyStore ks = KeyStore.getInstance("JCEKS");
try (FileInputStream fis = new FileInputStream(fileName)) {
ks.load(fis, password);
SecretKey secretKey = (SecretKey) ks.getKey(alias, password);
System.out.println(new BigInteger(1, secretKey.getEncoded()).toString(16));
}
This prints out the secret key as a hex string (toString() with radix 16).
Or you could use the GUI program KeyStore Explorer.
Related
I have got a passphrase protected PEM key file generated by OpenSSL
openssl genrsa -aes128 -passout stdin -out testfile.pem
I have also generated a public key file using OpenSSL
openssl rsa -in testfile.pem -out testfile_pub.pub ( propts for password)
I would like to be able to use this private key to sign my claims etc. and then send requests. What I am struggling to understand (or more like confirming my understanding about) are the following:
1) My private key is password protected, does it mean no one can actually generate the public key without unlocking it first? i.e. that's where the protection is?
2) If I was to read this encrypted private key PEM file in Java, I would have to do something similar to:
\\ 1. Read file as string
\\ 2. Replace all boring bits e.g. begin/end/rsa/private/public/key/enc/--
\\ 3. decode using Base64
\\ 4. read as PKCS8 keyspec and generate PrivateKey object
but doesn't this mean that no one is actually stopping me from reading the keyspecs ? I guess what I am trying to compare with is how we generate JKS keys with optional keypass/storepass. But may be I am not supposed to compare this.
Could anyone help me understand?
Thanks,
openssl rsa -in testfile.pem -out testfile_pub.pub does not export the public key, it actually exports the private key out in clear text (if you provided the correct password). To export the public key use the -pubout option.
Yes you will need the password to export the public key.
To import the private key in Java you will need to convert it to PKCS8 first:
openssl pkcs8 -topk8 -in testfile.pem -inform pem -out testfile_pkcs8.pem -outform pem
Then you can import it in Java like:
String encrypted = new String(Files.readAllBytes(Paths.get("testfile_pkcs8.pem")));
encrypted = encrypted.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", "");
encrypted = encrypted.replace("-----END ENCRYPTED PRIVATE KEY-----", "");
EncryptedPrivateKeyInfo pkInfo = new EncryptedPrivateKeyInfo(Base64.decode(encrypted));
PBEKeySpec keySpec = new PBEKeySpec("mypassword".toCharArray()); // password
SecretKeyFactory pbeKeyFactory = SecretKeyFactory.getInstance(pkInfo.getAlgName());
PKCS8EncodedKeySpec encodedKeySpec = pkInfo.getKeySpec(pbeKeyFactory.generateSecret(keySpec));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey encryptedPrivateKey = keyFactory.generatePrivate(encodedKeySpec);
No, it doesn't mean that anyone can read the key, because you still have to provide the password.
I am trying to store my own secret key in PKCS12 keystore. I tried by using below code:
char[] passArray = "password".toCharArray();// this is key store pass
String key = "test123"; // this is my own secret key
// Loading a Keystore
KeyStore p12KeyStore = KeyStore.getInstance("PKCS12");
p12KeyStore.load(new FileInputStream("testKeyStore.p12"), passArray);
Storing my own secret key like as shown below:
byte [] byteKey = key.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "DSA");
KeyStore.SecretKeyEntry secret = new KeyStore.SecretKeyEntry(keySpec);
KeyStore.ProtectionParameter password = new KeyStore.PasswordProtection(passArray);
p12KeyStore.setEntry("secret-key", secret, password);
but i am not sure whether storing the my own secret key as per best practice or not. and also when trying to get my own key from keystore as it is not getting like as my original secret key.
Key eKey = p12KeyStore.getKey("secret-key", passArray);
Can anyone please help me on this to store & get my own secret in PKCS12 keystore?
Are you sure the code you have above worked? Because DSA is a asymmetric algorithm, not a symmetric algorithm. If you are sure it is a secret key, it has to be AES or DES or DESede (Triple DES). Your above code should have failed.
And answers to your questions:
Just like databases stores data, keys (secret keys and key pairs) and certificates are meant to be stored in a keystore, that's where they should residing in your application. You should be referring/retrieving them from the keystore.
And from what you said in one of the statements, that the key is different from what you had originally when you stored and then retrieved, judging by this, I think the key you have is a Triple DES or a DES key. DES/TripleDES uses parity bits, and the parity bits are corrected by the Java API SecretKeySpec. This causes the key to look different from the original, but it is actually the same. You can read more about the parity bits here.
And as a best practice you shouldn't be storing the secret keys in a PKCS12 Keystore. The internet standard defines that the PKCS12 keystore should contain only one KeyPair entry associated with its certificate chain. Even though it can contain more than one entry, it is ideal to have only one entry, with the key password same as the keystore password. They can store secret keys too, but it is best if you store them in a JCEKS keystore format.
I am trying to do the AES encryption/decryption in java
I generated the secretkey using KeyGenerator. I stored the key using java keystore.
Key myKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection("secretpass".toCharArray());
//For writing the secret Key
KeyStore.SecretKeyEntry skEntry =
new KeyStore.SecretKeyEntry((SecretKey)myKey);
FileOutputStream fout = new FileOutputStream("test.ks");
KeyStore ksout = KeyStore.getInstance("JCEKS");
ksout.load(null,"changeit".toCharArray());
ksout.setEntry("secretalias", skEntry, protParam);
I wanted to get this secretkey from this file using openssl programatically. Is it possible? If so, please give me some suggestions on how do I proceed.
Thank you in advance.
This is not possible as the default keystore (jks) is a proprietary format used by Java.
To exchange the key you would need something portable like PKCS#11 (which is a supported KeyStore format at least in Java 8).
As the title suggests, I have .p12 file required for google service account api access. In order to get the credential to connect to the api, there's a field .setServiceAccountPrivateKey(PrivateKey privateKey). So, what's the easiest way in which I can do this? I have a resources folder which is in my classpath so if I add the p12 file there, I can get the resource from getClass().getResource() as either an inputStream or a URL. I've tried the URL method but it doesn't work (I get a "URI is not hierarchical" error trying to create a File object from URL.toURI()).
You can load your .p12 file using the ClassLoader.getResourceAsStream(String) method, load it to a KeyStore and them get the key from the KeyStore.
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(this.getClass().getClassLoader().getResourceAsStream("keyFile.p12"), p12Password.toCharArray());
PrivateKey key = (PrivateKey)keystore.getKey(keyAlias, p12Password.toCharArray());
ClassLoader.getResourceAsStream(String) loads resources from any location provided they're already on the classpath, there's no need to specify a path to the file.
keyAlias is the name of the entry in your p12 file that corresponds to the private key. PKCS12 files can contain multiple entries, so you need some way to indicate which entry you want to access. The alias is how this is achieved.
If you're not sure what the alias for your private key is, you can use the keytool utility from the command line to list the contents of your p12 file. This tool is included with all JRE and JDK installations.
keytool -list -keystore keyFile.p12 -storepass password -storetype PKCS12
Output
Keystore type: PKCS12
Keystore provider: SunJSSE
Your keystore contains 1 entry
yourKeyAlias, Sep 4, 2013, PrivateKeyEntry,
Certificate fingerprint (MD5): 48:A8:C4:12:8E:4A:8A:AD:58:81:26:90:E7:3D:C8:04
I think it's easier to call Google's SecurityUtils directly, e.g.:
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(), this.getClass().getResourceAsStream("keyFile.p12"), "notasecret", "privatekey", "notasecret")
It's one-line and you don't have to worry about aliasing.
If you get null from getKey() (eg. you are using BouncyCastle as a provider) you should find the last keyAlias element:
KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
keystore.load(this.getClass().getClassLoader().getResourceAsStream("keyFile.p12"), p12Password.toCharArray());
Enumeration aliases = keystore.aliases();
String keyAlias = "";
while (aliases.hasMoreElements()) {
keyAlias = (String) aliases.nextElement();
}
PrivateKey key = (PrivateKey)keystore.getKey(keyAlias, pass);
The above suggestions did not work for me. Then I tried the one at http://www.java2s.com/Code/Java/Security/RetrievingaKeyPairfromaKeyStore.htm and it worked. Copy pasting it below
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
public class Main {
public static void main(String[] argv) throws Exception {
FileInputStream is = new FileInputStream("your.keystore");
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, "my-keystore-password".toCharArray());
String alias = "myalias";
Key key = keystore.getKey(alias, "password".toCharArray());
if (key instanceof PrivateKey) {
// Get certificate of public key
Certificate cert = keystore.getCertificate(alias);
// Get public key
PublicKey publicKey = cert.getPublicKey();
// Return a key pair
new KeyPair(publicKey, (PrivateKey) key);
}
}
}
We are using SunMSCAPI to retrieve the current user keystore as below..
keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
We will need to build a JSSE keystore of type JKS/PKCS12 and pass it to an app..
Sort of beginning to understand how this works.. Any help would be appreciated.
Did you try something like
keystore.load(inputStreamFromOriginalFile, password);
KeyStore keystore2 = KeyStore.getInstance("JKS");
for (String name : toIterable(keystore.aliases())) {
Entry entry = keystore.getEntry(name, protParam);
keystore2.setEntry(name, entry, protParam);
}
keystore2,store(outputStream, password);
I mean a dump copy of all entries into a new keystore2.