安卓指纹检测新增手指

8

如何检测用户在我的应用程序中通过指纹认证后是否将新指纹添加到Android设置中?

也就是说,iOS 有一种称为(evaluatedPolicyDomainState)的东西来检测指纹目录中的更改,那么在Android中有什么替代方案呢?

出于安全原因,这需要提示密码。


这在安卓中不可能。 - LaurentY
谢谢,希望他们很快支持这样的事情。 - Sameer
5个回答

16
setUserAuthenticationRequired的文档中可以得知:
引用如下:

一旦安全锁屏被禁用(重新配置为“无”、“滑动”或其他不需要用户认证的模式)或者安全锁屏被强制重置(例如,由设备管理员),密钥将变得不可逆地失效。此外,如果密钥要求每次使用密钥都进行用户验证,则在有新指纹注册或不再注册指纹的情况下,它也将不可逆地失效,除非使用setInvalidatedByBiometricEnrollment(boolean)允许在注册后有效。尝试使用这些密钥初始化加密操作将抛出KeyPermanentlyInvalidatedException异常。

因此,要检查是否自创建指纹相关密钥以来已注册任何新指纹,只需使用该密钥创建一个密码,并尝试对密码进行init调用。如果已注册新指纹,则init调用应触发KeyPermanentlyInvalidatedException

你有关于描述步骤细节的文章链接吗? - Sameer
我不知道有这样的文章。只需按照通常的方式实现指纹认证(我相信您可以在谷歌上找到相关教程),并确保处理文档可能引发的所有异常。您感兴趣的是用于检测是否已注册其他指纹的异常KeyPermanentlyInvalidatedException - Michael
https://medium.com/@ghodasarabhaumik/android-fingerprint-enrolment-detection-detect-fingerprint-added-removed-68f8189766f9 - Bhaumik Ghodasara
这似乎在Android 9 Pie及以下版本中无法正常工作。 - htafoya

2

我可以将所有指纹ID以整数形式获得。

private void getFingerprintInfo(Context context) 
{
    try {
        FingerprintManager fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
        Method method = FingerprintManager.class.getDeclaredMethod("getEnrolledFingerprints");
        Object obj = method.invoke(fingerprintManager);

        if (obj != null) {
            Class<?> clazz = Class.forName("android.hardware.fingerprint.Fingerprint");
            Method getFingerId = clazz.getDeclaredMethod("getFingerId");

            for (int i = 0; i < ((List) obj).size(); i++)
            {
                Object item = ((List) obj).get(i);
                if(item != null)
                {
                    System.out.println("fkie4. fingerId: " + getFingerId.invoke(item));
                }
            }
        }
    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

请参考以下链接:https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/hardware/fingerprint/Fingerprint.java 有一个公共方法getFingerId(),但由于它有"@UnsupportedAppUsage",我们无法调用它。
因此,您需要使用反射来调用该方法。在获取指纹id列表后,您可以对其进行加密并存储在sharedPreference中。
指纹id是存储在设置中的指纹id。
在获取所有指纹id后,您可以确定用户是否添加/删除了指纹。
不需要依赖KeyPermanentlyInvalidatedException。它在Android 8.0中不会被抛出。
祝你好运!……
不要相信谷歌做了这样糟糕的工作。

2
我已经测试过了,到目前为止它似乎是一个不错的方法,但使用它的人应该注意两件事:(1)一些供应商生成的顺序ID(在此处检查https://issuetracker.google.com/issues/65578763#comment26获取更多信息),除此之外,(2)getEnrolledFingerprints不幸已被列入灰名单(在此处检查https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces获取信息),这意味着如果您的应用程序针对API 29+,则无法使用此功能。 - gbazilio
我想补充一下gbazilio所说的,getFingerId()在三星设备上不会返回有效的指纹ID,它返回一个索引(1、2、3等),这对于检查是否添加了新指纹没有用处。<br/>此外,还有4个其他函数,我测试过但不是很有用,如:getName()getGroupId()getDeviceId()describeContents()。<br/>如果将getName()与索引连接起来,则可能有用,但问题在于当您删除最后保存的指纹并创建其他具有相同名称的指纹时。 - Mohamed Ali Benmansour
似乎提供的类中修改了变量,因此无法再使用了。 :( - Navinpd

0
    private String getFingerprintInfo(Context context) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
        FingerprintManager fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
        Method method = FingerprintManager.class.getDeclaredMethod("getEnrolledFingerprints");
        Object obj = method.invoke(fingerprintManager);
        String allFingerPrintInfo = "";
        if (obj != null) {
            Class<?> clazz = Class.forName("android.hardware.fingerprint.Fingerprint");
            for (int i = 0; i < ((List) obj).size(); i++) {
                Object fingerPrint = ((List) obj).get(i);
                if (fingerPrint != null) {
                    String fingerPrintInfo = "";
                    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
                        Parcel p = Parcel.obtain();
                        p.setDataPosition(0);
//                        Method writeToParcel = clazz.getDeclaredMethod("writeToParcel", Parcel.class, Integer.class);
                        clazz.getDeclaredMethods()[1].invoke(fingerPrint, p, 0);
                        p.setDataPosition(0);
                        fingerPrintInfo = p.readString() + "_" + p.readInt() + "_" + p.readLong();
                    } else {
                        Method getFingerId = clazz.getDeclaredMethod("getFingerId");
                        fingerPrintInfo = (String) getFingerId.invoke(fingerPrint);
                    }
                    allFingerPrintInfo += fingerPrintInfo + "*";
                }
            }

        }

        return allFingerPrintInfo;

    }

你的回答可以通过添加额外的支持信息来改进。请编辑以添加更多细节,例如引用或文档,这样其他人就可以确认你的答案是否正确。您可以在帮助中心上找到关于如何撰写良好答案的更多信息。 - Community

-1
/**
 * Generate NIST P-256 EC Key pair for signing and verification
 *
 * @param keyName
 * @param invalidatedByBiometricEnrollment
 * @return
 * @throws Exception
 */
@TargetApi(Build.VERSION_CODES.P)
private KeyPair generateKeyPair(String keyName, boolean invalidatedByBiometricEnrollment) throws Exception {
  KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
  KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyName,
      KeyProperties.PURPOSE_SIGN)
      .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
      .setDigests(KeyProperties.DIGEST_SHA256,
          KeyProperties.DIGEST_SHA384,
          KeyProperties.DIGEST_SHA512)
      // Require the user to authenticate with a biometric to authorize every use of the key
      .setUserAuthenticationRequired(true)
      .setInvalidatedByBiometricEnrollment(invalidatedByBiometricEnrollment);
  keyPairGenerator.initialize(builder.build());
  return keyPairGenerator.generateKeyPair();
}

-4

你无法从应用程序中添加新的指纹。

在你的应用程序内部,你只能访问身份验证指纹方法,该方法通过密钥库检查已注册的指纹。


需要更详细的阐述,关于我们如何检测新指纹注册。 - Jignesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接