OpenPGP KeyStore in Java

The KeyStore class defined by DidiSoft OpenPGP Library for Java is composite storage for OpenPGP public and private keys.

  KeyStore class
+-----------------------------------------------------+
| getKey(userID/hex keyId/keyId) : KeyPairInformation |
| getKeys() : KeyPairInformation[]                    |
| generate...                                         |
| import...                                           |
| export...                                           |
+-----------------------------------------------------+

In addition, the file-based KeyStore protects the keys with a password.

NOTE: The com.didisoft.pgp.KeyStore class is not to be confused with the standard Java(tm)KeyStore

In this chapter, we are going to introduce the basic operations with an OpenPGP KeyStore.

Table of contents:

1. Create/open a KeyStore

Memory-based KeyStore

A KeyStore located in-memory can be used for temporary key storage. If the persistence of its contents is required, a manual call to KeyStore.store must be invoked.

import com.didisoft.pgp.KeyStore;
...
// create empty in-memory located KeyStore
KeyStore keyStore1 = new KeyStore();
KeyStore keyStore2 = KeyStore.getInstance();

File-based KeyStore

A KeyStore can be created with file storage and by default, each operation that modifies its state, like importing keys, generating keys, etc. is persisted automatically. A file-based KeyStore is stored encrypted with AES-256 bit key derived from the provided password.

The code lines below show how to create file-based KeyStore :

import com.didisoft.pgp.KeyStore;
...
// creates new or opens existing file based KeyStore
KeyStore keyStore = new KeyStore("mypgp.keystore", "keystore password");

NOTE: You may notice that no file is created after calling the file based constructor. In fact, the file will be created after the first key is imported or generated.

Custom KeyStore back-end

As of version 3.2.1 a new constructor is available that allows custom back-end storage.

1
2
3
4
// saves the keys in unprotected format
KeyStore(IKeyStoreStorage storage);
// saves the keys encrypted with AES-256 bit key password
KeyStore(IKeyStoreStorage storage, String password);

A KeyStore created with the above constructors will persist its state automatically. An implementation of IKeyStoreStorage must provide only two methods – one for initial loading of the KeyStore and another one invoked on each occasion when the KeyStore must be persisted.

1
2
3
4
public interface IKeyStoreStorage {
	InputStream getInputStream() throws IOException; 
	void store(InputStream data, int length) throws IOException;
}

More information and sample code can be found in the Knowledge Base article Custom storage for the Java OpenPGP KeyStore class

An example implementation that uses a database BLOB column for persisting a KeyStore can be found in the distribution ZIP file/Examples/storage/BlobKeyStorage.java

Protecting KeyStore password in-memory

As of version 3.1.3 of the library, an additional constructor method has been added to provide a custom key for encrypting the KeyStore password in-memory. A real-world implementation will usually obtain that key from a configuration file, but the example below just returns a hard-coded value. For more information, please refer to the article regarding the Heap Inspection issue.

1
2
3
4
5
KeyStore ks = new KeyStore("my.keystore", "password", new ICustomKeyListener() {			
	public byte[] getKey(Object sender) {
		return new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14. 15, 16 };
	}
});

Naming convention

There is no naming convention for KeyStore files. We prefer the file name extension *.keystore, but you can choose your own.

2. Importing keys

Please check the chapter for importing keys for detailed examples.

3. Exporting keys

Please check the chapter for exporting keys for detailed examples.

4. Generating keys

Depending on the asymmetric key algorithm used in the key, three types of keys can be created:
RSA based keys
DH/DSS based keys
Elliptic Curve keys

5. Listing contained keys

The example below illustrates how to list the contents of a KeyStore in the console, with a similar output as the one produced by GnuPG (gpg –list-keys) and PGP(r) (pgp –list-keys)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import com.didisoft.pgp.*;
 
public class KeystoreListKeys {
 public static void main(String[] args) 
  throws java.IO.IOException, PGPException {	
    KeyStore keyStore = new KeyStore("/DataFiles/pgp.keystore", "changeit");		
 
    System.out.print("Type | Size | Key ID | User ID");
 
    KeyPairInformation[] keys = keyStore.getKeys();
    for (int i=0; i < keys.length; i++) {
	KeyPairInformation pair = keys[i];            
	System.out.print(pair.getAlgorithm());
	System.out.print(pair.getKeySize());
	System.out.print(pair.getKeyIDHex());
	for (int j=0; j < pair.getUserIDs().length; j++) {
		System.out.print(pair.getUserIDs()[j]);
	}           			
	System.out.println();
  }		
 }	
}

6. Password probing

Sometimes we may want to check the password of a KeyStore before opening it:

boolean isPasswordProtected = KeyStore.isPasswordProtected("c:\\openpgp.keystore");
boolean passwordIsCorrect = KeyStore.checkPassword("c:\\openpgp.keystore", "password");

7. Changing the password of the KeyStore

The password of the KeyStore storage can be changed at runtime with KeyStore.setPassword.

KeyStore keyStore = new KeyStore("/DataFiles/pgp.keystore", "changeit");
keyStore.setPassword("new password");
keyStore.save(); // explicit save in order to apply the new password

8. Searching for a key

We can check is there a key with a given Key Id or User ID in a KeyStore instance:

  KeyStore keyStore = new KeyStore("pgp.keystore", "changeit");
  boolean keyExists1 = keyStore.containsKey("demo@didisoft.com");
  boolean keyExists2 = keyStore.containsKey("0AC2389B");

Summary

In this chapter we have discussed the basic operations with the KeyStore object exposed by DidiSoft OpenPGP Library for Java.

List of methods used:

KeyStore() constructor for an in-memory KeyStore
KeyStore(fileName, password) constructor for a file based KeyStore
getKeys() returns array of KeyPairInformation instances for the contained keys
checkPassword(fileName, password) checks is a given password the correct one for a keystore file
setPassword(new_password) sets a new password for the keystore file
containsKey(userId) checks is there a key with the given User ID