我在AndroidKeyStore中有一个公用/专用密钥对,它的生成如下:
val spec = KeyGenParameterSpec.Builder(alias(username), KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT)
.setKeySize(keySize)
.setUserAuthenticationRequired(true)
.setBlockModes(ablockMode)
.setEncryptionPaddings(apaddingMode)
.setCertificateSubject(X500Principal("CN=Itsami Mario, OU=Adventure Unit, O=Plumber Bros, C=US"))
.setKeyValidityStart(Date())
.setKeyValidityEnd(Date(Date().time + 1000 * 60 * 60 * 24 * 7))
.setCertificateSerialNumber(BigInteger(64, SecureRandom()))
.setDigests(digest)
.build()
keyPairGen.initialize(spec)
return keyPairGen.genKeyPair()
我希望每次使用私钥时都需要生物识别身份验证,但是在使用公钥加密时,我不需要生物识别提示。但是,在使用时,我在KeyGeneratior中使用setUserAuthenticationRequired(true)
,然后尝试不先显示BiometricPrompt进行加密,却收到android.security.KeyStoreException
并显示以下消息:Key user not authenticated
我如何要求对 de 加密进行身份验证,而不要求对 en 加密进行身份验证?
答案 0 :(得分:1)
您必须在运行Android 6,棉花糖的设备上进行测试。这是该版本中的known issue,已在Android 7中修复。
要解决此问题,您可以提取公钥的编码并从中创建一个新的PublicKey
对象,如下所示:
PublicKey publicKey = keyPair.getPublicKey();
PublicKey unrestrictedPublicKey =
KeyFactory.getInstance(publicKey.getAlgorithm()).generatePublic(
new X509EncodedKeySpec(publicKey.getEncoded()));
这将适用于所有版本。
请注意,还可以创建在解密时需要身份验证但在加密时不需要身份验证的AES密钥,这很酷(AES比RSA快得多,快得多)。诀窍是在AndroidKeyStore外部生成密钥,然后将其导入两次,一次使用PURPOSE_ENCRYPT
,一次使用PURPOSE_DECRYPT
,在两个不同的别名下,并在DECRYPT版本上指定用户身份验证要求。像这样:
// Note that we do *not* specify "AndroidKeyStore" when we call getInstance()
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey secretKey = keyGen.generateKey();
// This time we do specify "AndroidKeyStore".
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
// Now we import the encryption key, with no authentication requirements.
keyStore.setEntry(
"encrypt_key",
new KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
.setBlockMode(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
// And the decryption key, this time requiring user authentication.
keyStore.setEntry(
"decrypt_key",
new KeyStore.SecretKeyEntry(secretKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockMode(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthentication(true)
.build());
现在,您可以随时使用密钥别名“ encrypt_key”进行加密,而无需用户身份验证,并且可以使用密钥别名“ decrypt_key”进行解密,但前提是您必须进行BiometricPrompt
。 / p>
此方法的缺点是该秘密短暂存在于非安全存储器中。实际上,这仅在创建密钥时攻击者已经破坏了设备的情况下才重要,在这种情况下,您很可能已经丢失了。