android 生物识别

Biometrics and Cryptography are not the same thing. They are in fact completely independent of each other:

生物识别密码学不是一回事。 它们实际上是彼此完全独立的:

  • Cryptography is about hiding information from an adversary and validating the authenticity of that information. In cryptography, an adversary cannot read encrypted data without the secret key. Also, most cryptographic techniques have anti-tamper mechanisms.

    密码学是关于从对手隐藏信息并验证该信息的真实性。 在密码术中,没有密钥,对手无法读取加密的数据。 同样,大多数密码技术都具有防篡改机制。

  • Biometrics, on the other hand, is for verifying personal identity using bodily measurements. In biometrics, a fingerprint, face, or other aspects of who you are can be used for authentication.

    另一方面, 生物识别技术用于通过身体测量来验证个人身份。 在生物识别技术中,可以使用指纹,面部或其他身份信息进行身份验证。

There are many systems on Android that work together to secure data. Since Android 4.4, the contents of the user’s data partition are encrypted by default. Generally Jetpack Security is a sufficiently developer-friendly option which does the heavy lifting of handling key generation in the AndroidKeyStore and provides abstractions for encrypting Files and SharedPreferences.

Android上有许多可共同保护数据安全的系统。 从Android 4.4开始,默认情况下会加密用户数据分区的内容。 通常, Jetpack Security是一个对开发人员来说足够友好的选项,它极大地减轻了AndroidKeyStore中密钥生成的负担,并提供了用于加密文件和SharedPreferences的抽象。

Even though cryptography doesn’t depend on biometrics, there are cases where it makes sense to use biometrics to protect your encryption key to provide an extra layer of security. These use cases include: enterprise, government, financial, and healthcare. This post explores several places where the Biometric Library’s CryptoObject comes in handy for these use cases. Android’s biometric APIs support the following cryptographic operations — Cipher, MAC, and Signature. In this post, we’ll focus on Cipher.

即使加密不依赖于生物识别,在某些情况下,使用生物识别来保护您的加密密钥以提供额外的安全性也是有意义的。 这些用例包括:企业,政府,金融和医疗保健。 这篇文章探讨了生物识别 CryptoObject在这些用例中非常有用的几个地方。 Android的生物识别API支持以下加密操作-密码,MAC和签名。 在本文中,我们将重点介绍Cipher。

To understand how the two systems come together, let’s first dive a bit into how cryptography works on Android. Then, we will show how biometrics can be used for an added layer of security to make your app more resilient against potential attackers.

为了了解这两个系统是如何结合在一起的,让我们首先深入研究密码学在Android上的工作方式。 然后,我们将展示如何将生物识别技术用于附加的安全层,以使您的应用对潜在的攻击者更具弹性。

Android上的密码学和密钥管理 (Cryptography and key management on Android)

At the core of the Java Crypto API is a Cipher, an object that can be used to perform encryption and decryption of data. To apply a cipher, you need a SecretKey object that references the underlying cryptographic secret key. Only someone with this secret key can use the cipher to decrypt your data. On Android, secret keys should be kept in a secure system called the Android Keystore. The purpose of the Android Keystore is to keep the key material outside of the Android operating system entirely, and in a secure location sometimes referred to as the Trusted Execution Environment (TEE) or the Strongbox. Wherever the key material exists, there’s a potential for an attacker to gain access to it. Therefore the Android Keystore keeps the key material as closely restricted as possible and ensures that the app, the Android userspace, and even the Linux kernel have no access to the material.

Java Crypto API的核心是Cipher ,该对象可用于执行数据的加密和解密。 要应用密码,您需要一个引用基础加密密钥的SecretKey对象。 只有拥有此密钥的人才能使用密码解密您的数据。 在Android上,秘密密钥应保存在称为Android Keystore的安全系统中。 Android密钥库的目的是将密钥资料完全保留在Android操作系统之外,并保存在有时称为“ 可信执行环境 (TEE)”或“ 保险箱”的安全位置。 无论关键材料存在于何处,攻击者都有可能获取它。 因此, Android密钥库会尽可能严格地限制密钥资料,并确保应用程序,Android用户空间甚至Linux内核都无法访问该资料。

Say you wish to encrypt your app’s data on Android. When your app asks the Android KeyStore to create a secret key, the Keystore never actually gives your app the value of the SecretKey. That’s because the SecretKey is never allowed to leave the secure area. The actual process goes like this:

