Are KeyStore entries lost when the application is uninstalled? - android

I am generating an Asymmetric key pair in the Android key store as below:
I have used the public key for symmetric key wrapping and storing the wrapped key to a file. When I try to unwrap symmetric key using the private key, I am able to do so within that instance. Once my application is re-installed, I am unable to get the key store entry with the alias.
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
);
kpg.initialize(new KeyGenParameterSpec.Builder(
Constants.KEY_STORE_ALIAS_NAME,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
)
.setKeySize(Constants.ASYMMETRIC_KEY_LENGTH)
.setBlockModes(KeyProperties.BLOCK_MODE_ECB)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build()
);
keyPair = kpg.generateKeyPair();
// Code for accessing the key store entry to un wrap the symmetric key
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(Constants.KEY_STORE_ALIAS_NAME, null);
PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();

Keys stored in Android Keystore are non-extractable. It is a security measure
Security Features
Android Keystore system protects key material from unauthorized use. Firstly, Android Keystore mitigates unauthorized use of key material outside of the Android device by preventing extraction of the key material from application processes and from the Android device as a whole. Secondly, Android KeyStore mitigates unauthorized use of key material on the Android device by making apps specify authorized uses of their keys and then enforcing these restrictions outside of the apps' processes
This means that the keys can not be part of the Android backup service in any way. It allows to store application data on the cloud once the application is uninstalled. See HowBackupWorks.
It would be a serious security risk that private keys could be extracted and stored in cloud or even that they remain stored in the device when the application has been uninstalled
If you need to use an encryption key that does not depend on the reinstallation, you could generate a symmetric key from a user passphrase using a key derivation algorithm

Related

How to encrypt and decrypt data in Android using the elliptic curve key pair of type secp256r1?

I need to use NIST P-256 elliptic curves to encrypt and decrypt data. Now that I have generated the key pair, but how do I use them to encrypt and decrypt?
The official website only says how to use this ec key pair to sign/verify, but I want to know how to use this ec key pair to encrypt/decrypt.
website: https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec#example:-nist-p-256-ec-key-pair-for-signingverification-using-ecdsa
generate NIST P-256 key pair code:
val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")
val parameterSpec =
KeyGenParameterSpec.Builder("container", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1"))
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512)
.build()
kpg.initialize(parameterSpec)
val keyPair = kpg.generateKeyPair()
val ecPublicKey = keyPair.public as ECPublicKey
val ecPrivateKey = keyPair.private as ECPrivateKey
AndroidKeyStore does not currently support encryption or decryption with EC keys, only with RSA keys.
To use EC keys for encryption, you need to either use ECDH plus a key derivation function (KDF) to compute a shared symmetric key which you can use for your data, or to use ECIES which does that internally. But AndroidKeyStore doesn't support either mode of operation as of Android 10. Maybe in Android 11.
For now, you can either use RSA with an appropriate padding mode (OAEP recommended) to encrypt your symmetric key, or you can use the native Java cryto provider. This, unfortunately, will not use secure hardware to generate, store or use the key, and will instead do all of these things in your app's process space. There's an example here.
(For what it's worth, I'm the Google engineer who owns AndroidKeyStore. I've been planning to add ECDH support for a few years now, but it's always been pre-empted by other features that were considered higher priority. I will get to it, though.)
Public key encryption is not recommended to use for encryption. The general practice is hybrid-encryption where a block cipher key is exchanged then symmetric encryption is performed.
After the key exchange the most common issues Authentication and Integrity. The modern practice is using an authenticated encryption mode as AES-GCM. GCM mode gives you authentication and integrity. You can see an implementation here

How to save Oauth Access token securely in android

