For simplicities sake, I created a simple application that demonstrates how the Android Keystore system can be used to save a password, encrypt it, display the encrypted form and decrypt it.

I won't go into any XML/layout details, it is pretty basic stuff. I will be posting the full source code at the end anyway.

Let's jump right into the meat of this thing.

What I did was I created 2 classes. One is called EnCryptor, and the other Decryptor. The names are very self-explanatory.

For this example we will be using the following encryption/decryption transformation algorithm: “AES/GCM/NoPadding”

Creating new keys

Before we can begin the encryption process, we need to come up with a name for an alias we want to use to encrypt/decrypt data with. This can be any string. As long is not an empty one. The alias is the name of the entry in which the generated key will appear in Android KeyStore.

First, we need to get an instance of Androids KeyGenerator.

final KeyGenerator keyGenerator = KeyGenerator

.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");

We are saying that the algorithm we want to use this keygenerator for will be AES, and we want to save the keys/data in the AndroidKeyStore.

Once we have the instance we need to build a KeyGenParameterSpec using the KeyGenParameterSpec.Builder to pass into the KeyGenerators init method.

So what is this KeyGenParameterSpec anyways?

You can think of the KeyGenParameterSpec as the properties for the keys we are going to generate. For example, let's say we wanted the key to expire after a certain amount of time, this is where we would specify that.

He is our KeyGenParameterSpec.

final KeyGenerator keyGenerator = KeyGenerator

.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);

final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias,

KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)

.setBlockModes(KeyProperties.BLOCK_MODE_GCM)

.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)

.build();

So what is this saying?

The first thing is we pass in the alias we want to use. Remember, this can be anything. Next, we specify the purpose, which is to Encrypt and Decrypt data.

The setBlockModes, assures us that only the block modes specified can be used to both encrypt and decrypt the data, if any other type of block mode is used, it will be rejected. You can see the different types of block modes HERE.

Since we are using the “AES/GCM/NoPadding” transformation algorithm, we also tell the KeyGenParameterSpec the type of padding that should be used.

Encrypting data

Time to encrypt the data!

Once we get past all the setup, the encryption part is pretty easy.

final KeyGenerator keyGenerator = KeyGenerator

.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);



final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias,

KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)

.setBlockModes(KeyProperties.BLOCK_MODE_GCM)

.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)

.build();



keyGenerator.init(keyGenParameterSpec);

final SecretKey secretKey = keyGenerator.generateKey();



final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

cipher.init(Cipher.ENCRYPT_MODE, secretKey);

First, we initialize the keyGenerator with the keyGenParameterSpec. After that, we generate our SecretKey.

Now that we have our secret key, we use it to initialize our Cipher object, which is what will be taking care of the actual encryption. We tell the Cipher the type of encryption transformation we will be using, we specify that we are going to be encrypting right now, and we pass in the secretKey to use for the encryption.

final KeyGenerator keyGenerator = KeyGenerator

.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);



final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(alias,

KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)

.setBlockModes(KeyProperties.BLOCK_MODE_GCM)

.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)

.build();



keyGenerator.init(keyGenParameterSpec);

final SecretKey secretKey = keyGenerator.generateKey();



final Cipher cipher = Cipher.getInstance(TRANSFORMATION);

cipher.init(Cipher.ENCRYPT_MODE, secretKey);



iv = cipher.getIV();



encryption = cipher.doFinal(textToEncrypt.getBytes("UTF-8"));

Next, we grab a reference to the ciphers initialization vector (IV), which we will need for decryption, and we finalize the encryption with doFinal(textToEncrypt). The doFinal method returns a byte array which is the actual encrypted text.

Decrypting the data

Initiating the KeyStore

Before we start decrypting, we need an instance of the KeyStore.

keyStore = KeyStore.getInstance("AndroidKeyStore");

keyStore.load(null);

We use the keyStore to get our secret key using the alias we previously used when encrypting the data.

We need a SecretKeyEntry from the keyStore to grab the secretKey from.

keyStore = KeyStore.getInstance("AndroidKeyStore");

keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore

.getEntry(alias, null);



final SecretKey secretKey = secretKeyEntry.getSecretKey();

Remember earlier how we set the KeyGenParameterSpecs block mode to KeyProperties.BLOCK_MODE_GCM, so that only this type of block mode can be used to decrypt the data?

Because of this we need a GCMParameterSpec where we specify an authentication tag length (has to be one of these: 128, 120, 112, 104, 96, you can read more about it in the javadocs. For this example we will go with the highest value of 128), and pass in the IV we grabbed earlier during the encryption process.

We use this GCMParameterSpec with our Cipher to initialize the decryption process

keyStore = KeyStore.getInstance("AndroidKeyStore");

keyStore.load(null); final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore

.getEntry(alias, null);



final SecretKey secretKey = secretKeyEntry.getSecretKey(); final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

final GCMParameterSpec spec = new GCMParameterSpec(128, encryptionIv);

cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);

And like before, to get the decrypted data we do

final byte[] decodedData = cipher.doFinal(encryptedData);

To get the unencrypted string representation, we do

final String unencryptedString = new String(decodedData, "UTF-8");

And we are done!

You can find the full source code HERE

Extra: Fetching all Available aliases from the KeyStore

In order to grab all available aliases, we create a getAllAliasesInTheKeystore() method inside our KeyStoreManager, which returns an array list of all available aliases in the keystore.

private ArrayList<String> getAllAliasesInTheKeystore() throws KeyStoreException {

return Collections.list(keyStore.aliases());

}

keyStore.aliases() is what fetches the aliases from the keystore, which throws an exception if the keystore has not been initialized. It returns an Enumeration of type String with all available aliases. For ease of use, I turn the enumeration into an ArrayList. But you don’t necessarily have to do the same, this is just my personal preference. To do so I use the Collections utils class.