在应用程序中使用签名实现指纹认证

Posted

技术标签:

【中文标题】在应用程序中使用签名实现指纹认证【英文标题】:Implemented Finger Print Authentication in Application with signature 【发布时间】:2018-10-28 19:45:28 【问题描述】:

android 6.0 以下运行应用程序时遇到问题

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
    KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
    FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
        if (!fingerprintManager.isHardwareDetected()) 
            /**
             * An error message will be displayed if the device does not contain the fin.gerprint hardware.
             * However if you plan to implement a default authentication method,
             * you can redirect the user to a default authentication ctivity from here.
             * Example:
             * 
             */

         else 


            // Checks whether fingerprint permission is set on manifest
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) 

               // permission not granted
             else 

                // Check whether at least one fingerprint is registered
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 

                    // Checks whether lock screen security is enabled or not
                    if (!keyguardManager.isKeyguardSecure()) 
                        // finger print not support

                     else 

                        if (!fingerprintManager.hasEnrolledFingerprints()) 
                        // finger print not enrolled

                         else 

                            /*Amit Verma  EC signature*/
                            createKeyPair();
                            if (initSignature()) 
                                ConstantDeclaration.mCryptoObject = new FingerprintManager.CryptoObject(mSignature);
                            
                        
                    
                
            
        
    

这是生成密钥对的代码

@TargetApi(Build.VERSION_CODES.M)
    private void createKeyPair() 
        // 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 
            // Set the alias of the entry in Android KeyStore where the key will appear
            // and the constrains (purposes) in the constructor of the Builder

            KeyPairGenerator mKeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
            mKeyPairGenerator.initialize(
                    new KeyGenParameterSpec.Builder(KEY_NAME,
                            KeyProperties.PURPOSE_SIGN)
                            .setDigests(KeyProperties.DIGEST_SHA1)
                            .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
                            // Require the user to authenticate with a fingerprint to authorize
                            // every use of the private key
//                            .setUserAuthenticationRequired(true)
                            .setUserAuthenticationRequired(false)
                            .build());
            mKeyPairGenerator.generateKeyPair();
         catch (InvalidAlgorithmParameterException e) 
            throw new RuntimeException(e);
         catch (NoSuchAlgorithmException e) 
            e.printStackTrace();
         catch (NoSuchProviderException e) 
            e.printStackTrace();
        

    

这里是签名启动的代码。

 @TargetApi(Build.VERSION_CODES.M)
    private boolean initSignature() 
        try 
            mKeyStore = KeyStore.getInstance("AndroidKeyStore");
            mKeyStore.load(null);
            PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
//            String strKey = Base64.encodeToString(key.getEncoded(),Base64.DEFAULT);

//            System.out.println("PrivateKey::"+strKey);
            mSignature = Signature.getInstance("SHA1withECDSA");
            mSignature.initSign(key);

            PublicKey publicKey = mKeyStore.getCertificate(KEY_NAME).getPublicKey();
            String strPublicKey = Base64.encodeToString(publicKey.getEncoded(), Base64.DEFAULT);
            Singleton.getInstance().public_key_fp = strPublicKey;

            return true;
         catch (KeyPermanentlyInvalidatedException e) 
            return false;
         catch (Exception e) 
            throw new RuntimeException("Failed to init Cipher", e);
        /*catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
                | NoSuchAlgorithmException | InvalidKeyException e) 
            throw new RuntimeException("Failed to init Cipher", e);
        */
    

此代码运行良好,但是当我在 Android 6.0 以下运行我的应用程序时,启动应用程序时出现异常。

Android version: 19
Device: samsung SM-J100ML
App version: 7
Line Number1: java.lang.Class.newInstanceImpl(Native Method)
Description : java.lang.VerifyError: launcherActivity
    at java.lang.Class.newInstanceImpl(Native Method)
    at java.lang.Class.newInstance(Class.java:1208)
    at android.app.Instrumentation.newActivity(Instrumentation.java:1068)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2493)
    at android.app.ActivityThread.access$800(ActivityThread.java:166)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1283)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5584)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
    at dalvik.system.NativeStart.main(Native Method)

我认为签名导入的问题是 import java.security.Signature;

【问题讨论】:

我的猜测是您声明了某些字段或覆盖了 API 级别 19 上不存在的某些方法。 java.security.Signature 自 API 级别 1 以来一直存在:developer.android.com/reference/java/security/Signature 这不是您的问题。 Signature 本身不应导致VerifyError。但是删除Signature 会强制你删除使用Signature 的其他代码,并且可能该代码是VerifyError 的来源。 诀窍是阅读 logcat..在异常/崩溃发生之前你会发现 class not found 行(崩溃上方的 5-10 行) 尝试删除 KeyPermanentlyInvalidatedException 并在 catch 中只保留 Exception 类 【参考方案1】:

我通过阅读上面评论中所说的 logcat 发现了问题,

Could not find class 'android.security.keystore.KeyGenParameterSpec$Builder'

Could not find class 'android.hardware.fingerprint.FingerprintManager'

我用谷歌搜索了上面的课程,找到了这个链接here

所以我删除 catch 块 InvalidAlgorithmParameterException ,**KeyPermanentlyInvalidatedException** 并替换为 仅父类“异常”

【讨论】:

就像我在上面猜到的那样,它可以工作:) 呵呵... KeyPermanentlyInvalidatedException 被添加到developer.android.com/reference/android/security/keystore/… 中提到的 API 23 中

以上是关于在应用程序中使用签名实现指纹认证的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Form指纹认证

微信小程序 使用HMACSHA1和md5为登陆注册报文添加指纹验证签名

集成指纹与远程登录认证

Google Play 签名 SHA256 指纹发布一次后会改变吗?

如何从 Android KeyGuardmanager 中删除指纹认证?

Phonegap Android 指纹认证插件