I have access token from the server after authentication lets say "uyhjjfjfgg567f8fhjkkf" now I want to save it in the device securely. I looked in Keystore and Keychain in android developer sites. I dont clearly understand how it works and how we should retrieve the token from the keystore.
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512)
.build());
KeyPair kp = kpg.generateKeyPair();
/*
* Load the Android KeyStore instance using the the
* "AndroidKeyStore" provider to list out what entries are
* currently stored.
*/
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();
You don't need to save the access token, since it has short life anyway. Keeping it in memory is good enough.
You do need to keep the refresh token, and you have a few options for that:
In a file
Either directly in a file in the internal storage
or using SharedPreferences
or in a Database
Using the AccountManager
Consider using the StoredCredential. For the flow itself, I recommend you to use Google AppAuth library.
Of course, you can also encrypt the key using a cipher:
private static byte[] encrypt(byte[] key, byte[] text) throws GeneralSecurityException {
final SecretKeySpec skeySpec = new SecretKeySpec(key, KEY_ALGORITHM);
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, sInitVectorSpec);
return cipher.doFinal(text);
}
And the key can be stored in the KeyStore.
We use a custom SharedPreference instance that encrypts the keys and values when adding, and decrypts when requesting.
SecurePreferences preferences = ...
preferences.edit().putString( "key", "value" ).apply(); // key and value are encrypted automatically
String value = preferences.getString( "key", null ); // key and value are decrypted automatically
I would only recommend using SharedPreferences if the values are encrypted, because even though the xml file is only available to the app, it can be accessed on rooted devices.
If you already using a SqlLiteDB, I would probably use that. If not, it's bit heavy for just saving a token.
EDIT:
An oauth token is completely unrelated to the key and keystore used to sign the app.
The oauth token is a token provided by the server after validating the user's credentials, within the app.
The keystore contains 1 or more certificates that is used to digitally sign the app. This is to prevent someone else from uploading an app that has the same package name as yours and replacing it.

Encrypting Realm with key stored in KeyStore

