KeyPermanentlyInvalidatedException 不起作用

hoc*_*yen 5 android private-key android-fingerprint-api

我使用 KeyPermanentlyInvalidatedException 来检测是否添加了新指纹。但它不会抛出 KeyPermanentlyInvalidatedException。

我试过这些步骤:

  1. 项目清单
  2. 创建密钥对
  3. 从私钥初始化签名
  4. 从手机的设置添加新指纹
  5. 再次尝试从私钥初始化签名但它不会抛出 KeyPermanentlyInvalidatedException

我也从 stackoverflow找到了这个链接,但它没有帮助我。

从文件:

一旦安全锁屏被禁用(重新配置为无、滑动或其他不对用户进行身份验证的模式)或当安全锁屏被强制重置(例如,由设备管理员)时,密钥将不可逆转地失效。此外,如果密钥要求每次使用密钥都进行用户身份验证,则一旦注册新指纹或不再注册指纹,它也将不可逆转地失效,除非使用 setInvalidatedByBiometricEnrollment(boolean) 来允许注册后的有效性。尝试使用此类密钥初始化加密操作将引发 KeyPermanentlyInvalidatedException。

这是我的代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_authenticate);

    mButtonTest = findViewById(R.id.button_test);
    mButtonTest.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            buttonTestOnClick();
        }
    });

    boolean isFirstTime = PreferenceManager.getInstances().getFirstTime();
    PreferenceManager.getInstances().setFirstTime(false);

    if (isFirstTime) {
        createKeyPair();
    }
}

private void buttonTestOnClick() {
    boolean result = initSignature();
    Log.e("iii", "Create signature result: " + result);

    boolean isFirstTime = PreferenceManager.getInstances().getFirstTime();

    if (result) {
        if (isFirstTime) {
            enroll();
        }
        startListening();
    }
}


/**
 * Generates an asymmetric key pair in the Android Keystore. Every use of the private key must
 * be authorized by the user authenticating with fingerprint. Public key use is unrestricted.
 */
public void createKeyPair() {
    try {
        mKeyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
    } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
        throw new RuntimeException("Failed to get an instance of KeyPairGenerator", e);
    }

    // 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
        mKeyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(KEY_NAME,
                        KeyProperties.PURPOSE_SIGN)
                        .setDigests(KeyProperties.DIGEST_SHA256)
                        .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
                        // Require the user to authenticate with a fingerprint to authorize
                        // every use of the private key
                        .setUserAuthenticationRequired(true)
                        .build());
        mKeyPairGenerator.generateKeyPair();
    } catch (InvalidAlgorithmParameterException e) {
        throw new RuntimeException(e);
    }
}


/**
 * Initialize the {@link Signature} instance with the created key in the
 * {@link #createKeyPair()} method.
 *
 * @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 initSignature() {
    // Create keystore
    try {
        mKeyStore = KeyStore.getInstance("AndroidKeyStore");
    } catch (KeyStoreException e) {
        throw new RuntimeException("Failed to get an instance of KeyStore", e);
    }

    // Create signature
    try {
        mSignature = Signature.getInstance("SHA256withECDSA");
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Failed to get an instance of Signature", e);
    }


    try {
        mKeyStore.load(null);
        PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
        mSignature.initSign(key);
        return true;
    } catch (KeyPermanentlyInvalidatedException e) {
        return false;
    } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
            | NoSuchAlgorithmException | InvalidKeyException e) {
        throw new RuntimeException("Failed to init Cipher", e);
    }
}


private void enroll() {
    try {
        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        PublicKey publicKey = keyStore.getCertificate(AuthenticateActivity.KEY_NAME).getPublicKey();
        // Provide the public key to the backend. In most cases, the key needs to be transmitted
        // to the backend over the network, for which Key.getEncoded provides a suitable wire
        // format (X.509 DER-encoded). The backend can then create a PublicKey instance from the
        // X.509 encoded form using KeyFactory.generatePublic. This conversion is also currently
        // needed on API Level 23 (Android M) due to a platform bug which prevents the use of
        // Android Keystore public keys when their private keys require user authentication.
        // This conversion creates a new public key which is not backed by Android Keystore and
        // thus is not affected by the bug.
        KeyFactory factory = KeyFactory.getInstance(publicKey.getAlgorithm());
        X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKey.getEncoded());
        PublicKey verificationKey = factory.generatePublic(spec);
        //mStoreBackend.enroll("user", "password", verificationKey);
    } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException |
            IOException | InvalidKeySpecException e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是initSignature()函数总是返回 true。