Android 6.0棉花糖 在几个月前就已向用户公开提供。一路走来,我们一直在更新我们的代码示例集合,希望可以着重介绍一些让您兴奋的新功能。
我们将发布 AsymmetricFingerprintDialog,这是一个新的示例,演示如何在一个客户端或者服务器环境中安全地集成兼容的指纹读取器(如 Nexus Imprint)。
让我们详细了解一下此示例的工作方式,探讨它如何成为此前在公众预览版期间发布的 FingerprintDialog的有益补充。
对称密钥与非对称密钥
Android Fingerprint API 通过谨慎地保留设备上安全硬件中的用户指纹特征来保护用户隐私。这可以防范恶意的入侵者,确保用户即使在不受信任的应用中也可以安全地使用他们的指纹。
Android 还可以为应用程序开发者提供保护,确保在正确识别用户指纹之后才授予用户对安全数据或资源的访问权限。这可防止篡改应用,从而为离线数据和在线交互提供加密级别的安全性。
当用户激活他们的指纹读取器时,实际上他们是在解锁一个由硬件支持的加密保险库。作为开发者,您可以根据应用程序的需求来选择在该保险库中存储哪些类型的关键资料:
对称密钥:与密码相似,对称密钥允许对本地数据进行加密。它非常适合用于保护对数据库或离线文件的访问。 非对称密钥:提供一个由公钥和私钥组成的密钥对。公钥可以通过互联网安全地发送并存储在远程服务器上。稍后,可使用私钥对数据进行签名,以便能够通过公钥验证签名。已签名的数据无法被篡改,可以确定地标识数据的原始作者。通过此方式,非对称密钥可用于网络登录和验证在线交易。类似地,也可使用公钥加密数据,以便该数据只能通过私钥解密。
此示例演示了如何使用非对称密钥对网上购物进行身份验证。如果您想了解如何使用对称密钥,请查看之前发布的 FingerprintDialog 示例。
下面形象地解释了如何使用对称密钥流程将 Android 应用、用户及后端完美地结合在一起:
1设置:创建一个非对称密钥对首先,您需要创建一个非对称密钥对,如下所示:
KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); keyPairGenerator.initialize( new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_SIGN) .setDigests(KeyProperties.DIGEST_SHA256) .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) .setUserAuthenticationRequired(true) .build()); keyPairGenerator.generateKeyPair();
请注意,.setUserAuthenticationRequired(true) 需要此用户使用注册的指纹进行身份验证,以授权私钥的每次使用。
然后,您可以检索已创建的私钥和公钥,如下所示: KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); PublicKey publicKey = keyStore.getCertificate(MainActivity.KEY_NAME).getPublicKey();
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); PrivateKey key = (PrivateKey) keyStore.getKey(KEY_NAME, null); 2注册:向服务器注册公钥其次,您需要将公钥传输到后端,以便将来后端可以验证由该用户授权(即通过与此公钥对应的私钥进行签名)的交易。此示例使用伪后端实现,仅供参考,因此,它模拟公钥的传输,但在现实中,您需要通过网络传输此公钥。
boolean enroll(String userId, String password, PublicKey publicKey); 3让我们开始吧:使用指纹签署交易为让该用户能够验证交易(例如,购买某件商品),请提示用户触摸指纹传感器。
然后,开始侦听指纹,如下所示: Signature.getInstance("SHA256withECDSA"); KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); PrivateKey key = (PrivateKey) keyStore.getKey(KEY_NAME, null); signature.initSign(key); CryptoObject cryptObject = new FingerprintManager.CryptoObject(signature);
CancellationSignal cancellationSignal = new CancellationSignal(); FingerprintManager fingerprintManager = context.getSystemService(FingerprintManager.class); fingerprintManager.authenticate(cryptoObject, cancellationSignal, 0, this, null); 4完成:将此数据发送到后端并进行验证在身份验证成功后,发送已签名的数据(在此示例中为购买交易的商品清单)发送到后端,如下所示:
Signature signature = cryptoObject.getSignature(); // Include a client nonce in the transaction so that the nonce is also signed // by the private key and the backend can verify that the same nonce can't be used // to prevent replay attacks. Transaction transaction = new Transaction("user", 1, new SecureRandom().nextLong()); try { signature.update(transaction.toByteArray()); byte[] sigBytes = signature.sign(); // Send the transaction and signedTransaction to the dummy backend if (mStoreBackend.verify(transaction, sigBytes)) { mActivity.onPurchased(sigBytes); dismiss(); } else { mActivity.onPurchaseFailed(); dismiss(); } } catch (SignatureException e) { throw new RuntimeException(e); }
最后,使用在第 2 步中注册的公钥在后端验证已签名的数据。 @Override public boolean verify(Transaction transaction, byte[] transactionSignature) { try { if (mReceivedTransactions.contains(transaction)) { // It verifies the equality of the transaction including the client nonce // So attackers can't do replay attacks. return false; } mReceivedTransactions.add(transaction); PublicKey publicKey = mPublicKeys.get(transaction.getUserId()); Signature verificationFunction = Signature.getInstance("SHA256withECDSA"); verificationFunction.initVerify(publicKey); verificationFunction.update(transaction.toByteArray()); if (verificationFunction.verify(transactionSignature)) { // Transaction is verified with the public key associated with the user // Do some post purchase processing in the server return true; } } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { // In a real world, better to send some error message to the user } return false; }
此时,您可以假设该用户已正确的使用了自己的指纹通过身份验证,因为,如第 1 步所述,每次使用私钥之前均需要对用户进行身份验证。现在开始在后端进行后处理,并通知用户交易成功! 其他更新的示例 我们还针对 Android For Work API 提供了几个与 Android 6.0棉花糖 相关的更新,供您研读:AppRestrictionEnforcer 和 AppRestrictionSchema 这些示例最初是在推出应用限制功能(作为 Android for Work API 的一部分)时在 Android 5.0 棒棒糖中发布的。AppRestrictionEnforcer 演示作为配置文件所有者如何对其他应用设置限制。AppRestrictionSchema 定义了一些可以由 AppRestrictionEnforcer 控制的限制。此更新显示如何使用 Android 6.0 中引入的 2 个额外的限制类型。
我们希望您喜欢这些更新的示例。如果您对这些示例有任何疑问,请浏览我们的 GitHub 页面,并提交问题或给我们发送拉拽请求。
原文来自【安卓开发者全球博客】:
|