I am trying to setup an encrypted default realm instance in my app.
The idea is to generate a key using a KeyPairGenerator with a given alias, store it in the AndroidKeyStore and use said key every time it is needed.
WHAT I DO
This is how i generate the key:
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
if (!ks.containsAlias(KEY_ALIAS)) {
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
end.add(Calendar.YEAR, 99);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(this)
.setAlias(KEY_ALIAS)
.setSubject(new X500Principal("CN=Example, O=ExampleOrg"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.getTime())
.setEndDate(end.getTime())
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair();
}
I am using the KeyPairGenerator as i need to support api versions 18 and up.
Here is how i setup my default realm instance in my Application:
RealmConfiguration config = null;
try {
config = new RealmConfiguration
.Builder(this)
.encryptionKey(ks.getKey(KEY_ALIAS, null).getEncoded())
.name("dealmatrix.realm")
.schemaVersion(1)
.build();
where ks is a Keystore instance acquired like so:
Keystore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
WHAT GOES WRONG
My problem is that this expression:
ks.getKey(KEY_ALIAS, null).getEncoded()
returns null, which understandably leads to an exception.
I have read online that this is the intended behaviour of the KeyStore system.
If indeed i am unable to get the stored encryption key's byte array, how am I supposed to encrypt my realm using said key?
Are there any other methods to securely store an encryption key so that i may use it in my realm configuration?
There is a WIP example project in feature/example/store_password branch in Realm repository which uses Android keystore.
https://github.com/realm/realm-java/tree/feature/example/store_password/examples/StoreEncryptionPassword
Core logic is written in Store.java
We need some more works(cleanup, adding comments, supporting old devices) before releasing this example project. But I think this project helps you.
Android Keystore keys returning null from getEncoded is working as intended. getEncoded is supposed to return the private key's key material (usually in PKCS#8 DER-encoded format) or null if key material export is not supported. Android Keystore by design does not reveal/export key material of private or secret keys and thus getEncoded returns null. See https://developer.android.com/training/articles/keystore.html#SecurityFeatures.
You can still use these keys just fine with Signature and Cipher abstractions.
The Android Keystore prohibits extraction of private keys from it. So the design would be to generate a Realm key outside of the Android Keystore, so that you can use it for the encryption/decryption of the Realm database.
But to safely store that Realm key, you would use the power of the Android Keystore, by encrypting the Realm key with the Android Keystore and then store it locally (e.g. Shared Preferences). Later you could read that encrypted Realm key, decrypt it with the Android Keystore and use it again to unlock your Realm database.

Android KeyStore Initialization

First off I am new to android Programming, though I am not new to programming itself. What I am, essentially, trying to do is to save my encryption Keys into the Android Keystore. There seems to be a phenomenal lack of such information on GOOGLE, itself. Since there is not much how-to available on the topic I am assuming that it isn't fairly standard knowledge. So can someone please give me a sample code to
Initialize the KeyStore(Will be using AES-256).
Save multiple keys in a KeyStore(Please tell me the max number of keys I can store in 1 KeyStore, since i plan on saving nothing short of a 100).
Get Keys from KeyStore.
Edit Keys
Delete Keys
Delete Entire KeyStore
So in essence a code for all basic functions of a keystore.
Thank you in advance for your assistance.
If you set your minSdkVersion to 23 or higher Android M makes it easy to generate and manage symmetric keys as of this month.
Check out the 4th example listed here.
https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.html
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(
new KeyGenParameterSpec.Builder("key2",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
SecretKey key = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
...
// The key can also be obtained from the Android Keystore any time as follows:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
key = (SecretKey) keyStore.getKey("key2", null);
This example also was helpful.
https://github.com/googlesamples/android-ConfirmCredential/blob/master/Application/src/main/java/com/example/android/confirmcredential/MainActivity.java
I think Android Key Store does not support symmetric keys like AES keys. Please refer to here. BTW, why does the app need so many symmetric keys? I suggest that you store one master asymmetric key in key store, and use this key to encrypt many other symmetric keys in your app.
Hope you solve your problem soon.

AndroidKeyStore wiped out after device password change

I am currently working on android application which is based on Client-server architecture. For data security, I am using Public-Private key pair for data encryption and signing. I am using AndroidKeyStore for storing key pair. Below is the code to generate key pair:
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(
mContext)
.setAlias(mPrivateKeyAlias)
.setSubject(new X500Principal("CN=" + mPrivateKeyAlias))
.setSerialNumber(
BigInteger.valueOf(System.currentTimeMillis()))
.setStartDate(start.getTime())
.setEndDate(end.getTime()).setKeySize(2048).build();
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance(
"RSA",
"AndroidKeyStore");
kpGenerator.initialize(spec);
// Key Pair will be saved in AndroidKeyStore
KeyPair pair = kpGenerator.generateKeyPair();
After executing this code, Keystore releated files (CERT and PKEY files) will be generated at '/data/misc/keystore/user_0/' directory.
I am encrypting application sensitive data like auth-token and saving it to Shared Pref for security reasons.
But now when user changes device password or pin, keystore files are getting deleted as Masterkey used for keystore encryption is generated using device credentials.
Now to fix this issue, I tried to keep Public-Private key pair in RAM and when password gets changed. From onPasswordChanged(Context context, Intent intent) method of DeviceAdminReceiver, I am executing below code :
KeyStore keyStore = KeyStore
.getInstance("AndroidKeyStore");
keyStore.load(null);
keyStore.setKeyEntry(mPrivateKeyAlias, mPrivateKey.getPrivateKey(),
null, new Certificate[] { mPrivateKey.getCertificate() });
But, after this code only CERT file gets created at '/data/misc/keystore/user_0/' directory and while decryption using private key, giving some invalid signature error.
Also, I have shared my public key with server, encrypted data with private key, so creating new key pair would not be better solution.
So, how I can retain my public private key pair after device password change ? If there is no work around, what is the exact use of AndroidKeyStore? Where can I use it ?
This issue has been fixed by Google in Android 5.0 (Lollipop) release. But, for previous versions of Android, you will have to live with this issue. :(

Categories

Resources