假设您希望在Android上加密应用程序的数据。 当您的应用程序要求Android KeyStore创建密钥时,密钥库实际上不会为您的应用程序提供SecretKey的值。 这是因为绝不允许SecretKey离开安全区域。 实际过程如下:

  1. Your app asks the Android KeyStore for a SecretKey

    您的应用要求Android KeyStore提供SecretKey

  2. The Android Keystore creates the secret key in the secure location (Strongbox or TEE).
    Android密钥库在安全位置(保险箱或TEE)中创建密钥。
  3. The Keystore returns an alias to your app. Only the Keystore knows how to map this alias to your newly-created SecretKey.

    密钥库将别名返回到您的应用程序。 只有密钥库知道如何将此别名映射到您新创建的SecretKey

  4. When your app wants to perform encryption, it asks the Keystore system to do it.
    当您的应用程序想要执行加密时,它会要求Keystore系统进行加密。
  5. The Keystore system takes in the plaintext and the alias, and it returns encrypted data, called ciphertext. (Note that Cipher is just one example. Other artifacts include Signature, Mac, and IdentityCredential.)

    密钥库系统采用纯文本和别名,并返回称为密文的加密数据。 (请注意, Cipher只是一个示例。其他工件包括SignatureMacIdentityCredential 。)

  6. When your app wants to perform decryption, the Keystore system takes in the ciphertext and the alias and returns decrypted data, or plaintext.
    当您的应用程序想要执行解密时,Keystore系统将接收密文和别名,并返回解密后的数据或纯文本。

添加生物识别以要求用户在场 (Add biometrics to require user presence)

Android by default already performs full disk encryption with PIN/pattern/password. You add biometric authentication in your app to ask the system to further guard your secret keys using authentication binding. Even if a device should become compromised and an attacker makes a request, the Android Keystore would still refuse to decrypt the data — unless the attacker can somehow get the user to authenticate with their biometric credentials. Biometric authentication adds an additional layer of security — even on a compromised device — because the hardware managed by Keystore cannot be accessed unless the user is present.

默认情况下,Android已使用PIN /模式/密码执行全盘加密。 您在应用程序中添加了生物特征认证,以要求系统使用身份验证绑定进一步保护您的秘密密钥。 即使设备受到威胁并且攻击者提出了请求,Android Keystore仍然会拒绝解密数据-除非攻击者可以某种方式让用户使用其生物特征凭证进行身份验证。 生物识别身份验证增加了安全性的另一层,即使在受感染的设备上也是如此,这是因为除非存在用户,否则无法访问由密钥库管理的硬件。

The beauty of using biometrics to lock your secret key is that, like all other cryptographic solutions on Android, all sensitive operations between the biometrics system and the Android Keystore system take place in the secure space (TEE/SE), far away from prying eyes. To understand why that’s important, let’s peek under the hood to see how biometrics works and then how the two systems interact.

使用生物识别技术来锁定您的秘密密钥的好处在于,与Android上的所有其他加密解决方案一样,生物识别系统和Android Keystore系统之间的所有敏感操作都在安全的空间(TEE / SE)中进行,不会被撬开。 要了解为什么这很重要,让我们来了解一下生物识别技术是如何工作的,然后看看这两个系统如何相互作用。

在Android Biometric系统的内部 (Under the hood of the Android Biometric system)

Android requires a strong chain of trust. The user must verify that they are who they say they are before they can add a biometric. This decision is made in TEE. At no point in this process is the biometric credential shared with your app or allowed to leave the secure space on the device.

Android需要强大的信任链。 用户必须先验证自己的身份,然后才能添加生物特征。 该决定是在TEE中做出的。 在此过程中,绝不会与您的应用共享生物特征凭证或将其保留在设备上的安全空间。

In general, the Android Biometric system is used in two places, during enrollment (aka account setup) and during authentication (used in apps or keyguard).

通常,Android Biometric系统在注册(即帐户设置)和身份验证(在应用程序或键盘锁中使用)期间用于两个地方。

When the user sets up a new account on their device, the following happens:

当用户在其设备上设置新帐户时,将发生以下情况:

  1. They can choose to enroll their fingerprint (or face or iris).
    他们可以选择注册指纹(或面部或虹膜)。
  2. If the user decides to register a biometric credential, the associated sensor generates a template (also known as embedding) in the TEE.
    如果用户决定注册生物特征证书,则关联的传感器会在TEE中生成模板(也称为嵌入)。

Sometime later, your app allows the user to authenticate using biometrics. The framework, along with the Android Biometrics system in the TEE/SE, handles the actual authentication. This process involves the following steps:

稍后,您的应用允许用户使用生物识别技术进行身份验证。 该框架与TEE / SE中的Android Biometrics系统一起处理实际的身份验证。 此过程涉及以下步骤:

  1. The user presents their biometric credential, such as a fingerprint, on the sensor.
    用户在传感器上显示其生物识别凭证,例如指纹。
  2. The system securely generates an embedding in the TEE and compares it to the embedding that was created during setup. That is, the biometrics system checks if the credential matches one that’s registered with the device.
    系统会在TEE中安全地生成嵌入,并将其与设置过程中创建的嵌入进行比较。 也就是说,生物特征识别系统检查证书是否与在设备中注册的证书匹配。
  3. The framework relays the results to your app: either yes, the credential matches one of the registered templates, or no, the credential was not recognized.
    框架将结果中继到您的应用程序:是,凭据与注册模板之一匹配,否则,否,凭据未被识别。
  4. If a CryptoObject was used, an additional attestation is generated that can be later confirmed by the TEE that the biometric was authentic. This is used to unlock the CryptoObject.

    如果使用了CryptoObject ,则会生成其他证明,TEE随后可以确认该生物特征是真实的。 这用于解锁CryptoObject

