我正在使用 Android FingerPrintManager
API 并使用 KeyPairGenerator 创建 key 对,我想使用公钥加密密码,然后在用户通过输入 fingerPrint 进行身份验证时解密,但是一旦我运行我的项目它崩溃并给予
Caused by: java.lang.IllegalArgumentException: Crypto primitive not backed by AndroidKeyStore provider
我使用了这里的代码:Android Fingerprint API Encryption and Decryption 这篇文章说他能够进行加密和解密,并且 di 遵循相同的代码和步骤。 这是我的代码
public KeyStore getKeyStore() {
try {
return KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException exception) {
throw new RuntimeException("Failed to get an instance of KeyStore", exception);
}
}
public KeyPairGenerator getKeyPairGenerator() {
try {
return KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException exception) {
throw new RuntimeException("Failed to get an instance of KeyPairGenerator", exception);
}
}
public Cipher getCipher() {
try {
return Cipher.getInstance("RSA");
} catch (NoSuchAlgorithmException | NoSuchPaddingException exception) {
throw new RuntimeException("Failed to get an instance of Cipher", exception);
}
}
private void createKeyPair() {
try {
mKeyPairGenerator = getKeyPairGenerator();
mKeyPairGenerator.initialize(
new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_DECRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setUserAuthenticationRequired(true)
.build());
mKeyPairGenerator.generateKeyPair();
} catch (InvalidAlgorithmParameterException exception) {
throw new RuntimeException(exception);
}
}
private boolean initCipher(int opmode) {
try {
mKeyStore = getKeyStore();
mKeyStore.load(null);
mCipher = getCipher();
if (opmode == Cipher.ENCRYPT_MODE) {
PublicKey key = mKeyStore.getCertificate(KEY_NAME).getPublicKey();
PublicKey unrestricted = KeyFactory.getInstance(key.getAlgorithm())
.generatePublic(new X509EncodedKeySpec(key.getEncoded()));
OAEPParameterSpec spec = new OAEPParameterSpec(
"SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
mCipher.init(opmode, unrestricted, spec);
} else {
PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
mCipher.init(opmode, key);
}
return true;
} catch (KeyPermanentlyInvalidatedException exception) {
return false;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException
| IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | InvalidAlgorithmParameterException exception) {
throw new RuntimeException("Failed to initialize Cipher", exception);
}
}
private void encrypt(String password) {
try {
initCipher(Cipher.ENCRYPT_MODE);
byte[] bytes = mCipher.doFinal(password.getBytes());
enrcyptedPassword = Base64.encodeToString(bytes, Base64.NO_WRAP);
Log.d("EncryptedText", enrcyptedPassword);
} catch (IllegalBlockSizeException | BadPaddingException exception) {
throw new RuntimeException("Failed to encrypt password", exception);
}
}
private String decryptPassword(Cipher cipher) {
try {
initCipher(Cipher.DECRYPT_MODE);
byte[] bytes = Base64.decode(enrcyptedPassword, Base64.NO_WRAP);
return new String(cipher.doFinal(bytes));
} catch (IllegalBlockSizeException | BadPaddingException | RuntimeException exception) {
throw new RuntimeException("Failed to decrypt password", exception);
}
}
我从这里开始初始化我的 CryptoObject:
createKeyPair();
if (initCipher(Cipher.ENCRYPT_MODE)) {
mCryptoObject = new FingerprintManager.CryptoObject
(mCipher);
encrypt("1111");
if (!isFingerprintAuthAvailable()) {
return;
}
mCancellationSignal = new CancellationSignal();
mSelfCancelled = false;
mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null);
我在这一行遇到异常:
mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null);
最佳答案
@AlexKlyubin 是对的,您不需要使用指纹管理器进行加密,只需解密即可。为了加密文本,您需要做的就是调用上面的 encrypt(String password)
方法。
对于解密,您应该使用 FingerprintManagerCompat
而不是 FingerprintManager
。为了监听指纹事件和解密密码,您需要扩展 FingerprintManagerCompat.AuthenticationCallback
。我扩展了这个类,并实现了一个回调接口(interface):
public class FingerprintAuthentication extends FingerprintManagerCompat.AuthenticationCallback {
private final Callback mCallback;
public FingerprintCallback(Callback callback) {
mCallback = callback;
}
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
mCallback.onAuthenticationSucceeded(result);
}
@Override
public void onAuthenticationHelp(int messageId, CharSequence message) {
mCallback.onAuthenticationHelp(messageId, message);
}
@Override
public void onAuthenticationError(int messageId, CharSequence message) {
mCallback.onAuthenticationError(messageId, message);
}
@Override
public void onAuthenticationFailed() {
mCallback.onAuthenticationFailed();
}
public interface Callback {
void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);
void onAuthenticationHelp(int messageId, CharSequence message);
void onAuthenticationError(int messageId, CharSequence message);
void onAuthenticationFailed();
}
}
这样你就可以在你的Fragment
或Activity
中实现Callback
接口(interface),然后开始监听事件:
private void startListening(boolean cipher) {
Timber.v("Start listening for fingerprint input");
mCancellationSignal = new CancellationSignal();
if(cipher) {
mFingerprintManager.authenticate(new FingerprintManagerCompat.CryptoObject(mCipher),
0, mCancellationSignal, new FingerprintAuthentication(this), null);
} else {
setStage(Stage.CREDENTIALS);
}
}
最后,指纹认证成功后才能解密密码:
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
try {
mPassword = decryptPassword(result.getCryptoObject().getCipher());
} catch (IllegalBlockSizeException | BadPaddingException exception) {
exception.printStackTrace();
}
}
基本上,当用户首次登录时,您希望为他们显示一个“将来使用指纹”的选项:
如果用户选择此选项并单击登录,这就是您调用 encrypt()
的时间。然后,下次要求用户登录时,您将显示指纹对话框:
此时调用 startListening(initializeCipher(Cipher.DECRYPT_MODE))
。
关于java - 初始化 FingerpringManager.Crypto 对象,获取不受 AndroidKeyStore 提供程序支持的 Crypto 原语?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38016968/