Security updates

Android P introduces a number of new features that enhance the security of your app and the devices that run them. This page describes the changes that are most important for third-party app developers to keep in mind.

Unified biometric authentication dialog

In Android P, the system provides biometric authentication dialogs on behalf of your app. This functionality creates a standardized look, feel, and placement for the dialog, giving users more confidence that they're authenticating against a trusted biometric credential checker.

If your app uses FingerprintManager to display a fingerprint authentication dialog to users, you can now use a more flexible interface that responds to various types of biometric authentication. Migrate your app's logic to use BiometricPrompt. BiometricPrompt relies on the system to display the authentication dialog. It changes its behavior based on the biometric interface the user has selected.

APK signature scheme with key rotation

Android P adds support for APK Signature Scheme v3. This scheme has the option to include a proof-of-rotation record in its signing block for each signing certificate. This capability enables your app to be signed with a new signing certificate by linking the APK file's past signing certificates to the one with which it is now signed.

To change your app's signing certificate using this new scheme, run the new rotate command that's available in the apksigner tool, as demonstrated in the following sections.

Create a sequence of signing keys

Enable rotation by creating a new sequence of signatures, known as a signing certificate lineage, by executing the following command:

$ apksigner rotate --out /path/to/new/file --old-signer \
    --ks release.jks --new-signer --ks release2.jks

Rotate your signing keys

When you need to rotate your signing keys again, run the following version of the rotate command:

$ apksigner rotate --in /path/to/existing/lineage \
  --out /path/to/new/file --old-signer --ks release2.jks \
  --new-signer --ks release3.jks

Android Protected Confirmation

Supported devices that launch with Android P installed give you the ability to use the Protected Confirmation API. By using this new API, your app can use an instance of ConfirmationPrompt to display a prompt to the user, asking them to approve a short statement. This statement allows the app to reaffirm that the user would like to complete a sensitive transaction, such as making a payment.

If the user accepts the statement, your app receives a cryptographic signature that's protected by a keyed-hash message authentication code (HMAC). The signature is produced by the trusted execution environment (TEE), which protects the display of the confirmation dialog as well as user input. The signature indicates, with very high confidence, that the user has seen the statement and has agreed to it.

Caution: The Protected Confirmation API doesn't provide a secure information channel for the user. Your app cannot assume any confidentiality guarantees beyond those that the Android platform offers. In particular, don't use this API to display sensitive information that you wouldn't ordinarily show on the user's device.

After the user confirms the message, its integrity is assured, but your app must still use data-in-transit encryption to assure the confidentiality of the signed message.

