Read Secretkey from JCEKS keystore | Java - java

I am trying to read secret key (passphrase) from JCEKS keystore using Java code , code is working for JKS keystore but not for JCEKS keystore. i am using ibm_sdk71 as runtime (due to project requirements).
public static String getPasswordFromKeystore(String entry, String keystoreLocation, String keyStorePassword,String keyPP1) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, InvalidKeySpecException, java.security.UnrecoverableEntryException{
char[] password = "new".toCharArray() ;
FileInputStream fIn = new FileInputStream(keystoreLocation);
KeyStore.PasswordProtection keyStorePP = new KeyStore.PasswordProtection(keyStorePassword.toCharArray());
KeyStore.PasswordProtection keyPP = new KeyStore.PasswordProtection(keyPP1.toCharArray());
KeyStore ks= KeyStore.getInstance("JCEKS");
ks.load(fIn, keyStorePassword.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBE");
KeyStore.SecretKeyEntry ske;
ske = (KeyStore.SecretKeyEntry)ks.getEntry(entry, keyPP);
PBEKeySpec keySpec;
keySpec = (PBEKeySpec)factory.getKeySpec(ske.getSecretKey(),PBEKeySpec.class);
password = keySpec.getPassword();
return new String(password);
}
Appreciate any guidance.
Regards

Related

java.security.KeyStoreException: Cannot store non-PrivateKeys

I have generated a keypair of Public-private keys, and am trying to store the privatekey in Java keyStore.
But I am getting error everytime.
My piece of code:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair pair = keyGen.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String ss = Base64.encodeBase64String(cipher.doFinal(ppp.getBytes("UTF-8")));
System.out.println(ss);
// Creating the KeyStore object
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// Loading the KeyStore object
char[] ksPassword = "changeit".toCharArray();
String path = "C:/Program Files/Java/jre1.8.0_201/lib/security/cacerts";
java.io.FileInputStream fis = new FileInputStream(path);
keyStore.load(fis, ksPassword);
// Creating the KeyStore.ProtectionParameter object
KeyStore.ProtectionParameter protectionParam = new
KeyStore.PasswordProtection(ksPassword);
// Creating SecretKey object
SecretKey mySecretKey = new SecretKeySpec(ppp.getBytes(), "RSA");
// Creating SecretKeyEntry object
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(mySecretKey);
keyStore.setEntry("mykeyalias", secretKeyEntry, protectionParam);
// Storing the KeyStore object
java.io.FileOutputStream fos = null;
fos = new java.io.FileOutputStream("newKeyStoreName");
keyStore.store(fos, ksPassword);
But i'm getting below exception at the line keyStore.setEntry while running:
java.security.KeyStoreException: Cannot store non-PrivateKeys
at sun.security.provider.JavaKeyStore.engineSetKeyEntry(JavaKeyStore.java:261)
at sun.security.provider.JavaKeyStore$JKS.engineSetKeyEntry(JavaKeyStore.java:56)
at java.security.KeyStoreSpi.engineSetEntry(KeyStoreSpi.java:550)
at sun.security.provider.KeyStoreDelegator.engineSetEntry(KeyStoreDelegator.java:179)
at sun.security.provider.JavaKeyStore$DualFormatJKS.engineSetEntry(JavaKeyStore.java:70)
at java.security.KeyStore.setEntry(KeyStore.java:1557)
at com.sprint.neo.bc4j.util.TestMain.StoringKeys(TestMain.java:33)
Can anyone help to resolve this issue so that I can store Privatekeys to the java keyStore along with an alias name, to be used later. Where is the exact wrong in the above piece of code. Thanks a lot.

Java Key Store always ends up with null aliases

I've been trying on this for a couple of days and I'm hopelessly stuck.
To fully understand how java key store works, i've been trying to create my own keystore, put some stuff inside it, then retrieve them from another program.
Here's my keystore generator :
{
//generate a X509 certificate
Security.addProvider(new BouncyCastleProvider());
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream("certificate.cer"));
LOGGER.debug("BouncyCastle provider & X509 certificate added.");
//generate a private & a public key
KeyPair keyPair = generateRSAKeyPair();
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic();
//generate a keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = "keystore_password".toCharArray();
ks.load(null, keyStorePassword);
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
ks.store(fos, keyStorePassword);
}
ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);
//Symmetric key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);
//Asymmetric key
X509Certificate[] x509Certificates = new X509Certificate[1];
x509Certificates[0] = certificate;
ks.setKeyEntry("asymmetric key", priv, keyStorePassword, x509Certificates);
//certificate
ks.setCertificateEntry("test_certif", certificate);
Key key = ks.getKey("symmetric_key", keyStorePassword);
System.out.println("I have this symmetric key : " + key);
X509Certificate certificate1 = (X509Certificate) ks.getCertificate("test_certif");
System.out.println("I have this certificate : " + certificate1);
System.out.println(ks.aliases().nextElement());
LOGGER.debug("all went well");
}
As you probably noticed, it's not all polished: my goal for now is only to put some stuff inside the keystore. But the point here, from the last System.out.println(ks.aliases().nextElement());, is just to see there is indeed something inside the keystore. And this is working just fine, it gives back symmetric_key.
Now, from the same folder is another class that is supposed to read from that keystore.
Note: there is no issue regarding the file (I've tested by moving its localization) so it can't be that.
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = "keystore_password".toCharArray();
ks.load(new FileInputStream("TestKeyStore.jks"), keyStorePassword);
System.out.println(ks.containsAlias("symmetric_key"));
This always gets me: false
If I try this: System.out.println(ks.aliases());, it's always null
If I try this:
if (!keystore.aliases().hasMoreElements()) {
System.out.println("nothing inside the keystore");
}
it gives me back nothing inside the keystore.
Even though it's not the case in the generator.
Any clue?
Thank you
The problem is that you are setting the entries after writing the keystore.
If you move:
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.jks")) {
ks.store(fos, keyStorePassword);
}
Till after this line:
ks.setCertificateEntry("test_certif", certificate);
Everything should work fine.
Bellow you have an working example with some code removed for clarity:
public static void main(String[] args) throws Exception{
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
final KeyPair keyPair = keyGen.genKeyPair();
RSAPrivateKey priv = (RSAPrivateKey) keyPair.getPrivate();
//generate a keystore
KeyStore ks = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = PASSWORD;
ks.load(null, keyStorePassword);
X509Certificate[] chain = {generateCertificate("cn=Unknown", keyPair, 365, "SHA256withRSA")};
// saving one keypair in keystore object
ks.setKeyEntry("asymmetric key", keyPair.getPrivate(), keyStorePassword, chain);
//Symmetric key
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry((secretKey));
KeyStore.ProtectionParameter protectionParameter = new KeyStore.PasswordProtection(keyStorePassword);
// saving symmetric key in keystore object
ks.setEntry("symmetric_key", secretKeyEntry, protectionParameter);
// Saving our keystore object into the filesystem
try (FileOutputStream fos = new FileOutputStream("TestKeyStore.p12")) {
ks.store(fos, keyStorePassword);
}
// The rest of the code
}
The reason why it works in the method that saves the keystore is because the changed keystore is still in memory, but not on the filesystem. Also, since you are creating a PKCS12 keystore, I would avoid the .jks extension and go for something like .pkcs12.

