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:
- Create/open a KeyStore (in-memory, from a file, custom storage)
- Importing keys
- Exporting keys
- Generating keys
- Listing contained keys
- Password check
- Changing the password
- Searching for a key
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 |