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.
Related
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
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
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.
I'm looking to encrypt a string using DES in one app and then decrypt it in another app. Currently I think its not working because the key to encrypt is generated randomly and so in the second app, the key generated when attempting to decrypt is different.
I need to be able to set my own key for when I am encrypting and then set the same key in the second app when decrypting but cannot find an explicit method on how to do so
Currently my key is being generated as follows:
KeyGenerator keygenerator = KeyGenerator.getInstance("DES");
SecretKey myDesKey = keygenerator.generateKey();
How can I create a dummy key to use (e.g. 12345678)
Thanks
see this article, perhaps it can help you:
http://examples.javacodegeeks.com/core-java/crypto/encrypt-decrypt-with-des-using-pass-phrase/
The follow line allow me to generate a SecretKey
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
But I want to generate a SecretKey related to a specific String.
For example
String myKeyStr="abcde";
SecretKey mykey2=keyGeneratedFrom(myKeyStr);
Obviously the SecretKey generation should have a 1:1 link to avoid issue during the decryption.
I have no idea of how to solve this problem.
Could you help me?
Passwords are not keys. You have to use something like PBKDF2 to derive a key from a password. Even then, it pays to have secure passwords. There is a lot of information about PBKDF2 when used in Java, and the Bouncy Castle library can help too.
PBKDF2 function in Android
Java - PBKDF2 with HMACSHA256 as the PRF
PBKDF2 with bouncycastle in Java
Etcetera.
Don't forget to use a random salt.