That, in a nutshell, is how the biometric system works on Android.

简而言之,这就是生物识别系统在Android上的工作方式。

共同努力:在安全空间中检索私人数据 (Working together: private data retrieval in a secure space)

As you can see, both the Keystore system and the Biometric system on Android provide security measures on their own, especially since they keep their materials and sensitive operations in the secure space (TEE/SE). But data becomes even more secure when you require biometric authentication to unlock a SecretKey that’s associated with your app. That’s because the whole transaction takes place in the secure space (TEE/SE). Still, it’s important to note that biometric authentication is only part of the process for encrypting data; it merely establishes that a user is present.

如您所见,Android上的Keystore系统和Biometric系统均自行提供安全措施,尤其是因为它们将材料和敏感操作保存在安全空间(TEE / SE)中。 但是,当您需要生物识别身份验证来解锁与您的应用程序关联的SecretKey ,数据将变得更加安全。 这是因为整个交易都在安全空间(TEE / SE)中进行。 仍然需要注意的是,生物特征认证仅是加密数据过程的一部分。 它仅确定存在用户。

Here is how the Biometric and the Keystore systems work together to protect your users’ data:

这是Biometric和Keystore系统如何共同保护用户数据的方式:

  1. You, a developer, request that biometric authentication be required to access your secret key by setting setUserAuthenticationRequired(true).

    您(开发人员setUserAuthenticationRequired(true)通过设置setUserAuthenticationRequired(true)来要求要求生物特征认证来访问您的密钥。

  2. When your app requests data that’s associated with the SecretKey, the user gets a prompt to provide a valid biometric credential.

    当您的应用请求与SecretKey关联的数据时,用户会得到提示,要求提供有效的生物特征凭证。

  3. Recall that the biometric sensor communicates securely to the TEE so that neither the framework nor third-party apps are privy to the transaction. Hence, when the user taps the fingerprint sensor, the material is read directly by the TEE.
    回想一下,生物识别传感器可以安全地与TEE进行通信,因此框架和第三方应用程序都无法进行交易。 因此,当用户点击指纹传感器时,TEE将直接读取材料。
  4. If the biometric credential matches a credential that’s registered, the biometric component in the TEE mints a hardware authentication token (HAT). HATs contain an HMAC, which can be used to verify message integrity as well as authenticity.
    如果生物特征凭证与已注册的凭证匹配,则TEE中的生物特征组件将创建一个硬件身份验证令牌(HAT)。 HAT包含一个HMAC,可用于验证消息的完整性和真实性。
  5. The biometric component in the TEE/SE and Keymaster, also within the TEE/SE, share a secret key. Thus, when the framework forwards this HAT to the Keystore system, Keymaster is able to validate the authenticity and integrity of the HAT and unlock the appropriate key.
    TEE / SE中的生物识别组件以及TEE / SE中的Keymaster也共享一个密钥。 因此,当框架将该HAT转发到Keystore系统时,Keymaster能够验证HAT的真实性和完整性并解锁适当的密钥。
  6. The biometric framework invokes your app’s onAuthenticated() callback.

    生物识别框架调用应用程序的onAuthenticated()回调。

Note that because the system is seeking to match biometric credentials with an existing template, by default the system will invalidate all existing keys associated with biometric authentication if a new biometric credential is enrolled. That way, an adversary cannot just register their fingerprint or face and use that to access your private data. The secret key will simply stop working and data dependent on it is essentially lost. Therefore, if your app handles high-value transactions, such as a banking app, monitor the callback that indicates when the user adds a new biometric credential. In that callback, inform the user and ask them if it was intentional before you allow the user to re-register their biometric credentials in your app.

请注意,由于系统正在寻求将生物特征凭证与现有模板进行匹配,因此默认情况下,如果注册了新的生物特征凭证,则系统将使与生物特征认证关联的所有现有密钥无效。 这样,对手就不能仅注册他们的指纹或脸部并将其用于访问您的私人数据。 密钥只会停止工作,并且依赖于它的数据实际上会丢失。 因此,如果您的应用程序处理诸如银行应用程序之类的高价值交易,请监视指示用户何时添加新生物特征凭证的回调。 在该回调中,通知用户并询问他们是否有意,然后再允许用户在您的应用中重新注册其生物特征凭证。

Image for post
Figure 1
图1

加密对象 (The CryptoObject)

Biometrics and Cryptography are so independent that in your own project the code that deals with biometric authentication and the code that deals with encryption/decryption don’t even need to be in the same class. The only place the two systems should ever cross paths in your project is your definition of CryptoObject.

生物特征识别和密码术是如此独立,以至于在您自己的项目中,涉及生物特征认证的代码与涉及加密/解密的代码甚至不需要属于同一类。 在您的项目中,两个系统唯一应该跨越路径的地方就是CryptoObject的定义。

Furthermore, the CryptoObject is just a wrapper that conveniently carries the cipher along to where you might need it. Your app passes in the CryptoObject when it calls biometricPrompt.authenticate(CryptoObject) and the BiometricPrompt returns the exact same CryptoObject to your app’s onAuthenticationSucceeded() callback.

此外, CryptoObject只是一个包装器,可以方便地将密码携带到您可能需要的地方。 您的应用程序在调用biometricPrompt.authenticate(CryptoObject)时传递了CryptoObject ,而BiometricPrompt将完全相同的CryptoObject返回到应用程序的CryptoObject onAuthenticationSucceeded()回调中。

Admittedly, there is a little bit more to the story. The API also uses the CryptoObject parameter as indication that you require a strong biometric sensor for authentication; therefore, if you don’t pass in the parameter, your app’s SecretKey will not be unlocked after the user provides biometric authentication. Furthermore, a CryptoObject is specific to a particular cryptographic operation, and the biometric authentication that the CryptoObject is passed to unlocks only that one operation. This allows the developer to ensure that each use of the key must be authenticated/approved.

诚然,这个故事还有更多内容。 API还使用CryptoObject参数指示您需要强大的生物识别传感器进行身份验证; 因此,如果您不传递参数,则在用户提供生物特征认证后,您应用的SecretKey不会被解锁。 此外, CryptoObject特定于特定的加密操作,并且传递CryptoObject以进行解锁的生物特征认证仅解锁该一个操作。 这使开发人员可以确保必须对密钥的每次使用进行身份验证/批准。

现在来看一些代码 (Now for some code)

Here we will keep the cryptography portion simple. We will demonstrate how to use a Cipher and a SecretKey to symmetrically encrypt/decrypt data. You can learn more about cryptography on Android by reading through the pages on DAC.

在这里,我们将使加密部分保持简单。 我们将演示如何使用CipherSecretKey对称地加密/解密数据。 通过阅读DAC上的页面,您可以了解有关Android加密的更多信息。

To avoid confusion and for separation of concerns, you can put all your cryptography code in a single file and name the file CryptographyManager. The file might look like this.

为避免混淆和关注点分离,可以将所有加密代码放在一个文件中,并将文件命名为CryptographyManager 。 该文件可能如下所示。

interface CryptographyManager {/*** This method first gets or generates an instance of SecretKey and then initializes the Cipher* with the key. The secret key uses [ENCRYPT_MODE][Cipher.ENCRYPT_MODE] is used.*/fun getInitializedCipherForEncryption(keyName: String): Cipher/*** This method first gets or generates an instance of SecretKey and then initializes the Cipher* with the key. The secret key uses [DECRYPT_MODE][Cipher.DECRYPT_MODE] is used.*/fun getInitializedCipherForDecryption(keyName: String, initializationVector: ByteArray): Cipher/*** The Cipher created with [getInitializedCipherForEncryption] is used here*/fun encryptData(plaintext: String, cipher: Cipher): EncryptedData/*** The Cipher created with [getInitializedCipherForDecryption] is used here*/fun decryptData(ciphertext: ByteArray, cipher: Cipher): String}fun CryptographyManager(): CryptographyManager = CryptographyManagerImpl()data class EncryptedData(val ciphertext: ByteArray, val initializationVector: ByteArray)private class CryptographyManagerImpl : CryptographyManager {private val KEY_SIZE: Int = 256val ANDROID_KEYSTORE = "AndroidKeyStore"private val ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCMprivate val ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_NONEprivate val ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AESoverride fun getInitializedCipherForEncryption(keyName: String): Cipher {val cipher = getCipher()val secretKey = getOrCreateSecretKey(keyName)cipher.init(Cipher.ENCRYPT_MODE, secretKey)return cipher}override fun getInitializedCipherForDecryption(keyName: String, initializationVector: ByteArray): Cipher {val cipher = getCipher()val secretKey = getOrCreateSecretKey(keyName)cipher.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, initializationVector))return cipher}override fun encryptData(plaintext: String, cipher: Cipher): EncryptedData {val ciphertext = cipher.doFinal(plaintext.toByteArray(Charset.forName("UTF-8")))return EncryptedData(ciphertext,cipher.iv)}override fun decryptData(ciphertext: ByteArray, cipher: Cipher): String {val plaintext = cipher.doFinal(ciphertext)return String(plaintext, Charset.forName("UTF-8"))}private fun getCipher(): Cipher {val transformation = "$ENCRYPTION_ALGORITHM/$ENCRYPTION_BLOCK_MODE/$ENCRYPTION_PADDING"return Cipher.getInstance(transformation)}private fun getOrCreateSecretKey(keyName: String): SecretKey {// If Secretkey was previously created for that keyName, then grab and return it.val keyStore = KeyStore.getInstance(ANDROID_KEYSTORE)keyStore.load(null) // Keystore must be loaded before it can be accessedkeyStore.getKey(keyName, null)?.let { return it as SecretKey }// if you reach here, then a new SecretKey must be generated for that keyNameval paramsBuilder = KeyGenParameterSpec.Builder(keyName,KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)paramsBuilder.apply {setBlockModes(ENCRYPTION_BLOCK_MODE)setEncryptionPaddings(ENCRYPTION_PADDING)setKeySize(KEY_SIZE)setUserAuthenticationRequired(true)}val keyGenParams = paramsBuilder.build()val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,ANDROID_KEYSTORE)keyGenerator.init(keyGenParams)return keyGenerator.generateKey()}}

To further show that the separation of concerns is indeed real, the CryptographyManagerImpl is declared private so that the client code only sees the interface and its method signatures.

为了进一步表明关注点的分离确实是真实的,将CryptographyManagerImpl声明为私有,以便客户端代码仅看到接口及其方法签名。

After importing the biometrics Gradle dependency, build your PromptInfo object and your BiometricPrompt instance without concerning yourself with cryptography. In the code that presents an authentication dialog, such as MainActivity, set up BiometricPrompt as usual, as shown in the following steps.

导入生物特征信息Gradle依赖性后,无需考虑密码学就可以构建PromptInfo对象和BiometricPrompt实例。 在显示身份验证对话框的代码(例如MainActivity ,像往常一样设置BiometricPrompt ,如以下步骤所示。

1.导入Gradle依赖项 (1. Import the Gradle dependency)

Always use the latest release of the library. As of the publication date for this post, the latest version is 1.0.1.

始终使用该库的最新版本 。 截至本文发布之日,最新版本为1.0.1。

def biometric_version = '1.0.1'
implementation "androidx.biometric:biometric:$biometric_version"

2.创建一个BiometricPrompt实例 (2. Create an instance of BiometricPrompt)

class MainActivity : AppCompatActivity() {...private lateinit var biometricPrompt: BiometricPrompt...override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)...biometricPrompt = createBiometricPrompt()...}private fun createBiometricPrompt(): BiometricPrompt {val executor = ContextCompat.getMainExecutor(this)val callback = object : BiometricPrompt.AuthenticationCallback() {override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {super.onAuthenticationError(errorCode, errString)Log.d(TAG, "$errorCode :: $errString")}override fun onAuthenticationFailed() {super.onAuthenticationFailed()Log.d(TAG, "Authentication failed for an unknown reason")}override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {super.onAuthenticationSucceeded(result)Log.d(TAG, "Authentication was successful")processData(result.cryptoObject)}}//The API requires the client/Activity context for displaying the promptval biometricPrompt = BiometricPrompt(this, executor, callback)return biometricPrompt}
...
}

3.构建一个PromptInfo对象 (3. Build a PromptInfo object)

class MainActivity : AppCompatActivity() {...private lateinit var biometricPrompt: BiometricPromptprivate lateinit var promptInfo: BiometricPrompt.PromptInfo...override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)...biometricPrompt = createBiometricPrompt()promptInfo = createPromptInfo()...}...private fun createPromptInfo(): BiometricPrompt.PromptInfo {val promptInfo = BiometricPrompt.PromptInfo.Builder()// e.g. "Sign in".setTitle(getString(R.string.prompt_info_title))// e.g. "Biometric for My App".setSubtitle(getString(R.string.prompt_info_subtitle))// e.g. "Confirm biometric to continue".setDescription(getString(R.string.prompt_info_description)).setConfirmationRequired(false).setNegativeButtonText(getString(R.string.prompt_info_use_app_password))// .setDeviceCredentialAllowed(true) // Allow PIN/pattern/password authentication.// Also note that setDeviceCredentialAllowed and setNegativeButtonText are// incompatible so that if you uncomment one you must comment out the other.build()return promptInfo}...
}

