KeyStore getKey() returning null in Android - java

I'm using this code to store a key into a KeyStore in an Android App:
SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
DESKeySpec keySpec = new DESKeySpec(key); // byte[] key
SecretKey skey = kf.generateSecret(keySpec);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, "ksPassword".toCharArray());
PasswordProtection pass = new PasswordProtection(
"entryPassword".toCharArray());
KeyStore.SecretKeyEntry skEntry = new KeyStore.SecretKeyEntry(skey);
ks.setEntry("keyAlias", skEntry, pass);
FileOutputStream fos = ctx.getApplicationContext().openFileOutput("bs.keystore",
Context.MODE_PRIVATE);
ks.store(fos, ksPassword);
fos.close();
Then, in another method, I use this code to retrieve the key I stored,
FileInputStream fis = ctx.getApplicationContext().openFileInput("bs.keystore");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fis, "ksPassword".toCharArray());
Key k = (SecretKey) ks.getKey(keyAlias, "entryPassword".toCharArray());
fis.close();
but the instruction ks.getKey("keyAlias", "entryPassword".toCharArray()) returns null.
Where am I wrong?

Ok, I finally understood the problem...
I used the method to store more than a key in the keystore. Using the code ks.load(null, "ksPassword".toCharArray()); the previous key was erased each time (because loading an empty keystore) and only the last one was stored on the keystore.
So the correct code is:
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
try {
FileInputStream fis = ctx.getApplicationContext().openFileInput("bs.keystore");
ks.load(fis, ksPassword);
} catch(FileNotFoundException e) {
ks.load(null, ksPassword);
}
The first time that the method is executed the file bs.keystore does not exist, so the code in the catch block is executed. Instead in the next calls the file exists and the new key is added to the keystore.

Related

Working with Java.io.file, when ever I try to read a cert from it it always points to wrong path

I am trying to read a cert with file IO , every time I try accessing my cert under
testApp/src/main/resources -> cert
it always reads
X:\workspace1\testApp\target\classes\cert\test.p12
And here is my code that I am using, It always exceptions out with null pointer.
// String fileName = "config/sample.txt";
ClassLoader classLoader = App2.class.getClassLoader();
File file = new File(classLoader.getResource("cert/test.p12").getFile());
FileInputStream fm = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance("PKCS12");
try {
ks.load(fm, "test".toCharArray());
}
catch(Exception e) {
e.printStackTrace();
}
Key key = ks.getKey("test", "test".toCharArray());
Certificate cert = ks.getCertificate("test");
PublicKey publicKey = cert.getPublicKey();
System.out.println("Public key");
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
fm.close();
I want to read this cert to extract public or private key.
this worked for me
File file = new File(classLoader.getResource("./cert/test.p12").getFile());

The system cannot find the file specified trying to create .jks file

