I want to use one secure key to encrypt and decrypt data on device without saving it in SharedPreferences or DataStore. I want to generate that key using in app authorization (passcode and biometrics).
I know generating secure key with biometrics is possible using AndroidKeyStore. I know I can generate another key by using passcode. Is there any cryptographic way to use one of those keys to encrypt/decrypt local data?
I have tried generating keys with biometrics and passcode. But I could not find a way to encrypt and decrypt data with either of those keys. For example: user logs in and sets passcode and fingerprint. App should encrypt data so it could be decrypted using one of those authentication methods.
I am wondering how do other secure Android apps solve this problem. Can someone provide me an example where could I look into that?
I have done an Android Application using an ECC Key pair. When I have developed it last year, I wanted to create the ECC key in the Android Keystore. Unfortunately, this ECC key is used to generate a session key thanks to ECDH, and ECDH is not supported by Android Keystore (this is what I have been said here: ECDH with key in Android Key Store )
I have followed the recommendations: I have created an AES key in the Android KeyStore and I have used it to encrypt the ECC key before storing it in the SharedPreferences. Android KeyStore ensures that the AES key cannot be extracted and that only my application can use it to decrypt the ECC key.
I now have a concern for which I would like your advices:
What if someone install my application on a rooted phone, gets the APK, uncompile and modify it to print the ECC key after that has been read and decrypted? I don’t have this skill but I guess that some hackers do.
If that’s feasible, it means that the protection that I have used is not efficient.
Using ECDH is non-negotiable in my case so what solution do I have to secure my ECC key pair?
Thanks
There is no way to ensure that the key is non-extractable unless it's backed by secure hardware.
And for the rooted phone case, attacker doesn't need to modify and reinstall your APK in order to use your key. Any app on that device with the root permission can hook into your app and behaves like it. Even in trusted environment they can use your hardware backed key. Only thing they can't do is, extracting the key from the device.
You may want to read the relatively old paper about TEE and AndroidKeyStore: http://www.cs.ru.nl/~joeri/papers/spsm14.pdf . Especially "Overview of the results for Device-binding"
In order to reduce attack surface, you can:
Protect your key with the user-provided password along with the AndroidKeyStore AES key
Use SafetyNet API to check device integrity: https://developer.android.com/training/safetynet/attestation
I'm want to encrypt and decrypt files from SD-card using AES. In order to do it we always need a seed (usually a string which is inserted by user as a password):
public static byte[] generateKey(String password) throws Exception{
byte[] keyStart = password.getBytes("UTF-8");
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(keyStart);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
return skey.getEncoded();
}
I want to skip this step (inserting password by user) and JUST require user to Authenticate by finger-print sensor and then start Encryption process!
I wonder if there is a way that I can Obtain a unique-key for each different finger that touches finger-print sensor that can be used as SEED to create SecretKey!?
I read some questions on SO and related samples on github but I still cannot find a way to do it.
to clear the problem: I've done implementing the AES itself and completely OK with it and I just need to find a way to get unique-key from finger-print sensor after Authentication.
Updated 2019-10-14
TL;DR
No, you can't access the fingerprint. You can only get a "thumbs up" or "thumbs down" from the Biometric API. This is intentional by design.
You can, however, leverage the Android Keystore for hardware-backed cryptographic operations, and require user re-authentication to release the key. This pretty much does what you want.
The long answer
Generating a password-like seed from a fingerprint is impossible. As James K Polk commented, fingerprints vary when scanned, and they are never legibly stored directly on the device.
When a fingerprint is being enrolled, its image is temporarily stored
on secure device memory, where it is processed to generate validation
data and a fingerprint template (these are all inaccessible to the
Android OS). The raw image is then discarded. When a finger is
scanned, the image is compared to the validation data generated
before, and if it matches to a certain degree of certainty, a user is
deemed as authenticated.
Biometric operations are conducted inside of Android's Trusted Execution Environment (TEE). This is a completely isolated OS running either on a protected part of the CPU on a separate coprocessor on modern devices (SE).
It's a virtually untouchable environment with a restricted interface and hardware barriers put in place to protect against tampering with the chip and forced extraction of biometric validation data and cryptographic keys.
Solution
Going back to your original question, no, you can't get any unique finger identification. This would be inherently insecure, as any application could read the secret!
What you can do, is leverage Android's hardware-backed Keystore and require device-level authentication to release hardware-backed cryptographic keys (setUserAuthenticationRequired(true)). This means generating a random secret which is securely saved to the Keystore, requiring a finger swipe to release the key to userspace. I can't stress the word hardware-backed enough.
You have no control over which finger is can be used and whether vendor-specific implementations allow bypassing of biometrics with the device unlock pattern, for example.
Android Keystore
The Keystore's purpose is to protect cryptographic keys. Keys can only be retrieved by the application that owns them once sufficient requirements have been met, such as recent or immediate biometric authentication.
Keys can be protected against malicious extraction, and on modern devices, hardware bound, meaning they never leave the secure hardware (TEE/SE), and therefore are never exposed to your Android application. Any cryptographic operations, such as AES encryption/decryption, are securely executed outside of userspace (on secure hardware), and enrolling new fingerprints/changing the lock pattern will permanently invalidate the key. In this mode of operation, the Keystore entry merely serves as an "interface" to conduct crypto operations inside of the secure hardware, the true secret is never exposed to your application.
In summary
There is a Fingerprint/Biometric API, which is there purely for convenience, allowing you to quickly confirm an action by requiring the user to authenticate. It boils down to a "yes"/"no" answer from the TEE/SE, and vary greatly depending on the phone manufacturer!
The Keystore is a hardware-backed vault for cryptographic keys. Devices running API-level 28+ also have access to Strongbox Keymaster, if the device hardware supports it, which restricts cryptographic operations to a dedicated security CPU with more secure storage.
These features are device/vendor specific! And could be compromised/insecure! Warn users before enabling fingerprint authentication if you aren't sure about the device.
The only truly secure encryption method is prompting the user every time for the decrypt key (in this case, the mind is the hardware-backed store). Having it stored anywhere, even in live memory, is always a calculated risk.
Doing cryptography right is extremely difficult. I highly
advise that you research and try to understand the basics, and what
additional security Android has to offer, before attempting to use this in
production.
I would like to provide the security to symmetric key which I have used for encryption and decryption.
I would like to Encrypt the symmetric key and store in shared preferences.
How can I do this?
Actually this is not a very advisable strategy.
You should never store keys in your app, since you can not trust a delivered app.
The only way to do this is to have a trusted server wich has user accounts, that use the apis that need to be secured.
Collection of all reasons
Reasons why google does not advice to do so, and counter measures
I've read about Keystore which is in fact a repository of security certificates – either authorization certificates or public key certificates – used for instance in SSL encryption.(by Wikipedia).
Android developers use the Keystore to store their encryption keys in it, instead of
embedding the encryption key inside the android application. That's supposed to solve the problem of a hacker which is decompile their app and get the encryption key the is used by the app.
Whenever you want access the data inside the Keystore you have to specify a password. What prevents the hacker from decompiling the app, extracting the Keystore's password, and then gathering the encryption key inside the Keystore?
Or maybe I got it all wrong?
They are likely storing that key encrypted in the keystore itself. To access the key store, you will need some combination of the user's passcode for unlocking the android device and/or a device specific code such that only that device can decrypt the keystore.