4.特定于业务的OnClickListener (4. Business-specific OnClickListener)

Now that you have your BiometricPrompt and your PromptInfo, what you do next depends on your app’s business logic. In our case, a user types into an EditText object and then clicks either a Button to encrypt the text or another Button to decrypt any already-encrypted text.

现在您有了BiometricPromptPromptInfo ,接下来要做什么取决于应用程序的业务逻辑。 在我们的例子中,用户键入一个EditText对象,然后单击一个Button来加密文本,或者单击另一个Button来解密任何已经加密的文本。

Hence, for us, there are two click listeners: one calls the user to authenticate in order to encrypt data; another calls the user to authenticate in order to decrypt data. Because these onClick methods must each pass in an instance of CryptoObject when they call biometricPrompt.authenticate(), the Cipher is finally required.

因此,对于我们来说,有两种点击监听器:一种调用用户进行身份验证以加密数据;另一种是调用用户进行身份验证以加密数据。 另一个呼叫用户进行身份验证以解密数据。 因为这些onClick方法在调用biometricPrompt.authenticate()时必须各自传递CryptoObject的实例, CryptoObject最终需要使用Cipher

class MainActivity : AppCompatActivity() {private lateinit var biometricPrompt: BiometricPromptprivate lateinit var promptInfo: BiometricPrompt.PromptInfoprivate var readyToEncrypt: Boolean = false...override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)...biometricPrompt = createBiometricPrompt()promptInfo = createPromptInfo()// e.g. secretKeyName = "biometric_sample_encryption_key"secretKeyName = getString(R.string.secret_key_name)...findViewById<Button>(R.id.encrypt_button).setOnClickListener { authenticateToEncrypt() }findViewById<Button>(R.id.decrypt_button).setOnClickListener { authenticateToDecrypt() }}...private fun authenticateToEncrypt() {readyToEncrypt = trueif (BiometricManager.from(applicationContext).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {val cipher = cryptographyManager.getInitializedCipherForEncryption(secretKeyName)biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))}
}private fun authenticateToDecrypt() {readyToEncrypt = falseif (BiometricManager.from(applicationContext).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {val cipher = cryptographyManager.getInitializedCipherForDecryption(secretKeyName,initializationVector)biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))}}
}