I'm currently learning encryption/decryption techniques in Java and one major problem I have come across is storing the key in a .jks file and being able to load it in during different launches. In my calling class it calls the constructor and this is the code for it:
public Encrypt_Decrypt() throws NoSuchAlgorithmException, NoSuchPaddingException
{
Cipher cipher = Cipher.getInstance("AES");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
ivSpec = ivParams;
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
byte[] keyBytes = secretKey.getEncoded();
SecretKeySpec sks = new SecretKeySpec(keyBytes, "AES");
key = sks;
KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection("password".toCharArray());
try
{
File f = new File("keystore.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
java.io.FileInputStream fis = null;
try
{
fis = new java.io.FileInputStream("keystore");
}
finally
{
if (fis != null)
{
fis.close();
}
}
keyStore.load(fis, "password".toCharArray());
keyStore.setEntry("key", entry, protParam);
try (FileOutputStream fout = new FileOutputStream(f))
{
keyStore.store(fout, "password".toCharArray());
;
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
After launching this code in the calling class, this is the error it returns:
keystore (The system cannot find the file specified)
In my code I create the file so why is it having an issue? I looked in my project folder and it is not being saved there so what do I have to do to be able to create, store and use this file without issues?
The keystore (The system cannot find the file specified) message relates to this line:
new java.io.FileInputStream("keystore");
It looks like that should have been using the File f? Something similar to how the FileOutputStream is handled just below works well:
try (FileInputStream fis = new FileInputStream(f)) {
keyStore.load(fis, "password".toCharArray());
}
For reference, there's another error waiting there. Trying to store the AES symmetric key in the JKS keystore results in this error:
java.security.KeyStoreException: Cannot store non-PrivateKeys
at sun.security.provider.JavaKeyStore.engineSetKeyEntry(JavaKeyStore.java:258)
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 KeystoreTest.main(KeystoreTest.java:44)
This is because the JKS storetype only supports public/private keys - also here.
With a new JCEKS keystore instead, your example code then worked fine:
File f = new File("keystore.jceks");
KeyStore keyStore = KeyStore.getInstance("JCEKS");

How does one correctly create and access a KeyStore in java to store an encryption key?

I've been mixing and matching code, trying to learn by example for using KeyStores.
I have this createKeyStore method:
private static KeyStore createKeyStore(String fileName, String pw) throws Exception
{
File file = new File(fileName);
final KeyStore keyStore = KeyStore.getInstance("JCEKS");
if (file.exists())
{
// .keystore file already exists => load it
keyStore.load(new FileInputStream(file), pw.toCharArray());
}
else
{
// .keystore file not created yet => create it
keyStore.load(null, null);
keyStore.store(new FileOutputStream(fileName), pw.toCharArray());
}
return keyStore;
}`
It seems to work, no errors are thrown.
I am then trying to access the code by:
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream(keystorePath), pass.toCharArray());
String alias = "alias";
char[] password = pass.toCharArray();
Certificate cert = keystore.getCertificate(alias);
keystore.setCertificateEntry(alias, cert);
// Save the new keystore contents
FileOutputStream out = new FileOutputStream(keystoreFile);
keystore.store(out, password);
out.close();
But my call to keystore.load throws an Invalid Keystore Format exception.
I tried to replace the FileInputStream with null, but it seems to throw an error setting the certificate.
TL;DR: I am only trying to store a few encryption keys in this keystore, but I can't seem to access it correctly.
Thanks for reading!
You have:
final KeyStore keyStore = KeyStore.getInstance("JCEKS");
and
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
Change these so they agree.
This:
Certificate cert = keystore.getCertificate(alias);
keystore.setCertificateEntry(alias, cert);
is pointless. If there wasn't such a certificate in the keystore, it will fail, and if there was, it will just replace it with itself. What's the point exactly?
I tried to replace the FileInputStream with null
I cannot imagine why. There's nothing in the Javadoc that suggests that will work.
If you look at the documentation it says to create an empty keystore call the load() method with null as the file input parameter but not the password parameter. Passing null as the password parameter in your else clause causes null pointer exceptions when loading the keystore from file later.
keystore.load(null, pass.toCharArray());

How to convert pkcs8 to pkcs12 in Java

I know this is possible with openssl.
But I wonder if there are PKCS converting possibilities(pkcs8 to 12) in Java using any library.
First you read PKCS#8 encoded key as a file and create PrivateKey object
public PrivateKey loadPrivateKey(String keyFile)
throws Exception {
File f = new File(keyFile);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
Then this key is being saved into PKCS#12 key store
public void createKeyStore(String keyStorePwd, String keyStoreFile,
PrivateKey privateKey, X509Certificate certificate)
throws Exception {
char[] pwd = keyStorePwd.toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, pwd);
KeyStore.ProtectionParameter protParam =
new KeyStore.PasswordProtection(pwd);
Certificate[] certChain =
new Certificate[]{ certificate };
KeyStore.PrivateKeyEntry pkEntry =
new KeyStore.PrivateKeyEntry(privateKey, certChain);
ks.setEntry("keypair", pkEntry, protParam);
FileOutputStream fos = new FileOutputStream(keyStoreFile);
ks.store(fos, pwd);
fos.close();
}

How to store and load keys using java.security.KeyStore class

After creating secret keys, how do I store them using the Keystore class' methods and how do I load the keys?
Storing:
KeyStore ks = KeyStore.getInstance("JKS");
ks.setKeyEntry("keyAlias", key, passwordForKeyCharArray, certChain);
OutputStream writeStream = new FileOutputStream(filePathToStore);
ks.store(writeStream, keystorePasswordCharArray);
writeStream.close();
Note thet certChain might be null, unless you are passing PrivateKey
Loading:
KeyStore ks = KeyStore.getInstance("JKS");
InputStream readStream = new FileInputStream(filePathToStore);
ks.load(readStream, keystorePasswordCharArray);
Key key = ks.getKey("keyAlias", passwordForKeyCharArray);
readStream.close();
Read the javadocs
EDIT:
Note that if you are storing a SecretKey or using any part of the SunJCE provider (Java Cryptography Extension), you will need to set your KeyStore type to JCEKS.
KeyStore ks = KeyStore.getInstance("JCEKS");
I had a situation where I didn't know the key alias name, but I knew there was only one key was there in the keystore. I used the following code to load the key (after loading the keystore as shown above):
Enumeration<String> aliases = keyStore.aliases();
String alias = aliases.nextElement();
KeyStore.PrivateKeyEntry keyEnt = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias,
new KeyStore.PasswordProtection(keystorePass.toCharArray()));
PrivateKey privateKey = keyEnt.getPrivateKey();
I have added a post on my blog with details of how to load the private key, public key and how to use them.

Categories

Resources