初始化 FingerpringManager.Crypto 对象,获取 AndroidKeyStore 提供程序不支持的加密原语?

2024-05-04

我使用的是安卓FingerPrintManagerAPI 并使用 KeyPairGenerator 创建密钥对,我想用公钥加密密码,然后在用户通过输入指纹进行身份验证时解密,但是一旦我运行我的项目,它就会崩溃并给出

引起原因:java.lang.IllegalArgumentException:加密原语不是 由 AndroidKeyStore 提供商支持

我使用了这里的代码:Android指纹API加解密 https://stackoverflow.com/questions/35992681/android-fingerprint-api-encryption-and-decryption这篇文章说他能够进行加密和解密,我遵循了相同的代码和步骤。 这是我的代码

public KeyStore getKeyStore() {
    try {
        return KeyStore.getInstance("AndroidKeyStore");
    } catch (KeyStoreException exception) {
        throw new RuntimeException("Failed to get an instance of KeyStore", exception);
    }
}

public KeyPairGenerator getKeyPairGenerator() {
    try {
        return KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
    } catch (NoSuchAlgorithmException | NoSuchProviderException exception) {
        throw new RuntimeException("Failed to get an instance of KeyPairGenerator", exception);
    }
}

public Cipher getCipher() {
    try {
        return Cipher.getInstance("RSA");
    } catch (NoSuchAlgorithmException | NoSuchPaddingException exception) {
        throw new RuntimeException("Failed to get an instance of Cipher", exception);
    }
}

private void createKeyPair() {
    try {
        mKeyPairGenerator = getKeyPairGenerator();
        mKeyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_DECRYPT)
                        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
                        .setUserAuthenticationRequired(true)
                        .build());
        mKeyPairGenerator.generateKeyPair();
    } catch (InvalidAlgorithmParameterException exception) {
        throw new RuntimeException(exception);
    }
}

private boolean initCipher(int opmode) {
    try {
        mKeyStore = getKeyStore();
        mKeyStore.load(null);

        mCipher = getCipher();

        if (opmode == Cipher.ENCRYPT_MODE) {

            PublicKey key = mKeyStore.getCertificate(KEY_NAME).getPublicKey();

            PublicKey unrestricted = KeyFactory.getInstance(key.getAlgorithm())
                    .generatePublic(new X509EncodedKeySpec(key.getEncoded()));

            OAEPParameterSpec spec = new OAEPParameterSpec(
                    "SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
            mCipher.init(opmode, unrestricted, spec);
        } else {
            PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);
            mCipher.init(opmode, key);
        }

        return true;
    } catch (KeyPermanentlyInvalidatedException exception) {
        return false;
    } catch (KeyStoreException | CertificateException | UnrecoverableKeyException
            | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | InvalidAlgorithmParameterException exception) {
        throw new RuntimeException("Failed to initialize Cipher", exception);
    }
}


private void encrypt(String password) {
    try {
        initCipher(Cipher.ENCRYPT_MODE);
        byte[] bytes = mCipher.doFinal(password.getBytes());
        enrcyptedPassword = Base64.encodeToString(bytes, Base64.NO_WRAP);
        Log.d("EncryptedText", enrcyptedPassword);
    } catch (IllegalBlockSizeException | BadPaddingException exception) {
        throw new RuntimeException("Failed to encrypt password", exception);
    }
}

private String decryptPassword(Cipher cipher) {
    try {
        initCipher(Cipher.DECRYPT_MODE);
        byte[] bytes = Base64.decode(enrcyptedPassword, Base64.NO_WRAP);
        return new String(cipher.doFinal(bytes));
    } catch (IllegalBlockSizeException | BadPaddingException | RuntimeException exception) {
        throw new RuntimeException("Failed to decrypt password", exception);
    }
}

从这里我正在初始化我的 CryptoObject:

