Biometric Authentication on Android — Part 1

Why your app needs it

Isai Damier
Android Developers

--

To protect private and sensitive information, many apps require the user to log in. If your app supports the traditional login experience, it probably works similarly to the process that’s depicted in figure 1. The user enters a username and password, the app sends the credentials to a remote server, and finally the remote server returns a userToken that the app can then use later to query the remote server for restricted data. Whether you require your user to login each time they open the app or just once per installation, figure 1 works fine.

Figure 1: Authentication without biometrics

However, there are several drawbacks to using the process depicted in figure 1:

  • If it’s used for per-session authentication, which banking apps use, then the process becomes cumbersome very quickly, as the user is required to enter a password every time they open the app.
  • If it’s used for per-install authentication, which email apps use, then the device owner’s private content is visible to anyone who just happens to be holding the device since it does not verify the owner’s presence.

To help overcome these drawbacks, biometric authentication offers a number of conveniences that makes the authentication process easier for end-users and more attractive for developers — even developers who might otherwise not require frequent login in their apps. Key among these benefits is that using biometric authentication is as easy as tapping a sensor or looking at your device. And importantly, as a developer, you get to decide how often a user must re-authenticate — once a day, once a week, every time they open the app, etc. All in all, the API surface has a number of features that makes login easier for developers and their users.

Today many apps that handle personal data, such as email or social networking apps, tend to only require a one-time authentication upon installation. That practice was popularized at a time when entering a username and password every time a user opens an app adversely affected the user experience. But with biometric authentication, security doesn’t have to be so taxing on the user. Even if your app would normally require one-time authentication, you may consider requiring biometric authentication periodically to verify user presence. The length of the period is entirely up to you, the developer.

If an app requires authentication per session (or some such frequency as once every 2 hours or once per day, etc.), then looking at the device or tapping on a sensor is only marginally noticeable compared to having to type in a password each time. If an app only requires a one-time authentication, as many emailing apps do, then biometrics would add an additional layer of security at the small cost of the user simply picking up and looking at their device. If a user wants to continue keeping their emails open without re-authenticating, then they should have that choice. But for users who want a bit more privacy, then biometric authentication should provide that additional peace of mind. Either way, the cost on the end-user is minuscule especially compared to the added benefit.

Implementing biometric authentication using BiometricPrompt

The BiometricPrompt API allows you to implement authentication both with and without encryption. If you are working on an app that requires a stronger security system, like a healthcare app or a banking app, then you may want to tie your encryption keys to biometric authentication so as to verify user presence. Otherwise, you may want to implement biometric authentication as a convenience for your users. The code snippets for both cases are very similar, except that for the encryption implementation you would pass in a CryptoObject, whereas for the convenience implementation you would leave out the CryptoObject parameter.

Encryption version:

biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))

While in the code snippet above we pass a Cipher to the CryptoObject, you are free to pass a number of alternatives, such as a Mac or Signature.

No CryptoObject version:

biometricPrompt.authenticate(promptInfo)

To implement biometric authentication in your Android app, use theAndroidX Biometric library. Although the API handles different modalities (fingerprint, face, iris, etc.) automatically under the hood, as a developer you still get to choose the desired security level of biometrics that your app will accept by setting setAllowedAuthenticators()as shown in the code snippet below. Class 3 (formerly Strong) means you want biometrics that unlock credentials stored in the Keystore (i.e. cryptography); Class 2 (formerly Weak) means you just want to unlock your app without relying on credentials that are further protected by cryptography. There is a Class 1, but it doesn’t work with apps. See the Android Compatibility Definition Document for more details.

fun createPromptInfo(activity: AppCompatActivity): BiometricPrompt.PromptInfo =   BiometricPrompt.PromptInfo.Builder().apply {      setAllowedAuthenticators(BIOMETRIC_STRONG)      // Continue setting other PromptInfo attributes such as title,  subtitle, description   }.build()

Encryption and auth-per-use keys vs time-bound keys

An auth-per-use key is a secret key that can be used to perform one cryptographic operation. So, for instance, if you want to perform ten cryptographic operations then you have to unlock the key ten times. Hence the designation auth-per-use: you must authenticate (i.e. unlock the key) each time you use it.

A time-bound key, on the other hand, is a secret key that is valid for a certain time period — which you establish beforehand by passing a number of seconds to setUserAuthenticationValidityDurationSeconds. If the number of seconds you pass to the time-bound function is -1, the default value, then the system assumes you want auth-per-use. For all other numbers, we recommend three seconds or more, the system honors the duration you set. To easily create time-bound keys, see the MasterKeys class in Jetpack Security.

Normally — in conjunction with the aforementioned -1 — you would pass a CryptoObject to BiometricPrompt.authenticate() to request auth-per-use. However, instead of using a CryptoObject, you could set a very short duration, such as 5 seconds, to use a time-bound key as if it were an auth-per-use key. The two approaches are practically equivalent for showing user presence, so the choice is up to you as to how you want to design your app’s UX.

Regarding what’s happening under the hood: When you use CryptoObject, the secret key is unlocked only for the specified operation. This is because the Keymint(or Keymaster) gets a HardwareAuthToken (HAT) with a specific operationId. The secret key gets unlocked and you can only use it for the operation represented by the Cipher/Mac/Signature operation you wrap around the CryptoObject, and you can only perform the specified operation once before it locks again — it’s an auth-per-use key. When you don’t use a CryptoObject, the HAT that gets sent to the Keymint doesn’t have an operationId; therefore, the Keymint simply looks for a HAT with a valid timestamp (timestamp + time-based-key-duration > now), and you can use that key until its time expires — it’s a time-bound key.

At first glance, it may sound like a time-bound key can be accessed by any app as long as the time-window is valid. But the reality is that, short of a compromised user-space, there is no concern about some app X using some app Y’s keys or operations. The Android framework will not allow other apps to find or initialize another app’s operation.

Part 1 Summary

In this post, you learned the following:

  • Why username+password only authentication is problematic.
  • Why it’s a good idea to include biometric authentication in your app.
  • Design considerations for different types of apps.
  • How to invoke BiometricPrompt with or without encryption.
  • The difference between auth-per-use vs time-bound encryption keys.

In the next post, you will learn how to incorporate the right UIs and logic in your biometric authentication flow.

--

--

Isai Damier
Android Developers

Android Engineer @ Google; founded geekviewpoint.com; Haitian; enjoy classical lit and chess. Twitter: @isaidamier