- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当我们打电话时
mFingerprintManager
.authenticate(cryptoObject, 0 /* flags */, mCancellationSignal, this, null);
我注意到为 cryptoObject
传递 null
是完全可以的。根据FingerprintManager documentation
FingerprintManager.CryptoObject: object associated with the call or null if none required.
根据https://github.com/googlesamples/android-FingerprintDialog ,它显示了创建 CryptoObject
的漫长步骤。
因此,我不确定对于我的用例是否应该使用 CryptoObject
还是 null
。我读过Why crypto object is needed for Android fingerprint authentication?但仍然无法完全理解并决定我的情况。
我的用例如下。
我有一个笔记应用程序的启动锁定屏幕。通常,当用户启用开机锁屏时,需要设置图案绘制。如果他忘记了图案绘制,他可以使用指纹作为替代。该应用程序如下所示
这是源代码。目前,我正在使用 CryptoObject
。然而,根据我的用户反馈,他们中的一小部分人面临着这个新功能的一些应用程序问题。尽管我们在 Google Play Console 中没有看到任何崩溃报告,但我们怀疑在 CryptoObject
生成过程中出现了问题。
因此,如果 CryptoObject
可以替换为 null,我们很乐意这样做以简化我们的代码。
在 FingerprintManager.authenticate 期间,我是否需要 CryptoObject 对象或 null 对于以下用例
/**
* Small helper class to manage text/icon around fingerprint authentication UI.
*/
public class FingerprintUiHelper extends FingerprintManagerCompat.AuthenticationCallback {
private static final String TAG = "FingerprintUiHelper";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String DEFAULT_KEY_NAME = "hello world key name";
private int configShortAnimTime;
private final FingerprintManagerCompat mFingerprintManager;
private final ImageView mIcon;
private final Callback mCallback;
private CancellationSignal mCancellationSignal;
private boolean mSelfCancelled;
private final ResetErrorRunnable resetErrorRunnable = new ResetErrorRunnable();
private final int mSuccessColor;
private final int mAlertColor;
private class ResetErrorRunnable implements Runnable {
@Override
public void run() {
resetError();
}
}
public static FingerprintUiHelper newInstance(ImageView icon, Callback callback, int successColor, int alertColor) {
FingerprintManagerCompat fingerprintManagerCompat = FingerprintManagerCompat.from(WeNoteApplication.instance());
return new FingerprintUiHelper(fingerprintManagerCompat, icon, callback, successColor, alertColor);
}
private void initResource() {
configShortAnimTime = WeNoteApplication.instance().getResources().getInteger(android.R.integer.config_shortAnimTime);
}
/**
* Constructor for {@link FingerprintUiHelper}.
*/
private FingerprintUiHelper(FingerprintManagerCompat fingerprintManager,
ImageView icon, Callback callback, int successColor, int alertColor) {
initResource();
mFingerprintManager = fingerprintManager;
mIcon = icon;
mCallback = callback;
mSuccessColor = successColor;
mAlertColor = alertColor;
}
public boolean isFingerprintAuthAvailable() {
// The line below prevents the false positive inspection from Android Studio
// noinspection ResourceType
return mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.hasEnrolledFingerprints();
}
/**
* Initialize the {@link Cipher} instance with the created key in the
* {@link #createKey(String, boolean)} method.
*
* @param keyName the key name to init the cipher
* @return {@code true} if initialization is successful, {@code false} if the lock screen has
* been disabled or reset after the key was generated, or if a fingerprint got enrolled after
* the key was generated.
*/
private boolean initCipher(Cipher cipher, String keyName) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return false;
}
KeyStore keyStore;
KeyGenerator keyGenerator;
try {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
} catch (KeyStoreException e) {
Log.e(TAG, "", e);
return false;
}
try {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
Log.e(TAG, "", e);
return false;
}
// The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
// for your flow. Use of keys is necessary if you need to know if the set of
// enrolled fingerprints has changed.
try {
keyStore.load(null);
// Set the alias of the entry in Android KeyStore where the key will appear
// and the constrains (purposes) in the constructor of the Builder
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyName,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
// Require the user to authenticate with a fingerprint to authorize every use
// of the key
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
// This is a workaround to avoid crashes on devices whose API level is < 24
// because KeyGenParameterSpec.Builder#setInvalidatedByBiometricEnrollment is only
// visible on API level +24.
// Ideally there should be a compat library for KeyGenParameterSpec.Builder but
// which isn't available yet.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setInvalidatedByBiometricEnrollment(true);
}
keyGenerator.init(builder.build());
keyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
| CertificateException | IOException e) {
Log.e(TAG, "", e);
return false;
}
try {
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(keyName, null);
cipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (Exception e) {
Log.e(TAG, "", e);
return false;
}
}
public void startListening() {
if (!isFingerprintAuthAvailable()) {
return;
}
Cipher defaultCipher;
try {
defaultCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
Log.e(TAG, "", e);
return;
}
if (false == initCipher(defaultCipher, DEFAULT_KEY_NAME)) {
return;
}
FingerprintManagerCompat.CryptoObject cryptoObject = new FingerprintManagerCompat.CryptoObject(defaultCipher);
startListening(cryptoObject);
showIcon();
}
private void startListening(FingerprintManagerCompat.CryptoObject cryptoObject) {
if (!isFingerprintAuthAvailable()) {
return;
}
mCancellationSignal = new CancellationSignal();
mSelfCancelled = false;
// The line below prevents the false positive inspection from Android Studio
// noinspection ResourceType
mFingerprintManager
.authenticate(cryptoObject, 0 /* flags */, mCancellationSignal, this, null);
}
public void stopListening() {
if (mCancellationSignal != null) {
mSelfCancelled = true;
mCancellationSignal.cancel();
mCancellationSignal = null;
}
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
if (!mSelfCancelled) {
if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
mIcon.removeCallbacks(resetErrorRunnable);
showError();
return;
}
if (errMsgId == FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST) {
return;
}
showError();
mIcon.postDelayed(resetErrorRunnable, configShortAnimTime);
}
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
showError();
mIcon.postDelayed(resetErrorRunnable, configShortAnimTime);
}
@Override
public void onAuthenticationFailed() {
showError();
mIcon.postDelayed(resetErrorRunnable, configShortAnimTime);
}
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
mIcon.setColorFilter(mSuccessColor);
mIcon.postDelayed(() -> mCallback.onAuthenticated(), configShortAnimTime);
}
private void showIcon() {
mIcon.setVisibility(View.VISIBLE);
}
private void showError() {
mIcon.setColorFilter(mAlertColor);
}
private void resetError() {
mIcon.clearColorFilter();
}
public interface Callback {
void onAuthenticated();
}
}
最佳答案
您是否需要 CryptoObject
取决于您是否想要执行需要用户使用指纹进行身份验证的加密操作。只有你知道答案。
例如,假设您的应用与服务器进行通信,并且在某个时刻您想向服务器证明用户已在您的应用中使用其指纹进行了身份验证。
您可能采取的方法是,当用户首次在您的应用程序中“注册”时(无论如何完成),您创建一个需要指纹身份验证的 RSA key 对,并与服务器共享公钥。
稍后,当您想向服务器证明用户已通过身份验证时,您可以向服务器请求一些数据进行签名。然后,您使用 RSA 私钥创建一个Signature
,并将其包装到 CryptoObject
中。用户通过身份验证后,您可以对从服务器获取的数据进行签名,并将签名发送到服务器,服务器可以使用公钥验证签名。
与仅仅说“指纹身份验证成功”相比,这增加了额外的安全级别,因为 - 除非设备上存在一些严重的安全缺陷 - 私钥在用户经过身份验证之前无法使用,即使在已取得 root 权限的设备上也是如此。
关于android - 在 FingerprintManager.authenticate 期间,我是否需要 CryptoObject 对象或 null 对于以下用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53853910/
我最近购买了《C 编程语言》并尝试了 Ex 1-8这是代码 #include #include #include /* * */ int main() { int nl,nt,nb;
早上好!我有一个变量“var”,可能为 0。我检查该变量是否为空,如果不是,我将该变量保存在 php session 中,然后调用另一个页面。在这个新页面中,我检查我创建的 session 是否为空,
我正在努力完成 Learn Python the Hard Way ex.25,但我无法理解某些事情。这是脚本: def break_words(stuff): """this functio
我是一名优秀的程序员,十分优秀!