直接使用从密钥库加载的 SecretKey 时,密钥用户未通过身份验证

Key user not authenticated when using a SecretKey directly as loaded from keystore

我正在尝试使用 Cipher 和 KeyStore 中加载的 SecretKey 来加密数据,但总是出现此错误:

Caused by: android.security.KeyStoreException: Key user not authenticated

我尝试自己创建 SecretKeySpec,它成功了。我正在使用 android Q 进行测试。

谁能帮我解释一下这个问题?

我的代码

    public Cipher createCipher() {
        Cipher cipher;
        try {
            cipher = Cipher.getInstance(
                    KeyProperties.KEY_ALGORITHM_AES + "/"
                            + KeyProperties.BLOCK_MODE_CBC + "/"
                            + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("Failed to get Cipher", e);
        }
        return cipher;
    }

    public boolean initCipher() {
        try {
            cipher = createCipher();
            SecretKey key = KeyStoreTools.getSecretKey(KEY_NAME);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return true;
        } catch (KeyPermanentlyInvalidatedException e) {
            KeyStoreTools.removeAlias(KEY_NAME);
            return false;
        } catch (Throwable e) {
            throw new RuntimeException("Failed to init Cipher", e);
        }
    }
    public static SecretKey getSecretKey(String keyName) {
        Key key = getKey(keyName);
        if (!keyExists(key)) {
            key = generateKey(keyName);
        }
        return (SecretKey) key;
    }

    public static SecretKey generateKey(String keyName) {
        SecretKey secretKey = null;
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyName,
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
            builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(
                            KeyProperties.ENCRYPTION_PADDING_PKCS7);
            keyGenerator.init(builder.build());
            secretKey = keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException | NoSuchProviderException exc) {
            exc.printStackTrace();
        } catch (Throwable e) {
            throw new RuntimeException("Failed to generateKey", e);
        }
        return secretKey;
    }

    public String encrypt(Cipher cipher, byte[] dataToEncrypt) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(dataToEncrypt);
            byte[] enc = cipher.doFinal(md.digest());
            String base64 = Base64.encodeToString(enc, Base64.DEFAULT);
            return base64;
        } catch (BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e ) {
            e.printStackTrace();
        }
        return "";
    }

我的问题抛出是因为:

我在密钥被标记为成功的用户身份验证之前使用密码进行加密。所以在 onAuthenticationSucceeded 中移动加密并且它起作用了。

希望我的回答对其他人有所帮助。