放在一起 (Putting it all together)

For us, the MainActivity class looks as follows in the end:

对于我们来说, MainActivity类的末尾如下所示:

class MainActivity : AppCompatActivity() {private lateinit var textInputView: AppCompatEditTextprivate lateinit var textOutputView: AppCompatTextViewprivate lateinit var biometricPrompt: BiometricPromptprivate lateinit var promptInfo: BiometricPrompt.PromptInfoprivate var readyToEncrypt: Boolean = falseprivate lateinit var cryptographyManager: CryptographyManagerprivate lateinit var secretKeyName: Stringprivate lateinit var ciphertext:ByteArrayprivate lateinit var initializationVector: ByteArrayoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)cryptographyManager = CryptographyManager()// e.g. secretKeyName = "biometric_sample_encryption_key"secretKeyName = getString(R.string.secret_key_name)biometricPrompt = createBiometricPrompt()promptInfo = createPromptInfo()textInputView = findViewById(R.id.input_view)textOutputView = findViewById(R.id.output_view)findViewById<Button>(R.id.encrypt_button).setOnClickListener { authenticateToEncrypt() }findViewById<Button>(R.id.decrypt_button).setOnClickListener { authenticateToDecrypt() }}private fun createBiometricPrompt(): BiometricPrompt {val executor = ContextCompat.getMainExecutor(this)val callback = object : BiometricPrompt.AuthenticationCallback() {override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {super.onAuthenticationError(errorCode, errString)Log.d(TAG, "$errorCode :: $errString")}override fun onAuthenticationFailed() {super.onAuthenticationFailed()Log.d(TAG, "Authentication failed for an unknown reason")}override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {super.onAuthenticationSucceeded(result)Log.d(TAG, "Authentication was successful")processData(result.cryptoObject)}}//The API requires the client/Activity context for displaying the prompt viewval biometricPrompt = BiometricPrompt(this, executor, callback)return biometricPrompt}private fun createPromptInfo(): BiometricPrompt.PromptInfo {val promptInfo = BiometricPrompt.PromptInfo.Builder().setTitle(getString(R.string.prompt_info_title)) // e.g. "Sign in".setSubtitle(getString(R.string.prompt_info_subtitle)) // e.g. "Biometric for My App".setDescription(getString(R.string.prompt_info_description)) // e.g. "Confirm biometric to continue".setConfirmationRequired(false).setNegativeButtonText(getString(R.string.prompt_info_use_app_password)) // e.g. "Use Account Password"// .setDeviceCredentialAllowed(true) // Allow PIN/pattern/password authentication.// Also note that setDeviceCredentialAllowed and setNegativeButtonText are// incompatible so that if you uncomment one you must comment out the other.build()return promptInfo}private fun authenticateToEncrypt() {readyToEncrypt = trueif (BiometricManager.from(applicationContext).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {val cipher = cryptographyManager.getInitializedCipherForEncryption(secretKeyName)biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))}}private fun authenticateToDecrypt() {readyToEncrypt = falseif (BiometricManager.from(applicationContext).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {val cipher = cryptographyManager.getInitializedCipherForDecryption(secretKeyName,initializationVector)biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))}}private fun processData(cryptoObject: BiometricPrompt.CryptoObject?) {val data = if (readyToEncrypt) {val text = textInputView.text.toString()val encryptedData = cryptographyManager.encryptData(text, cryptoObject?.cipher!!)ciphertext = encryptedData.ciphertextinitializationVector = encryptedData.initializationVectorString(ciphertext, Charset.forName("UTF-8"))} else {cryptographyManager.decryptData(ciphertext, cryptoObject?.cipher!!)}textOutputView.text = data}companion object {private const val TAG = "MainActivity"}
}

