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 fingerprint authentication dialog
In Android P, the system provides fingerprint 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 fingerprint credential checker.
If your app uses'
FingerprintManager
to display a fingerprint authentication dialog to users, migrate your app's
logic to use
FingerprintDialog
instead, which relies on the system to display the dialog.
High-assurance user 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
ConfirmationDialog 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:
-
Generate an asymmetric signing key using the
KeyGenParameterSpec.Builderclass. When creating the key, passtrueintosetUserConfirmationRequired(). Also, callsetAttestationChallenge(), passing a suitable challenge value provided by the relying party. -
Enroll the newly-generated key and your key's attestation certificate with the appropriate relying party.
-
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.
-
Set up the
ConfirmationCallbackobject that informs your app when the user has accepted the prompt shown in a confirmation dialog:class MyConfirmationCallback : ConfirmationCallback() { override fun onConfirmedByUser(dataThatWasConfirmed: ByteArray?) { super.onConfirmedByUser(dataThatWasConfirmed) // Sign dataThatWasConfirmed using your generated signing key. // By completing this process, you generate a "signed statement". } override fun onDismissedByUser() { super.onDismissedByUser() // Handle case where user declined the prompt in the // confirmation dialog. } override fun onDismissedByApplication() { super.onDismissedByApplication() // 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
onConfirmedByUser()callback is called. ThedataThatWasConfirmedblob 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 theConfirmationDialogbuilder. Your app should use the previously-created key to sign thedataThatWasConfirmedblob. 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
extraDataandpromptTextfromdataThatWasConfirmedand verify thatextraDatamatches what was previously stored. As a final check, your server should check that thepromptTextcorresponds 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 inpromptText. -
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 = ConfirmationDialog.Builder() .setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?") .setExtraData(myExtraData) .build(context) 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:
-
Generate a key pair that uses the
PURPOSE_WRAP_KEYpurpose. It's recommended that you add attestation to this key pair, as well. -
On a server or machine that you trust, generate the ASN.1 message that the
SecureKeyWrappershould 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 } -
Create a
WrappedKeyEntryobject, passing in the ASN.1 message as a byte array. -
Pass this
WrappedKeyEntryobject into the overload ofsetEntry()that accepts aKeystore.Entryobject.


