
Secure data in Android — Encryption in Android (Part 2)
This article is a part of “Secure data in Android” series:
- Encryption
- Encryption in Android (Part 1)
- Encryption in Android (Part 2)
- Encrypting Large Data
- Initialization Vector
- Key Invalidation
- Fingerprint
- Confirm Credentials
Those describes the “Secure data in Android” workshop topics. Sample application with full code snippets is available on GitHub.
In previous “Encryption in Android (Part 1)” article we spoke about Java Cryptography Architecture and Android Key Store system. This article will show you how to work with keyguard, how to create and manage cryptographic keys and how to encrypt and decrypt data in Android.
Table of Contents
- Lock Screen
- Choose a Key
- Key Storage
- Key Generation
- Key Management
- Encryption & Decryption
- Usage Example
- Whats Next
- Security Tips
Lock Screen
If you want to secure your data — protect your device.
To be more secure, before providing an access to any of application features, we can request user to setup his device Lock Screen (if it has been not setup yet). Also some other features that we will review later in this series, such as Fingerprint, requires lock screen to be setup.
And there is a special system service — KeyguardManager, that can help us with this task.
isDeviceSecure method— checks if device is secured with a PIN, pattern or password. Available from API 23.
isKeyguardSecure method— checks if keyguard is secured by a PIN, pattern or password or a SIM card is currently locked. Available from API 16. It’s not the best option to use, as it is also checking if a SIM card is locked, but it is totally better then nothing.

Now, in onStart()
of your Activity, simply check if device is secured with lock screen, and if not, show security alert.
Full source code is available here.
Choose a Key
Now, when device is secured with Lock Screen, we can focus on application sensitive data protection, like user Master password and Secrets (see Encryption in Android (Part 1), Sample Project). We already know that encryption will be used for this. And first what we need to do is to choose what Key (symmetric, asymmetric) and Algorithm to use.
Also we know that Symmetric Keys are available from Android 23+ API, and Asymmetric from 18+ API (see Encryption in Android (Part 1), Android Key Store). Our choice is predictable, we will use Asymmetric Keys, but still, what algorithm to chose? Lets search for help in documentation :