摘要 (Summary)

In this post, you learned the following:

在这篇文章中,您了解了以下内容:

  • The difference between the cryptography (Keystore) system and the biometric system on Android.
    密码(密钥库)系统和Android上的生物识别系统之间的区别。
  • How to protect your app-specific, secure data by associating it with a biometric.
    如何通过将其与生物识别信息相关联来保护您的应用特定的安全数据。
  • How to combine the two systems using CryptoObject to achieve a higher degree of security.

    如何使用CryptoObject组合两个系统以实现更高的安全性。

  • How to use setUserAuthenticationRequired(true) when defining your SecretKey in order to lock the key using authentication binding.

    定义SecretKey时如何使用setUserAuthenticationRequired(true)以使用身份验证绑定锁定密钥。

  • How to pass your cryptographic cipher to the CryptoObject when you authenticate in order to unlock the secret key.

    身份验证时如何将密码密码传递给CryptoObject以便解锁密钥。

The complete sample Android app demonstrating these concepts is at https://github.com/isaidamier/blogs.biometrics.cryptoBlog.

演示这些概念的完整示例Android应用程序位于https://github.com/isaidamier/blogs.biometrics.cryptoBlog 。

Happy Coding!

编码愉快!

翻译自: https://medium.com/androiddevelopers/using-biometricprompt-with-cryptoobject-how-and-why-aace500ccdb7

