» Dump

Android biometrics

I was curious about how Android handles fingerprint scans.

Of course, apps must not get access to fingerprint data so that the fingerprints are kept secure. So what kinds of APIs and security models does Android have?

Analysis

First, an analysis of the results. Technical details are summarized in later sections.

The Android biometrics APIs prevent disclosure of biometric information to third party apps. The app only receives the information that authentication succeeded, or a bit more info in case of an error. In this sense, using biometrics for third party Android apps is safe.

The Android compatibility requirements mandate hardware-backed security that can shield fingerprint info even from kernel-level malware. There are limits on spoof resistance, but these limits are weaker than people might think. In this sense, biometric information is well protected against software-based attackers trying to acquire biometrics or trying to bypass authentication checks, but biometrics might not be as reliable as passphrases to defend against motivated physical attackers trying to unlock the phone.

Android defines a testing protocol for biometric sensors such as fingerprint readers. The protocol can produce reasonable results, which can then be used for classing the sensor appropriately per the compatibility requirements. However, the protocol can also be carried out in a more lax manner that might misrepresent the security.

The weakest point in all of this seems to be the phone's vendor. The vendor produces the hardware, implements fingerprint matching, and provides the drivers used by Android. While the compatibility requirements constrain how the biometric systems can be implemented, it is possible that even a well-intentioned vendor makes mistakes that can be exploited. In some places, the compatibility requirements also only talk about third-party apps, which permits privileged access for vendor apps (at least for the insecure class 1 biometrics).

Android biometrics APIs

The Android documentation provides an overview for biometric authentication methods, including a block diagram with different components.

This architecture has evolved in recent Android versions.

  • ancient Android: FingerprintManager) provides an abstract interface for accessing fingerprint authentication functionality. This is a low-level interface that can switch on the fingerprint scanner, and then receives an authentication result. The app is responsible for providing an appropriate user interface.

  • Android 9: BiometricPrompt replaces the FingerprintManager. It provides similar scan results, but lets the Android operating system render the fingerprint prompt.

  • Android 10 added support for face authentication.

How does BiometricPrompt work?

  1. (optional): use BiometricManager#canAuthenticate(auth) to check whether a given authentication method is available.

  2. Create a prompt using the BiometricPrompt.Builder class. This can set various options:

    • what authenticators are allowed: strong biometrics (class 3), weak biometric (class 2), or device credentials (e.g. PIN, pattern, password)
    • whether confirmation is required: if set to false, there might not have to be any user interaction, in particular for face scans.
    • title, subtitle, and description for the authentication request UI
    • cancel button
  3. Invoke the prompt via BiometricPrompt#authenticate().

    This method takes a callback object that handles the following events:

    • onAuthenticationError() for unrecoverable problems (e.g. no suitable hardware)
    • onAuthenticationHelp() for recoverable errors (e.g. bad scan)
    • onAuthenticationFailed() for rejecting the auth (e.g. wrong fingerprint)
    • onAuthenticationSucceeded() for success (e.g. matching fingerprint)

    This method can optionally take a crypto object, representing a key that should be unlocked through a fingerprint (e.g. an encryption key for a password manager).

  4. The app receives a result through one of the callback methods. All the success handler receives is information about the used authentication type (biometric or device credential), and the unlocked crypto object if provided.

This seems to be a good design that discloses very little to the app. The app can offer biometrics as a choice and require a certain security level, but essentially only receives a pass/fail result. It doesn't get to know whether facial or fingerprint scans were used, or which finger was used.

Android biometrics security requirements

The Android 13 Compatibility Definition Document (CDD) provides requirements for biometrics. Biometrics are classified as:

  • class 1 (convenience) – not sufficient for BiometricPrompt
  • class 2 (weak) – not sufficient for protecting keys
  • class 3 (strong)

These classes differ in parameters such as the maximum tolerated false acceptance rate.

  • performance / quality

    class 1class 2class 3
    max false rejection rate10% (recommendation)
    max false acceptance rate0.002%
    max spoof/imposter acceptance rate30% (note 1)20% (note 1)7%

    note 1: additional steps are recommended or suggested if the spoof acceptance rate is above 7%

  • rate limits

    class 1class 2class 3
    max false trials20
    max failures3infinite
    primary auth requiredevery 24h / 72h72h
  • TEE / hardware security

    class 1class 2class 3
    rate limiting in TEEstrongly recommended
    biometric matching in TEErequired
    secure storagerequired
    apps cannot distinguish enrollmentsrequired
    hardware-backed keystorerequired

Class 1 provides insecure convenience biometrics, e.g. voice unlock. It is not accessible to apps.

The defining feature of class 2 biometrics and better is the requirement for hardware-based methods that have to maintain the security of biometrics even if Android is compromised.

To quote the relevant requirements from class 2, emphasis mine:

  • [C-2-3] MUST perform the biometric matching in an isolated execution environment outside Android user or kernel space, such as the Trusted Execution Environment (TEE), or on a chip with a secure channel to the isolated execution environment.

  • [C-2-4] MUST have all identifiable data encrypted and cryptographically authenticated such that they cannot be acquired, read or altered outside of the isolated execution environment or a chip with a secure channel to the isolated execution environment as documented in the implementation guidelines on the Android Open Source Project site.

  • [C-2-6] MUST NOT enable third-party applications to distinguish between individual biometric enrollments.

  • [C-2-7] MUST NOT allow unencrypted access to identifiable biometric data or any data derived from it (such as embeddings) to the Application Processor outside the context of the TEE. Upgrading devices launched on Android version 9 or earlier are not exempted from C-2-7.

  • [C-2-8] MUST have a secure processing pipeline such that an operating system or kernel compromise cannot allow data to be directly injected to falsely authenticate as the user. Note: If device implementations are already launched on Android version 9 or earlier and cannot meet the requirement C-2-8 through a system software update, they MAY be exempted from the requirement.

Class 3 is generally equivalent to class 2. In exchange for stronger spoof resistance, more failures and longer durations between primary authentication is tolerated. In fact, class 3 biometrics can be used as that primary authentication for lower classes. Class 3 also adds the requirement for a hardware-backed keystore.

Measuring biometric security

Android provides a protocol for measuring the security of biometric sensors, in particular for the spoof acceptance rate and imposter acceptance rate metrics.

  • Test subjects enroll their fingerprints (at least 10 different people)

  • In a calibration phase, the optimal "presentation attack instrument" for the spoof attack is to be found. For example, this could be a fingerprint with printed ink, or a mold with latex paint.

    The protocol does not explain what "optimal" means, which might allow testers to select the instrument that is most likely to be rejected correctly. However, this might not matter much since the testing phase will only count success/failure, not attempts with insufficient fingerprint data.

    Preparing the instrument requires lifting a fingerprint. This may be done in a cooperative manner by taking a mold of the subject's finger. However, the testing protocol allows non-cooperative lifting of fingerprints from some surface. This unclear methodology will produce a wide range results.

  • Test the spoof instrument against the fingerprint sensor. Only attempts that result in success or failure are counted, attempts with insufficient data are discarded.

The test protocol suggests testing to 95% confidence and a 5% margin of error, but does not require these limits. Thus, security claims can be made under this test protocol with only low quality data.

It is also worth noting that the spoof acceptance rate is measured on the level of individual trials. If the same attack instrument is presented three times to a sensor, fails the first two times, but then unlocks the phone on the third try, this would be counted as a SAR of 33%, even though the user was 100% compromised. Whether this is a valid way to think about fingerprint spoofs is beyond my knowledge.