createKeyPair();
    if (initCipher(Cipher.ENCRYPT_MODE)) {
        mCryptoObject = new FingerprintManager.CryptoObject
                (mCipher);
        encrypt("1111");
        if (!isFingerprintAuthAvailable()) {
            return;
        }
        mCancellationSignal = new CancellationSignal();
        mSelfCancelled = false;
        mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null);

我在这一行遇到异常:

mFingerprintManager.authenticate(mCryptoObject, mCancellationSignal, 0 /* flags */, this, null);

@AlexKlyubin 是对的,您不需要使用指纹管理器进行加密,只需解密。为了加密文本,您所需要做的就是调用encrypt(String password)方法同上。

对于解密,您应该使用FingerprintManagerCompat代替FingerprintManager。为了监听指纹事件并解密密码,您需要扩展FingerprintManagerCompat.AuthenticationCallback。我扩展了这个类,并实现了一个回调接口:

public class FingerprintAuthentication extends FingerprintManagerCompat.AuthenticationCallback {

    private final Callback mCallback;

    public FingerprintCallback(Callback callback) {
        mCallback = callback;
    }

    @Override
    public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
        mCallback.onAuthenticationSucceeded(result);
    }

    @Override
    public void onAuthenticationHelp(int messageId, CharSequence message) {
        mCallback.onAuthenticationHelp(messageId, message);
    }

    @Override
    public void onAuthenticationError(int messageId, CharSequence message) {
        mCallback.onAuthenticationError(messageId, message);
    }

    @Override
    public void onAuthenticationFailed() {
        mCallback.onAuthenticationFailed();
    }

    public interface Callback {

        void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result);

        void onAuthenticationHelp(int messageId, CharSequence message);

        void onAuthenticationError(int messageId, CharSequence message);

        void onAuthenticationFailed();
    }
}

有了这个你可以实现Callback界面在你的Fragment or Activity,然后开始监听事件:

private void startListening(boolean cipher) {
    Timber.v("Start listening for fingerprint input");
    mCancellationSignal = new CancellationSignal();
    if(cipher) {
        mFingerprintManager.authenticate(new FingerprintManagerCompat.CryptoObject(mCipher),
                0, mCancellationSignal, new FingerprintAuthentication(this), null);
    } else {
        setStage(Stage.CREDENTIALS);
    }
}

最后,指纹认证成功后才能解密密码:

@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
    try {
        mPassword = decryptPassword(result.getCryptoObject().getCipher());
    } catch (IllegalBlockSizeException | BadPaddingException exception) {
        exception.printStackTrace();
    }
}

基本上,当用户第一次登录时,您希望向他们显示“将来使用指纹”的选项:

如果用户选择此选项并单击登录,则此时您可以调用encrypt()。然后,下次要求用户登录时,您将显示指纹对话框:

这是你打电话的时候startListening(initializeCipher(Cipher.DECRYPT_MODE)).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