getKey(alias, keyPassword) returns null value for secret key when calling from separate method

I am trying to retrieve a stored key in java key store. I have written the following code.
public class clientEncryptionUtility
{
public static void generateKeyAndStoreOnKeyStore(String _keyStorePassword, String _keyStorePath, String _keyPassword, String keyAlias) throws Exception // take the keystore path, alias, password
{
KeyStore keyStore = KeyStore.getInstance("JCEKS");
char[] keyStorePassword = _keyStorePassword.toCharArray();
String path = _keyStorePath;
FileInputStream fis = new FileInputStream(path);
//load keystore
keyStore.load(fis, keyStorePassword);
//Loading the KeyStore object
KeyStore.ProtectionParameter protectionParam = new KeyStore.PasswordProtection(keyStorePassword);
//Generate the symmetric key for encryption
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
int keyBitSize = 128;
keyGenerator.init(keyBitSize, secureRandom);
SecretKey secretKey = keyGenerator.generateKey(); //Secret encryption key is genereated
//setting the password for the key stored in keystore
System.out.println("Algorithm used to generate key : "+secretKey.getAlgorithm());
char[] keyPassword = _keyPassword.toCharArray();
KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(keyPassword);
KeyStore.SecretKeyEntry secretKeyEntry = new KeyStore.SecretKeyEntry(secretKey);
keyStore.setEntry(keyAlias, secretKeyEntry, entryPassword);
SecretKey newSecretKey = (SecretKey) keyStore.getKey(keyAlias, keyPassword);
String stringKey = newSecretKey.toString();
System.out.println("The encryption key at the alias is: " + stringKey);
}
public static void getKeyFromKeyStore(String _keyStorePassword, String _keyStorePath, String keyAlias, String _keyPassword) throws Exception
{
KeyStore keyStore = KeyStore.getInstance("JCEKS");
char[] keyStorePassword = _keyStorePassword.toCharArray();
String path = _keyStorePath;
FileInputStream fis = new FileInputStream(path);
//load keystore
keyStore.load(fis, keyStorePassword);
char[] keyPassword = _keyPassword.toCharArray();
SecretKey secretKey = (SecretKey) keyStore.getKey(keyAlias, keyPassword);
// Key key = keyStore.getKey(keyAlias, keyPassword);
String stringKey = secretKey.toString();
System.out.println("The encryption key at the alias is: " + stringKey);
}
}
-If I call the generateKeyAndStoreOnKeyStore() method, and store the key and retrieve the key in the same function, the key is retrieved.
-However if I do the same from another method getKeyFromKeyStore() wherein I am just trying to retrieve the key at the alias from the keystone, I get a nullPointerException.
-Where am I going wrong?
Unfortunately it's not clear from the javadocs that you must call the KeyStore.store(...) method to persist changes to the keystore. Once generateKeyAndStoreOnKeyStore() exits, the KeyStore instance created there goes out of scope and any unsaved changes made to the keystore disappear.
Call the KeyStore.store(...) method after making changes.

