Skip to main content

Understanding Keystore in Android

When it comes to securing sensitive information in an Android application, encryption plays a vital role. Keystore is a system provided by Android that facilitates encryption of sensitive information such as private keys, passwords, and other secure data. In this article, we will discuss Keystore in Android, how it works, and how to use it in an Android application.

What is Keystore?

Keystore is a system that provides a secure storage for sensitive data in an Android application. It allows developers to generate and store cryptographic keys in a container that is protected by the Android system. The keys stored in the Keystore are secured with a password or PIN, which can only be accessed by the application that created them.

How Keystore works

Keystore works by generating and storing cryptographic keys in a container that is protected by the Android system. These keys are then used to encrypt and decrypt sensitive information in an Android application. The Keystore uses a combination of hardware and software security measures to ensure that the keys are protected from unauthorized access.

When an Android application requires access to a key stored in the Keystore, it must first authenticate itself to the Android system. This is done by passing a password or PIN to the Keystore. Once the application is authenticated, it can access the key and use it to encrypt or decrypt sensitive information.

Using Keystore in an Android Application

Using Keystore in an Android application involves the following steps:

Step 1: Create a Keystore

The first step is to create a Keystore. This can be done using the following code:

val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)

Step 2: Generate a Key Pair

The next step is to generate a key pair. This involves generating a public and private key that can be used for encryption and decryption. This can be done using the following code:

val keyPairGenerator = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"
)

val builder = KeyGenParameterSpec.Builder(
"key_alias",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)

builder.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
builder.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)

keyPairGenerator.initialize(builder.build())
val keyPair = keyPairGenerator.generateKeyPair()

Step 3: Encrypt and Decrypt Data

Once the key pair has been generated, it can be used to encrypt and decrypt sensitive information in the Android application. This can be done using the following code:

val publicKey = keyStore.getCertificate("key_alias").publicKey
val privateKey = keyStore.getKey("key_alias", null) as PrivateKey

val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.ENCRYPT_MODE, publicKey)
val encryptedData = cipher.doFinal("Sensitive information".toByteArray())

cipher.init(Cipher.DECRYPT_MODE, privateKey)
val decryptedData = cipher.doFinal(encryptedData)

Let's now at some more examples.

Example 1: Simple Kotlin Android KeyStore Secure Storage Example

Let's look at simple example step by step.

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

No third party dependency is needed.

Step 3: Design Layout

We will just have a dummy layout:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Write Code

Here is how we obtain a secret key:

    fun getKey(): SecretKey {
val keystore = KeyStore.getInstance("AndroidKeyStore")
keystore.load(null)

val secretKeyEntry = keystore.getEntry("MyKeyAlias", null) as KeyStore.SecretKeyEntry
return secretKeyEntry.secretKey
}

Here is how we encrypt data:

    fun encryptData(data: String): Pair<ByteArray, ByteArray> {
val cipher = Cipher.getInstance("AES/CBC/NoPadding")

var temp = data
while (temp.toByteArray().size % 16 != 0)
temp += "\u0020"

cipher.init(Cipher.ENCRYPT_MODE, getKey())

val ivBytes = cipher.iv
val encryptedBytes = cipher.doFinal(temp.toByteArray(Charsets.UTF_8))

return Pair(ivBytes, encryptedBytes)
}

And here is how we decrypt data:

    fun decryptData(ivBytes: ByteArray, data: ByteArray): String{
val cipher = Cipher.getInstance("AES/CBC/NoPadding")
val spec = IvParameterSpec(ivBytes)

cipher.init(Cipher.DECRYPT_MODE, getKey(), spec)
return cipher.doFinal(data).toString(Charsets.UTF_8).trim()
}

Here is the full code:

MainActivity.kt

import android.os.Bundle
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import androidx.appcompat.app.AppCompatActivity
import java.security.KeyPairGenerator
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.IvParameterSpec

class MainActivity : AppCompatActivity() {

companion object {
val TRANSFORMATION = "AES/GCM/NoPadding"
val ANDROID_KEY_STORE = "AndroidKeyStore"
val SAMPLE_ALIAS = "MYALIAS"
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
val keyGenParameterSpec = KeyGenParameterSpec.Builder("MyKeyAlias",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()

keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey()

val pair = encryptData("Test this encryption")

val decryptedData = decryptData(pair.first, pair.second)

val encrypted = pair.second.toString(Charsets.UTF_8)
println("Encrypted data: $encrypted")
println("Decrypted data: $decryptedData")

}
fun getKey(): SecretKey {
val keystore = KeyStore.getInstance("AndroidKeyStore")
keystore.load(null)

val secretKeyEntry = keystore.getEntry("MyKeyAlias", null) as KeyStore.SecretKeyEntry
return secretKeyEntry.secretKey
}

fun encryptData(data: String): Pair<ByteArray, ByteArray> {
val cipher = Cipher.getInstance("AES/CBC/NoPadding")

var temp = data
while (temp.toByteArray().size % 16 != 0)
temp += "\u0020"

cipher.init(Cipher.ENCRYPT_MODE, getKey())

val ivBytes = cipher.iv
val encryptedBytes = cipher.doFinal(temp.toByteArray(Charsets.UTF_8))

return Pair(ivBytes, encryptedBytes)
}

fun decryptData(ivBytes: ByteArray, data: ByteArray): String{
val cipher = Cipher.getInstance("AES/CBC/NoPadding")
val spec = IvParameterSpec(ivBytes)

cipher.init(Cipher.DECRYPT_MODE, getKey(), spec)
return cipher.doFinal(data).toString(Charsets.UTF_8).trim()
}
}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

NumberLink
1.Download Example
2.Follow code author

Conclusion

In conclusion, Keystore is a system provided by Android that facilitates encryption of sensitive information in an Android application. It allows developers to generate and store cryptographic keys in a container that is protected by the Android system. Using Keystore in an Android application involves creating a Keystore, generating a key pair, and using it to encrypt and decrypt sensitive information. By using Keystore, developers can ensure that sensitive information in their Android applications is protected from unauthorized access.