初始化 FingerpringManager.Crypto 对象,获取 AndroidKeyStore 提供程序不支持的加密原语? 的相关文章

  • android中listview显示数据库中的数据

    我是安卓新手 我想知道如何在列表视图中显示数据库中的数据 它不会向数据库添加数据 我只是显示我们存储在数据库中的任何内容 请帮助我实现这一目标 提前致谢 使用这些课程可能会对您有所帮助 用于数据库创建 package com example
  • Jetpack 导航:如何从一个嵌套图的子级导航到另一个嵌套图的子级?

    导航结构 MainActivity nav root HomeFragment AuthNestedGraph nav auth BeforeOtpFragment home OtpFragment ProfileNestedGraph n
  • Android 中的列表视图分页

    我有一个列表视图 其中显示了 50 个元素 我决定对视图进行分页 以便视图的每个部分都有 10 个元素 然后单击 下一个 按钮以获取下一个 10 个元素 如何设置10个数据 我关注这篇文章http rakhi577 wordpress co
  • Java-如何将黑白图像加载到二进制中?

    我在 FSE 模式下使用 Java 和 swing 我想将完全黑白图像加载为二进制格式 最好是二维数组 并将其用于基于掩码的每像素碰撞检测 我什至不知道从哪里开始 过去一个小时我一直在研究 但没有找到任何相关的东西 只需将其读入Buffer
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • Intellij 中的 Google OR-Tools:UnsatisfiedLinkError

    我正在建立一个应该使用 Google OR Tools 的 java 框架 下面的代码编译成功 但在运行时抛出异常 Exception in thread main java lang UnsatisfiedLinkError com go
  • 在 IntelliJ 中运行 Spring Boot 会导致 Unable to load 'javax.el.E​​xpressionFactory'

    我正在尝试运行一个简单的 Spring Boot 应用程序 该应用程序具有以下 Maven pom file
  • Jenkins 的代码覆盖率 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Java:java.util.ConcurrentModificationException

    我正在制作 2D 目前正在研究用子弹射击 子弹是一个单独的类 所有项目符号都存储在称为项目符号的数组列表中 当它超出屏幕一侧 Exception in thread main java util ConcurrentModification
  • 屏幕开/关检测

    在这里 我试图确定屏幕是否打开 但按下电源锁定 解锁按钮时它似乎不起作用 应用程序运行没有错误 但 if else 中的代码似乎没有效果 Edited现在代码可以工作了 谢谢Olgun 但媒体播放器播放不会停止 并且每次在屏幕上 离屏时都会
  • 如何找到被点击的JLabel并从中显示ImageIcon?

    这是我的代码 我想知道哪个l单击 然后在新框架中显示该 ImageIcon e getSource 不起作用 final JFrame shirts new JFrame T shirts JPanel panel new JPanel n
  • Android Root 执行 su 带参数

    我在使用参数执行 su 时遇到问题 包含空格 我的 Command java 看起来像这样 public class Command Process process public String executeCommand String c
  • 由于“进程崩溃”,仪器运行失败。

    我想运行以下测试 package com xxx yyy import android content Context import androidx test InstrumentationRegistry import androidx
  • 了解 Spark 中的 DAG

    问题是我有以下 DAG 我认为当需要洗牌时 火花将工作划分为不同的阶段 考虑阶段 0 和阶段 1 有些操作不需要洗牌 那么为什么 Spark 将它们分成不同的阶段呢 我认为跨分区的实际数据移动应该发生在第 2 阶段 因为这里我们需要cogr
  • 在 Nougat 7.1.1 中点击应用程序快捷方式时出现应用程序未安装错误

    我在向现有应用程序添加静态应用程序快捷方式时遇到一些问题 我按照以下步骤操作https developer android com guide topics ui shortcuts html https developer android
  • 警告:无法更改每个人的权限:

    当运行 Java 快速入门示例时https developers google com drive web quickstart java hl hu https developers google com drive web quicks
  • Java:使用 Graph API 在线更新 Sharepoint 上的 docx 文件

    我在使用 Java 在线更新 Sharepoint 上的 docx 文件时遇到问题 首先 我检查了构建 PUT 请求的 URL 此处 并使用此请求 PUT drives drive id items item id content 我首先使
  • 为什么带处理程序的连续自动对焦相机不允许切换相机闪光灯?

    到目前为止我所做的 我已经实现了用于读取二维码的自定义相机 需要继续聚焦相机以获得更好的二维码读取 我的问题当我使用处理程序每 秒聚焦一次时 相机闪光灯开 关按钮不起作用 或者打开和关闭相机闪光灯需要太多时间 当我删除每秒自动对焦相机的代码
  • 如何在不同版本的Google App Engine中使用自定义域名?

    我使用谷歌应用程序引擎作为我的 Android 和 Web 应用程序的服务器 我使用 Android Studio 开发了 Android 应用程序 并使用 Eclipse 开发了 Web 应用程序 我在应用程序引擎中部署了两个版本 第一个
  • 如何捕获 try-with-resource 语句中 close 方法抛出的异常

    我正在读关于try with resourceJava 中的语句可用于指定任意数量的资源 try Resource1 res1 initialize code Resource1 res2 initialize code statement

随机推荐