RSA — the only one available algorithm we can use, in Cipher
, for Android Key Store Asymmetric Keys, on API 18+ devices.
Key Storage
On Android, cryptographic keys are stored in theKeyStore
:
And there is a fabric getInstance("type")
method, that creates KeyStore
instance with given type by traversing the list of registered security Providers, starting with the most preferred one. We are going to search for “AndroidKeyStore” type.
There’s also another KeyStore
fabric method: getInstance("type", "provider")
—that returns a KeyStore
object of the specified type from the specified Provider.
Basically calling this :
val keyStore = KeyStore.getInstance("AndroidKeyStore")keyStore.provider.name // AndroidKeyStore
keyStore.type // AndroidKeyStore
is pretty the same as calling:
val provider = “AndroidKeyStore”
val keyStore = KeyStore.getInstance(provider, provider)keyStore.provider.name // AndroidKeyStore
keyStore.type // AndroidKeyStore
But note, if there are more then one registered types in different Providers, with the same name, getInstance(“type”)
method will return you the first matching result among of them. And this has two different sides:
- You (or device vendors for example) can create your own Provider , and make it as the most preferred, by simply setting its position (you will see how to make this later on during this article series). Theoretically this may lead to some confusions, where you will get wrong, not expected key store type;
- On other side, this approach can be used to fix some compatibility issues, where system will add new
AndroidKeyStore
type implementation, keeping the same name convention, into another Provider (there is one more system Provider, called “AndroidKeyStoreBCWorkaround”, we will review it in “Encryption & Decryption” paragraph). This allows us to keep the same, working, code on different API’s, what is pretty cool.
The getInstance(“type”)
method have been working well for me so far. Documentation samples also referees to this method, so I would recommend you to use it to get KeyStore
instance, rather then alternative getInstance(“type”, “provider”)
method.
If you still have some doubts, or something is not working as expected, use
keyStore.provider.name
andkeyStore.type
methods, to validate details of createdKeyStore
instance.
After getting the instance, you must to call the load(loadStoreParameter)
method, that will load key store data basing on the providedProtectionParameter
.
Protection parameters may be used to check the integrity of key store data, or to protect the confidentiality of sensitive key store data (such as a PrivateKey).
In case of AndroidKeyStore
provider, we just need to pass null
as a parameter, and system will load data under the cover, basing on our application identifier.
Key Generation
On Android, asymmetric cryptographic keys are created with KeyPairGenerator
:
Similarly to the key store, there is a fabric getInstance(“algorithm”, “provider”)
method, that should be used to create a key.
There’s also another, simplified, version of that method — getInstance(“algorithm”)
. Don’t use it. This method is searching for algorithm among all of existed Providers and unlike the key store, where we was using pretty unique “AndroidKeyStore” type, algorithm names are common in different Providers (“RSA” exists almost everywhere ). Here we need to explicitly define the provider we want to use.
KeyPairGenerator
instance must be initialized with specification. Before M, KeyPairGeneratorSpec
class should be used to provide it:
In Android Key Store, each key must have an identifier — alias. If you are trying to save key into the key store, with alias that exists already, it will be overwritten with new key. Use setAlias()
builders method to provide alias.
Asymmetric keys must be signed with a certificate. It is mostly used in client -server communications, where client (or server) is verifying certificate, to be certain that the server really is who he claims to be (and not a man in the middle). You will be not able to save asymmetric key without certificate.
If both public and private keys are desired for usage in one application, then you can just create a fake, self signed, certificate.
Certificate requires a start and end date (validity duration), that could be set with setStartDate
and setEndDate
builder methods. Also you need to provide serial number and a subject of certificate, that can be used with setSerialNumber
and setSubject
builder methods.
Printed output of fake self signed certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=MASTER_KEY CA Certificate
Validity
Not Before: Nov 7 12:59:12 2017 GMT
Not After : Nov 7 12:59:12 2037 GMT
Subject: CN=MASTER_KEY CA Certificate
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b8:bf:51:10:fc:8c:7f:39:31:cc:be:43:43:81:
f1:8b:5a:55:94:c4:5c:8c:56:51:5a:63:85:36:87:
ff:3e:f2:a2:3b:9c:b0:e0:a8:3d:5e:1b:41:9c:00:
6e:02:b2:42:d0:9c:e8:2f:4a:52:62:ac:7d:8e:75:
a0:5e:58:57:ae:a5:2e:2c:48:0c:7f:cc:1a:95:46:
2b:2b:a7:5e:96:69:d7:98:b8:32:92:7d:80:e9:19:
07:da:52:1a:29:de:e1:fb:56:43:60:7f:28:ce:23:
ca:ee:12:11:17:1d:0b:86:76:1a:f1:99:69:81:01:
b0:d3:2c:6b:e7:ac:4f:f2:f7:97:88:ef:94:7a:28:
a4:66:6e:d5:29:67:84:12:2e:d3:d3:d7:a6:f6:d4:
ed:81:a4:24:9b:f2:2a:77:16:d9:0d:62:31:cd:cc:
c4:f0:fc:be:8d:6a:b4:14:fc:26:6b:a0:06:79:95:
40:68:0e:da:5e:25:69:f9:36:fb:eb:35:a5:e2:63:
81:f0:88:c2:8e:be:fc:8d:65:ce:99:7f:88:cf:af:
50:9a:59:77:dc:cd:76:a9:8c:64:de:e8:57:3b:40:
bf:72:21:2c:60:3d:e0:7b:dd:1e:01:81:3a:24:81:
d4:a9:e2:e8:af:80:f6:00:f6:7f:fd:9f:48:d2:f7:
96:d1
Exponent: 65537 (0x10001)
Signature Algorithm: sha256WithRSAEncryption
1f:f6:40:99:1c:c1:62:19:89:1f:35:fb:18:7e:93:1e:99:8c:
84:a4:cd:7b:93:c7:23:46:7c:9a:50:aa:a5:f2:34:07:82:ef:
45:28:ac:50:6c:4e:a2:92:35:e4:75:97:12:47:ef:80:e4:6d:
b2:61:e4:4b:7f:79:4c:7c:ee:87:a9:ad:23:a1:ec:e9:1a:2c:
8e:0c:04:61:6c:4b:f3:6e:a6:ff:3e:bb:ad:45:5a:c5:0f:ae:
4e:7c:d5:93:d0:98:69:0d:3e:bc:22:1f:85:11:db:0e:80:66:
ff:58:4d:57:2f:64:cb:f8:c0:07:c9:91:f9:7a:a8:48:0e:f6:
2a:08:d9:db:89:8c:5b:24:a7:ad:8a:08:f5:aa:3e:ac:99:31:
15:9d:93:4f:d1:c5:7b:2d:41:f2:7e:99:5b:38:b8:1d:1a:63:
d2:57:34:10:4b:06:95:39:41:df:22:38:8d:a9:4f:9b:05:86:
46:09:02:51:fc:41:39:54:ca:dd:1d:8e:34:77:01:1b:87:51:
22:9c:4b:e8:ae:d5:8d:d8:e6:e1:ba:18:41:94:ef:64:b6:63:
d9:2e:06:ea:1e:ae:80:11:5f:71:b2:28:b0:cc:4e:18:5e:3f:
4f:28:ae:4f:90:57:1e:41:51:36:02:94:ad:9b:7d:03:25:e7:
f7:8a:4d:26
After providing the key details, initialize theKeyPairGenerator
instance with specification using the initialize(specification)
method.
In M, KeyGenParameterSpec
was introduced. It is used to initialize asymmetric and symmetric keys. KeyPairGeneratorSpec
was deprecated.
KeyGenParameterSpec
requires to specify the purposes of key usage. For instance, keys created with KeyProperties.PURPOSE_ENCRYPT
cannot be used for decryption.
Also, you must to specify the block mode and encryption padding (see Encryption, Modes & Paddings) you want to use with this key. Use setBlockModes
and setEncryptionPaddings
builder methods for that.
There’s no more need to define a fake certificate manually, KeyGenParameterSpec
will do this automatically. You still can customize default values with:
Finally, whenKeyPairGenerator
instance is initialized with specification, use generateKeyPair()
method, to create private-public key pair. In Android Key Store provider, this method will automatically save key in KeyStore
.
Key Management
KeyStore
provides methods, that helps us to manage saved keys:
getKey(“alias”, “password”) — returns a key with given alias or null if the given alias does not exist or does not identify a key-related entry. In Android Key Store, no password is required.
getCertificate(“alias”) — returns the certificate, or null if the given alias does not exist or does not contain a certificate.
deleteEntry(“alias”) — delete a key with given alias. KeyStoreException
will be thrown, if the entry cannot be removed.
Full source code is available here.
Encryption & Decryption
On Android, encryption and decryption are made with Cipher
:
There is a fabric getInstance(“transformation”)
method, that is searching for given transformation among existed Providers (like in other cryptographic components we reviewed above) and should be used to create a Cipher
instance.
The transformation represents the algorithm, that will be used for encryption or decryption, in format of: ”Algorithm/Mode/Padding”.
Method getInstance(“transformation”, "provider")
, where you can explicitly specify the Provider, also exists here. But note, you should not use it with Cipher.
val transformation = "RSA/ECB/PKCS1Padding"
val provider = "AndroidKeyStore"// API 19
val cipher: Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidOpenSSL// API 23, 24
val cipher: Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidKeyStoreBCWorkaroundval cipher: Cipher = Cipher.getInstance(transformation, provider)
// throws java.security.NoSuchAlgorithmException:
// Provider AndroidKeyStore does not provide RSA/ECB/PKCS1Padding
As you can see, technically AndroidKeyStore
provider doesn’t provide RSA algorithm to the Cipher. Instead, there are AndroidOpenSSL
and AndroidKeyStoreBCWorkaround
providers, that knows how to use AndroidKeyStore
provider keys for this algorithm.
To start working with Cipher
instance we need to initialize it for specific operation with a Key. Use init(mode, key)
method with Cipher.ENCRYPT_MODE
to initialize it for encryption:
Or use init(mode, key)
method with Cipher.DECRYPT_MODE
to initialize Cipher for decryption:
After initialization, use doFinal(data)
method, to process encrypted or decrypted data with this Cipher.
You can reinitialize created cipher instance as many times as you need to.
Full source code is available here.
Usage Example
To summarize everything we was talking about, lets try to encrypt and decrypt simple “Hello World” message:
Full source code is available here.
Whats Next
In next “Encrypting Large Data” article from “Secure data in Android” series:
Up to this moment, we tried to process only small data. Lets try to encrypt larger message, larger then 250 symbols. Oops…
Security Tips
If your app requires access to sensitive data, evaluate whether you need to transmit it to a server or you can run the operation on the client.
Consider running any code using sensitive data on the client to avoid transmitting user data.
Make sure that you do not inadvertently expose user data to other applications on the device through overly permissive IPC, world-writable files, or network sockets.
More about encryption in Android you can learn at:
- Android Security Internals: An In-Depth Guide to Android’s Security Architecture book
- Android Explorations blog