To provide high-assurance user confirmation in your app, complete the following steps:

  1. Generate an asymmetric signing key using the KeyGenParameterSpec.Builder class. When creating the key, pass true into setUserConfirmationRequired(). Also, call setAttestationChallenge(), passing a suitable challenge value provided by the relying party.

  2. Enroll the newly-generated key and your key's attestation certificate with the appropriate relying party.

  3. Send transaction details to your server and have it generate and return a blob of extra data. For example, the extra data of a financial transaction might comprise the amount, origin account, and destination account. The blob should contain a cryptographic nonce for protection against replay attacks, and the blob might also contain app-specific data. Your server should store the blob and transaction details locally.

  4. Set up the ConfirmationCallback object that informs your app when the user has accepted the prompt shown in a confirmation dialog:

    class MyConfirmationCallback : ConfirmationCallback() {
        override fun onConfirmed(dataThatWasConfirmed: ByteArray?) {
            super.onConfirmed(dataThatWasConfirmed)
            // Sign dataThatWasConfirmed using your generated signing key.
            // By completing this process, you generate a "signed statement".
        }
    
        override fun onDismissed() {
            super.onDismissed()
            // Handle case where user declined the prompt in the
            // confirmation dialog.
        }
    
        override fun onCanceled() {
            super.onCanceled()
            // Handle case where your app closed the dialog before the user
            // could respond to the prompt.
        }
    
        override fun onError(e: Exception?) {
            super.onError(e)
            // Handle the exception that the callback captured.
        }
    }
    

    If the user approves the dialog, the onConfirmed() callback is called. The dataThatWasConfirmed blob is a CBOR data structure that contains, among other details, the prompt text that the user saw as well as the extra data that you passed into the ConfirmationPrompt builder. Your app should use the previously-created key to sign the dataThatWasConfirmed blob. You should then pass this blob, along with the signature and transaction details, back to the relying party.

    After receiving the signature, your server should check it. If the signature is valid, you can then extract extraData and promptText from dataThatWasConfirmed and verify that extraData matches what was previously stored. As a final check, your server should check that the promptText corresponds to the transaction details that appear in the extra data. If this step succeeds, your server can carry out the transaction, knowing with a high degree of confidence that the user has seen and approved the message in promptText.

  5. Add logic similar to that shown in the following code snippet to display the dialog itself:

    // This data structure varies by app type. This is just an example.
    data class ConfirmationPromptData(val sender: String,
            val receiver: String, val amount: String)
    
    val myExtraData: ByteArray = byteArrayOf()
    val myDialogData = ConfirmationPromptData("Ashlyn", "Jordan", "$500")
    val threadReceivingCallback = Executor { runnable -> runnable.run() }
    val callback = MyConfirmationCallback()
    
    val dialog = ConfirmationPrompt.Builder(context)
            .setPromptText("${myDialogData.sender}, send
                            ${myDialogData.amount} to
                            ${myDialogData.receiver}?")
            .setExtraData(myExtraData)
            .build()
    dialog.presentPrompt(threadReceivingCallback, callback)
    

Hardware security module

Supported devices that are launched with Android P installed can have a StrongBox Keymaster, an implementation of the Keymaster HAL that resides in a hardware security module. The module contains its own CPU, secure storage, a true random-number generator, and additional mechanisms to resist package tampering and unauthorized sideloading of apps. When checking keys stored in the StrongBox Keymaster, the system corroborates a key's integrity with the Trusted Execution Environment (TEE).

To support low-power StrongBox implementations, a subset of algorithms and key sizes are supported:

  • RSA 2048
  • AES 128 and 256
  • ECDSA P-256
  • HMAC-SHA256 (supports key sizes between 8 bytes and 64 bytes, inclusive)
  • Triple DES 168

When generating or importing keys using the KeyStore class, you indicate a preference for storing the key in the StrongBox Keymaster by passing true to the setIsStrongBoxBacked() method in either the KeyGenParameterSpec.Builder class or the KeyProtection.Builder class.

Secure key import into Keystore

Android P provides additional key decryption security by adding the ability to import encrypted keys securely into the Keystore using a new ASN.1‑encoded key format. The Keymaster then decrypts the keys in the Keystore, so the content of the keys never appears as plaintext in the device's host memory.

To support secure importing of encrypted keys into the Keystore, complete the following steps:

  1. Generate a key pair that uses the PURPOSE_WRAP_KEY purpose. It's recommended that you add attestation to this key pair, as well.

  2. On a server or machine that you trust, generate the ASN.1 message that the SecureKeyWrapper should contain.

    The wrapper contains the following schema:

    KeyDescription ::= SEQUENCE {
        keyFormat INTEGER,
        authorizationList AuthorizationList
    }
    
    SecureKeyWrapper ::= SEQUENCE {
        wrapperFormatVersion INTEGER,
        encryptedTransportKey OCTET_STRING,
        initializationVector OCTET_STRING,
        keyDescription KeyDescription,
        secureKey OCTET_STRING,
        tag OCTET_STRING
    }
    
  3. Create a WrappedKeyEntry object, passing in the ASN.1 message as a byte array.

  4. Pass this WrappedKeyEntry object into the overload of setEntry() that accepts a Keystore.Entry object.

Option to allow key decryption only on unlocked devices

Android P introduces the unlockedDeviceRequired flag. This option determines whether the Keystore requires the screen to be unlocked before allowing decryption of any in-flight or stored data using the specified key. These types of keys are well suited for encrypting sensitive data to store on disk, such as health or enterprise data. The flag provides users a higher assurance that the data cannot be decrypted while the device is locked should their phone be lost or stolen.

To keep a key safe from decryption while the device is locked, enable the flag by passing true to the setUnlockedDeviceRequired() method. After completing this step, when the user's screen is locked, any attempts to decrypt or sign data using this key fail. A locked device requires a PIN, password, fingerprint, or some other trusted factor before it can be accessed.