android 生物识别

http://www.taodudu.cc/news/show-4140888.html

相关文章:

  • Monash call:什么是生物识别安全 - 定义,系统以及设备
  • Android Q 上的Biometric生物识别
  • 生物识别
  • 语音输入是计算机在哪个领域的应用,语音识别技术是什么_语音识别技术应用领域介绍...
  • 生物识别技术在汽车领域带来了巨大变革
  • telnet客户端 端口23失败
  • 23是个尴尬的年龄
  • MySQL之23:59:59进位
  • 作为ARM Cortex-M家族的继承者 Cortex-M23与M33有哪五大特色?
  • SOT-23封装对应元器件、管脚分布及其功能示意汇总
  • matlab求解微分方程ode23
  • C++设计模式(全23种)
  • 23种常见设计模式详解
  • SOT23(Small Outline Transistor)
  • matlab中ode23s使用方法,MATLAB中ode23函数,龙格库塔函数
  • 23位子网掩码是多少_23位子网掩码包含哪几个网段
  • 香港服务器要个人信息么,香港个人信息应当遵循服务器23.225合法
  • 题目:在C语言中,表达式23|2^5的值是()
  • 宝塔安装phalcon扩展及nginx配置
  • Phalcon介绍
  • Phalcon 上传文件
  • php和phalcon,PHP_phalcon框架使用指南,初次认识phalcon是在刚学php的时
  • php phalcon 中文手册,基础教程 · Phalcon 3.4中文手册 · 看云
  • phalcon 自动加载_创建 Phalcon7 项目
  • Phalcon框架的访问控制列表 ACL(Access Control Lists ACL)
  • phalcon
  • php phacon 关联模型吗,Phalcon模型
  • phalcon mysql in_phalcon:跟踪sql语句
  • phalcon mysql_phalcon mysql_phalcon数据库操作
  • phalcon mysql中文乱码_Phalcon查询语言