Storing AES Secret key using keystore in java

I am using Java keystore to store the secret key for AES encryption.
final String strToEncrypt = "Hello World";
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey sk = kg.generateKey();
String secretKey = String.valueOf(Hex.encodeHex(sk.getEncoded()));
//Storing AES Secret key in keystore
KeyStore ks = KeyStore.getInstance("JCEKS");
char[] password = "keystorepassword".toCharArray();
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream("keyStoreName");
ks.load(fis, password);
} finally {
if (fis != null) {
fis.close();
}
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection(password);
KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(sk);
ks.setEntry("secretKeyAlias", skEntry, protParam);
But i am getting following Exception.
Exception in thread "main" java.security.KeyStoreException: Uninitialized keystore
at java.security.KeyStore.setEntry(Unknown Source)
How to fix this error? Thanks in advance
According to the KeyStore documentation ,
Before a keystore can be accessed, it must be loaded.
so you are loading the KeyStore but what if a FileNotFoundException occures at
fis = new java.io.FileInputStream("keyStoreName"); , hence if file does not exist we load the KeyStore with null values ,like , ks.load(null,null); .

Generate certificate chain in java

The question is how to generate certificate chains programmatically in Java. In other words, I would like to perform in java the operations detailed here: http://fusesource.com/docs/broker/5.3/security/i382664.html
Besically, I can create the RSA keys for a new client:
private KeyPair genRSAKeyPair(){
// Get RSA key factory:
KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
log.error(e.getMessage());
e.printStackTrace();
return null;
}
// Generate RSA public/private key pair:
kpg.initialize(RSA_KEY_LEN);
KeyPair kp = kpg.genKeyPair();
return kp;
}
and I generate the corresponding certificate:
private X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm)
throws GeneralSecurityException, IOException {
PrivateKey privkey = pair.getPrivate();
X509CertInfo info = new X509CertInfo();
Date from = new Date();
Date to = new Date(from.getTime() + days * 86400000l);
CertificateValidity interval = new CertificateValidity(from, to);
BigInteger sn = new BigInteger(64, new SecureRandom());
X500Name owner = new X500Name(dn);
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));
// Sign the cert to identify the algorithm that's used.
X509CertImpl cert = new X509CertImpl(info);
cert.sign(privkey, algorithm);
// Update the algorith, and resign.
algo = (AlgorithmId)cert.get(X509CertImpl.SIG_ALG);
info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
cert = new X509CertImpl(info);
cert.sign(privkey, algorithm);
return cert;
}
Then I generate the cert signing request and I save it to csrFile file:
public static void writeCertReq(File csrFile, String alias, String keyPass, KeyStore ks)
throws KeyStoreException,
NoSuchAlgorithmException,
InvalidKeyException,
IOException,
CertificateException,
SignatureException,
UnrecoverableKeyException {
Object objs[] = getPrivateKey(ks, alias, keyPass.toCharArray());
PrivateKey privKey = (PrivateKey) objs[0];
PKCS10 request = null;
Certificate cert = ks.getCertificate(alias);
request = new PKCS10(cert.getPublicKey());
String sigAlgName = "MD5WithRSA";
Signature signature = Signature.getInstance(sigAlgName);
signature.initSign(privKey);
X500Name subject = new X500Name(((X509Certificate) cert).getSubjectDN().toString());
X500Signer signer = new X500Signer(signature, subject);
request.encodeAndSign(signer);
request.print(System.out);
FileOutputStream fos = new FileOutputStream(csrFile);
PrintStream ps = new PrintStream(fos);
request.print(ps);
fos.close();
}
where
private static Object[] getPrivateKey(KeyStore ks, String alias, char keyPass[])
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException {
key = null;
key = ks.getKey(alias, keyPass);
return (new Object[]{ (PrivateKey) key, keyPass });
}
Now I should sign the CSR with the CA private key, but I cannot see how to achive that in java. I have "my own" CA private key in my jks.
Besides, once I manage to sign the CSR I should chain the CA cert with the signed CSR: how that can be done in java?
I would prefer not to use bc or other external libs, just "sun.security" classes.
Thank you.
I believe the code example in the post http://www.pixelstech.net/article/1406726666-Generate-certificate-in-Java----2 will show you how to generate certificate chain with pure Java. It doesn't require you to use Bouncy Castle.
Sorry, but despite your desires, and besides writing all of your crypto code and including it with your project (not recommended), I'd recommend using Bouncy Castle here.
Specifically, please refer to https://stackoverflow.com/a/7366757/751158 - which includes code for exactly what you're looking to do.
I see you've already gone over to the BouncyCastle side of the house but just in case anyone else was wondering; you can add the cert chain to the entry when putting the key into the KeyStore. For example
// build your certs
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load([keystore stream], password.toCharArray());// or null, null if it's a brand new store
X509Certificate[] chain = new X509Certificate[2];
chain[0] = _clientCert;
chain[1] = _caCert;
keyStore.setKeyEntry("Alias", _clientCertKey, password.toCharArray(), chain);
keyStore.store([output stream], password.toCharArray());
// do other stuff

Categories