Itchy
Itchy

Reputation: 2414

How can I store passwords securely in Operating Systems "default" Key-Store?

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

Answers (2)

Denis Stafichuk
Denis Stafichuk

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.

How to store passwords in Windows, Linux or macOS

There is the Java Keyring library. It stores passwords in:

  1. Keychain on macOS
  2. Credential Manager on Windows
  3. DBus Secret Service on GNOME

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

J&#246;rg
J&#246;rg

Reputation: 958

  1. 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.

  2. 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

Related Questions