# Android Biometrics **Problem statement**: - MeeAgentConfig requires a password to init a MeeAgent. We need to store this password somewhere, one of the variants is *EncryptedSharedPreferences*. Here is the [article](https://developer.android.com/topic/security/data) about the EncryptedSharedPreferences: Brief summary: - [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) is part of the Security library, which uses a two-part system for key management: * A keyset that contains one or more keys to encrypt a file or shared preferences data. The keyset itself is stored in [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences). * A primary (master) key that encrypts all keysets. This key is stored using the [Android keystore system](https://developer.android.com/training/articles/keystore). - EncryptedSharedPreferences wraps the SharedPreferences class and automatically encrypts keys and values using a two-scheme method: * Keys are encrypted using a deterministic encryption algorithm such that the key can be encrypted and properly looked up. * Values are encrypted using [AES-256 GCM](https://datatracker.ietf.org/doc/html/rfc5116#section-5.2) and are non-deterministic
 - Here is an example of how we can initialise EncryptedSharedPreferences: ![](https://hackmd.io/_uploads/H1DbOm0Ln.png) :::warning Think of where we should put this initialisation and ensure values in the EncryptedSharedPreferences will be accessible after application restarts ::: - As we can see from the example, we need to pass mainKeyAlias to create EncryptedSharedPreferences - Here is the [recommended approach](https://developer.android.com/topic/security/data#write-files) of the mainKeyAlias creation: ![](https://hackmd.io/_uploads/rkfMcXA83.png) - However, it is stated under the code snippet in the article, that for the use cases requiring additional security we can request user authentication for key use: ![](https://hackmd.io/_uploads/Hk8t5m0U2.png) :::warning [createConfirmDeviceCredentialIntent](https://developer.android.com/reference/android/app/KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence,%20java.lang.CharSequence)) is deprecated in API level 29 ::: - To sum up, we can work with the EncryptedSharedPreferences in two modes - using default key generation parameter specification, or create our own which requires authentication - One more way to work with the user authentication for the key use is described in [this article](https://developer.android.com/training/articles/keystore#UserAuthentication) - One of the problems with the current implementation of the [biometric authentication dialog](https://developer.android.com/training/sign-in/biometric-auth#biometric-only) in Android is in the combination of types of authentication that an app supports. For those purposes the BiometricManager.Authenticators interface is used. - It lets us declare the following types of authentication: **BIOMETRIC_STRONG**, **BIOMETRIC_WEAK** and **DEVICE_CREDENTIAL**. To define the types of biometric authentication that an app accepts we need to pass an authentication type or a bitwise combination of types into the **setAllowedAuthenticators()** method  - The problem is that the following combinations of authenticator types aren't supported on Android 10 (API level 29) and lower: **DEVICE_CREDENTIAL** and **BIOMETRIC_STRONG | DEVICE_CREDENTIAL**. To check for the presence of a PIN, pattern, or password on Android 10 and lower, we need to use the **KeyguardManager.isDeviceSecure()** method. Thus, the authentication flow differs in older android versions, and version-dependent options are listed below: * **Api level >= 30** *setAllowedAuthenticators* can use combinations: **DEVICE_CREDENTIAL**, **BIOMETRIC_STRONG | DEVICE_CREDENTIAL**, **BIOMETRIC_STRONG** 1. User has biometry set up, and we allow only biometry for an authentication using BiometricPrompt (*setAllowedAuthenticators* - **BIOMETRIC_STRONG**) **Options:** 1. After successful user authentication we create MainKeyAlias using the recommended approach (which is described above) and rely on encryptedSharedPreferences under-the-hood encryption without any additional security. Further implementation is similar to ios, we generate some random password for a user, [add it to the EncryptedSharedPreferences](https://developer.android.com/topic/security/data#edit-shared-preferences) and can access it later. 2. We use a [cryptographic solution that depends on authentication](https://developer.android.com/training/sign-in/biometric-auth#crypto). This solution works only with the biometric prompt and **BIOMETRIC_STRONG** authenticator. After the user authenticates successfully using a biometric prompt, our app can perform a cryptographic operation. For example, if we authenticate using a Cipher object, our app can then perform encryption and decryption using a SecretKey object. Code snippets are in the article, but the main steps are: * Generate a key that uses the KeyGenParameterSpec configuration with **setUserAuthenticationRequired(true)** * Start a biometric authentication workflow that incorporates a cipher * Within the biometric authentication callbacks, use the secret key to encrypt the sensitive information 2. User has biometry set up, and we allow biometry or device credential for an authentication using BiometricPrompt (*setAllowedAuthenticators* - **BIOMETRIC_STRONG | DEVICE_CREDENTIAL**) **Options:** 1. The same as 1.1 2. We can also use a [cryptographic solution that depends on authentication](https://developer.android.com/training/sign-in/biometric-auth#crypto). We can use a secret key that allows for authentication using either biometric credentials or lock screen credentials (PIN, pattern, or password). When configuring this key, we should specify a validity time period. During this time period, our app can perform multiple cryptographic operations without the user needing to re-authenticate. :::danger To use this type of key, we must allow for [fallback to non-biometric credentials](https://developer.android.com/training/sign-in/biometric-auth#allow-fallback), which means that we can't pass an instance of CryptoObject into the authenticate() method of our BiometricPrompt object. ::: 3. User has lock screen credentials (PIN, pattern, or password), but no biometry. We can do authentication by using *setAllowedAuthenticators* - **DEVICE_CREDENTIAL**. **Options** are the same as in the previous case with *setAllowedAuthenticators* - **BIOMETRIC_STRONG | DEVICE_CREDENTIAL** 4. User doesn’t have screen credentials and biometry **Options**: * Local pin for the app * Don’t give an access to the app until user enables biometry or device credentials - **Api level < 30** To build biometric prompt we can pass only **BIOMETRIC_STRONG** to *setAllowedAuthenticators()* To check for the presence of a PIN, pattern, or password on Android 10 and lower, we can use the *KeyguardManager.isDeviceSecure()* 1. User has biometry set up, and we allow only biometry for an authentication using BiometricPrompt (*setAllowedAuthenticators* - **BIOMETRIC_STRONG**) **Options** are the same as for the first case when Api level >= 30 2. User has screen password/pin/graphic key: We could enforce users to enter their credentials by calling deprecated in API 29 and described above [createConfirmDeviceCredentialIntent](https://developer.android.com/reference/android/app/KeyguardManager#createConfirmDeviceCredentialIntent(java.lang.CharSequence,%20java.lang.CharSequence)). There are also two **options**: - First one is similar to approach, described in 1.1 section of Api level >= 30 - Second one is securing EncryptedSharedPreferences with the key, generated using KeyGenParameterSpec.Builder with setUserAuthenticationRequired set to true (the approach is described above) 3. User doesn’t have screen credentials and biometry **Options**: * Local pin for the app * Don’t give an access to the app until user enables biometry or device credentials **Notes:** - After the user authenticates, we can check whether the user authenticated using a device credential or a biometric credential by calling getAuthenticationType() - [An article](https://medium.com/redmadrobot-mobile/authenticate-me-if-you-can-d01033531a03) with the example of the local pin implementation - [Google cryptography library ](https://developers.google.com/tink)