android 生物识别_将生物识别提示与cryptoobject一起使用相关推荐

  1. 人脸识别_云端人脸识别-人脸识别SDK+API-人脸识别闸机解决方案

    云端人脸识别-人脸识别SDK+API-人脸识别闸机解决方案 人脸识别闸机-人脸识别闸机解决方案 软硬一体的人脸识别闸机解决方案,提升人员系统化管理的安全性与便捷性 方案构成 针对人员出入的闸机及门禁场 ...

  2. 人脸反光识别和读数识别_云端人脸识别-人脸识别SDK+API-人脸识别闸机解决方案...

    云端人脸识别-人脸识别SDK+API-人脸识别闸机解决方案 人脸识别闸机-人脸识别闸机解决方案 软硬一体的人脸识别闸机解决方案,提升人员系统化管理的安全性与便捷性 方案构成 针对人员出入的闸机及门禁场 ...

  3. python机器视觉车牌识别_机器视觉车牌识别

    机器视觉车牌识别 --车牌号识别系统研究课题 2018年7月10日,许昌学院信息工程(软件职业技术)学院"创出彩"机器视觉智能检测实践队第10天研究正式开展,由于老师有别的事情要忙 ...

  4. 夜间环境人脸识别_动态人脸识别系统的优势

    TH-894是一款天煌电子全新的三防动态人脸识别xt终端采用嵌入式系统.功耗低,运行更稳定.数据更安全.使用高性能智能处理器,基于深度学习的人脸识别与抓拍信息提取,极大的提高了人脸抓拍率.采用夜间红外 ...

  5. python 命名实体识别_命名实体识别的两种方法

    作者:Walker 目录 一.什么是命名实体识别 二.基于NLTK的命名实体识别 三.基于Stanford的NER 四.总结 一 .什么是命名实体识别? 命名实体识别(Named Entity Rec ...

  6. 人脸识别与膜虹识别_当人脸识别遭遇口罩,虹膜识别的机会来了

    本文转自[科技日报]: 当人脸识别遭遇口罩,虹膜识别的机会来了 专家指出虹膜识别标准体系还需进一步完善 本报记者 马爱平 突如其来的新冠肺炎疫情,让人脸识别(Face ID)技术遭遇尴尬,因为一旦用户 ...

  7. 人脸识别与膜虹识别_超越人脸识别——虹膜识别vs静脉识别

    谈及人脸识别,那简直是人尽皆知,应用广泛了.以往玩笑"靠脸"吃饭,如今已不再是玩笑,随着科技发展越发迅猛,我们的生活中德"刷脸"都在慢慢落后.其中"盗 ...

  8. 人脸识别与膜虹识别_当人脸识别遭遇口罩:虹膜识别可作替代方案,比人脸更难伪造...

    突如其来的新冠肺炎疫情,让人脸识别(Face ID)技术遭遇尴尬,因为一旦用户戴上口罩,就难以实现人脸解锁.近日,有消息表示苹果公司iOS系统的更新版将推出一个重要功能,就是"戴口罩也可使用 ...

  9. 人物关系 人脸识别_「人脸识别」可以代替「人像鉴定」吗?

    刷脸支付.刷脸安检.刷脸取快递.刷脸住酒店--人脸识别正在替代钥匙.公交卡.身份证.银行卡等,迅速渗透人们日常生活和工作的方方面面,一个"全民刷脸"的时代正在加速到来. 在司法鉴定 ...

  10. 安卓 图像清晰度识别_最新人脸识别技术方案

    这两年,随着科技的迅速发展,人脸识别已经逐渐成为了新时期生物识别技术应用的重要领域,忘记密码了?没事儿,咱还可以"刷脸"!今天,小编将带大家了解一下最新的人脸识别技术,看看这项技术 ...

最新文章

  1. 入门必备 | 一文读懂神经架构搜索
  2. 新装 Win7 系统装完驱动精灵,一打开到检测界面就卡死——原因与解决方案
  3. 在线编译工具 Jenkins Hudson 的关系
  4. 后台开发技术--接入层设计
  5. 与高通公司合作的Cyanogen团队,Thunderbird等等
  6. java控制double输出的小数点位数
  7. 数据库-子查询概念和分类
  8. Linux 命令 find / -ctime +1 真的是查找1天前创建的文件咩?
  9. java 获取所有线程,Java 实例 - 获取所有线程
  10. 380免费云存储_从四个方面分析:云存储服务的特点、影响
  11. MATLAB清除内存中变量
  12. 【板栗糖GIS】WPS-怎么在表格里设置超链接并修改风格
  13. mywallet android app,记账软件MyWallet
  14. 安卓的第三方sdk是html,第三方SDK目录
  15. 心脏病最新研究进展2021年4月
  16. MATLAB桌角边缘线,构建创意平板折叠桌的数学模型
  17. 论坛上的所有泡MM技巧
  18. 数据分析记录(六)--多元线性回归在SPSS中的实现(步骤及指标含义)
  19. Linux 查看CPU 内存 IO使用率,linux 查看CPU内存 网络 流量 磁盘 IO
  20. JAVA 基础编程练习500题

热门文章

  1. Redis技术架构演进
  2. php doctrine datetime,php – doctrine和Symfony 2中的DateTime字段
  3. 币种对应的转换因子(处理日元台币…
  4. (第二章)HTML基本标记
  5. HTML5实例教程:拼图游戏-何韬-专题视频课程
  6. 【UVa11584】划分成回文串
  7. 关于刷微信投票的js代码
  8. 云服务器选ssd还是hdd_服务器租用主机硬盘使用机械硬盘还是固态硬盘
  9. PAT 1034 有理数四则运算 python
  10. 习惯的力量在于不由主——知道顶个球用,成为习惯才是你的