Чтобы помочь вам подтвердить намерения пользователей при инициировании конфиденциальной транзакции, например, совершении платежа, поддерживаемые устройства под управлением Android 9 (уровень API 28) и выше позволяют использовать функцию Android Protected Confirmation. При использовании этого рабочего процесса ваше приложение отображает пользователю запрос на одобрение в виде краткого заявления, подтверждающего его намерение завершить конфиденциальную транзакцию.
Если пользователь принимает это заявление, ваше приложение может использовать ключ из хранилища ключей Android для подписи сообщения, отображаемого в диалоговом окне. Подпись с высокой степенью уверенности подтверждает, что пользователь ознакомился с заявлением и согласен с ним.
Внимание: Android Protected Confirmation не предоставляет пользователю безопасный канал передачи информации. Ваше приложение не может гарантировать конфиденциальность, превышающую гарантии, предоставляемые платформой Android. В частности, не используйте этот рабочий процесс для отображения конфиденциальной информации, которую вы обычно не отображаете на устройстве пользователя.
После того как пользователь подтвердит сообщение, его целостность будет гарантирована, но ваше приложение по-прежнему должно использовать шифрование данных при передаче, чтобы защитить конфиденциальность подписанного сообщения.
Чтобы обеспечить поддержку высоконадежного подтверждения пользователя в вашем приложении, выполните следующие действия:
- Сгенерируйте асимметричный ключ подписи с помощью класса - KeyGenParameterSpec.Builder. При создании ключа передайте- trueв- setUserConfirmationRequired(). Также вызовите- setAttestationChallenge(), передав соответствующее значение вызова, предоставленное проверяющей стороной.
- Зарегистрируйте вновь сгенерированный ключ и сертификат подтверждения вашего ключа у соответствующей проверяющей стороны. 
- Отправьте данные о транзакции на свой сервер и дайте ему возможность сгенерировать и вернуть большой двоичный объект (BLOB) с дополнительными данными . Дополнительные данные могут включать данные, требующие подтверждения, или подсказки для анализа, например, локаль строки запроса. - Для более безопасной реализации BLOB-объект должен содержать криптографический одноразовый номер для защиты от атак повторного воспроизведения и устранения неоднозначности транзакций. 
- Настройте объект - ConfirmationCallback, который информирует ваше приложение, когда пользователь принял приглашение, отображаемое в диалоговом окне подтверждения:- Котлин- 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 // responded to the prompt. } override fun onError(e: Exception?) { super.onError(e) // Handle the exception that the callback captured. } } - Ява- public class MyConfirmationCallback extends ConfirmationCallback { @Override public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) { super.onConfirmed(dataThatWasConfirmed); // Sign dataThatWasConfirmed using your generated signing key. // By completing this process, you generate a signed statement. } @Override public void onDismissed() { super.onDismissed(); // Handle case where user declined the prompt in the // confirmation dialog. } @Override public void onCanceled() { super.onCanceled(); // Handle case where your app closed the dialog before the user // responded to the prompt. } @Override public void onError(Throwable e) { super.onError(e); // Handle the exception that the callback captured. } } - Если пользователь одобряет диалог, вызывается обратный вызов - onConfirmed(). BLOB-объект- dataThatWasConfirmed— это структура данных CBOR , которая содержит, помимо прочего, текст подсказки, увиденный пользователем, а также дополнительные данные, переданные вами в конструктор- ConfirmationPrompt. Используйте ранее созданный ключ для подписи BLOB-объекта- dataThatWasConfirmed, а затем передайте этот BLOB-объект вместе с подписью и данными транзакции обратно проверяющей стороне.- Чтобы в полной мере воспользоваться гарантиями безопасности, которые предлагает Android Protected Confirmation, проверяющая сторона должна выполнить следующие шаги после получения подписанного сообщения: - Проверьте подпись под сообщением, а также цепочку сертификатов подтверждения ключа подписи.
-  Убедитесь, что у сертификата подтверждения установлен флаг TRUSTED_CONFIRMATION_REQUIRED, указывающий на необходимость подтверждения ключа подписи доверенным пользователем. Если ключ подписи — это ключ RSA, проверьте, что у него нет свойствPURPOSE_ENCRYPTилиPURPOSE_DECRYPT.
-  Проверьте extraData, чтобы убедиться, что это подтверждающее сообщение относится к новому запросу и ещё не обработано. Этот шаг защищает от атак повторного воспроизведения.
-  Проанализируйте promptTextна предмет информации о подтверждённом действии или запросе. Помните, чтоpromptText— это единственная часть сообщения, которую пользователь фактически подтвердил. Проверяющая сторона ни при каких обстоятельствах не должна предполагать, что данные, подлежащие подтверждению, включённые вextraDataсоответствуютpromptText.
 
- Добавьте логику, аналогичную показанной в следующем фрагменте кода, для отображения самого диалогового окна: - Котлин- // This data structure varies by app type. This is 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) - Ява- // This data structure varies by app type. This is an example. class ConfirmationPromptData { String sender, receiver, amount; ConfirmationPromptData(String sender, String receiver, String amount) { this.sender = sender; this.receiver = receiver; this.amount = amount; } }; final int MY_EXTRA_DATA_LENGTH = 100; byte[] myExtraData = new byte[MY_EXTRA_DATA_LENGTH]; ConfirmationPromptData myDialogData = new ConfirmationPromptData("Ashlyn", "Jordan", "$500"); Executor threadReceivingCallback = Runnable::run; MyConfirmationCallback callback = new MyConfirmationCallback(); ConfirmationPrompt dialog = (new ConfirmationPrompt.Builder(getApplicationContext())) .setPromptText("${myDialogData.sender}, send ${myDialogData.amount} to ${myDialogData.receiver}?") .setExtraData(myExtraData) .build(); dialog.presentPrompt(threadReceivingCallback, callback); 
Дополнительные ресурсы
Дополнительную информацию о подтверждении защищенной версии Android можно найти в следующих ресурсах.
