Reputation: 2414
I'm developing a Java client application that connects to a web service. For this web service, I need an authentication secret (password/token/...). How can I store this password securely within the Operating Systems "default" Key-Store System?
(By "default" I mean a standard tool provided by the OS, e.g. on Mac there is a "Keychain Access" application that stores certificates and passwords. Some applications manage to store their passwords there and each time the password is needed the Operating System itself provides a dialog asking for permission. Or on Windows, there is the Data Protection API.)
So far I came across this question about storing certificates and Java's KeyStore class. And managed to write the following:
//Loading the OS default keystore
KeyStore ks = KeyStore.getInstance("KeychainStore", "Apple");
ks.load(null, null);
//Reading keys
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (ks.isKeyEntry(alias)) {
Key key = ks.getKey(alias, "anything".toCharArray()); //this invokes the OS popup
if (key == null) {
System.err.println(alias + " could not be read");
} else {
System.out.println(alias + " (algorithm = " + key.getAlgorithm() + ", format = " + key.getFormat() + ")");
}
}
}
//Writing keys (does not work yet)
String secretExample = "my very secret secret";
SecretKey generatedSecret = SecretKeyFactory.getInstance("PBE").generateSecret(new PBEKeySpec(secretExample.toCharArray()));
ks.setKeyEntry("my.app.Secret", generatedSecret, null, null); //throws java.security.KeyStoreException: Key protection algorithm not found: java.security.KeyStoreException: Key is not a PrivateKey
ks.setKeyEntry("my.app.Secret", secretExample.getBytes(), null); //throws java.security.KeyStoreException: key is not encoded as EncryptedPrivateKeyInfo
With this I can already read some keys but have not been able to write any. The last two lines are my not working possible solutions (each throws a different exception).
I think storing passwords securely is a very general problem. I would like to address it by using the options provided by Operating Systems. How can I do that?
Upvotes: 4
Views: 2323
Reputation: 2782
java.security.KeyStore
was not created to deal with passwords. It is a storage facility for cryptographic keys and certificates. While you can try to use it to store passwords since it can for example store private keys, I would advise you against that, because KeyStore's API is cumbersome as you saw yourself and was not designed for your use case.
There is the Java Keyring library. It stores passwords in:
Here's how to use it:
public static void main(String[] args) throws Exception {
Keyring keyring = Keyring.create();
String serviceName = "test-app";
String accountName = "test-account";
keyring.setPassword(serviceName, accountName, "test-password");
String password = keyring.getPassword(serviceName, accountName);
System.out.println(password);
}
Gradle
implementation 'com.github.javakeyring:java-keyring:1.0.1'
Maven
<dependency>
<groupId>com.github.javakeyring</groupId>
<artifactId>java-keyring</artifactId>
<version>1.0.1</version>
</dependency>
If you want to support desktop environments other than GNOME you would probably have to come up with your own solution or search for a different library, but this should get you started.
Upvotes: 3
Reputation: 958
JKS used to be the standard KeyStore format in Java (till Java 8). It uses quite weak encryption and is limited. E.g. it can not store SecretKey instances. IMHO the apple specific KeyStore or at least the Java access to it has similar limitations.
In case you consider to create a KeyStore independent from OS and use a portable solution instead, you can choose a different format such as PKCS12 or JCEKS. For details see here: http://www.pixelstech.net/article/1408345768-Different-types-of-keystore-in-Java----Overview In that case you should be aware that creating a new KeyStore with Java code is tricky. The easiest way is to use keytool (commandline tool that comes with JDK) to create your initial KeyStore. Then you can easily use load and store methods to load it and save changes. In case you manage to get it working with the OS specific KeyStore you actually do not have to create it as it is already there.
Upvotes: 1