初始化FingerpringManager.Crypto对象,获取Crypto原语未被AndroidKeyStore提供程序支持? [英] Initializing FingerpringManager.Crypto Object, getting Crypto primitive not backed by AndroidKeyStore provider?

查看:1038
本文介绍了初始化FingerpringManager.Crypto对象,获取Crypto原语未被AndroidKeyStore提供程序支持?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Android FingerPrintManager API并使用KeyPairGenerator创建密钥对,我想使用公钥加密密码,然后在用户通过使用fingerPrint进行身份验证时进行解密,但是很快我运行我的项目它崩溃,并给出


导致:java.lang.IllegalArgumentException:加密原语不
支持AndroidKeyStore提供者


我从这里使用了代码:



如果用户选择此选项并单击登录,则当您调用 encrypt()时。然后,下次用户需要登录时,您会转发指纹对话框:





这是当你调用 startListening(initializeCipher(Cipher.DECRYPT_MODE))


I am using Android FingerPrintManager API and creating key pair using KeyPairGenerator, i want to encrypt a password with public key and then decrypt when user is authenticated by entring fingerPrint but as soon i run my project it gets crash and gives

Caused by: java.lang.IllegalArgumentException: Crypto primitive not backed by AndroidKeyStore provider

i hved used code from here : Android Fingerprint API Encryption and Decryption this post says that he is able to do ecryption and decryption an di have followed the same code and steps. here is my code

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);
    }
}

and from here i am initializing my 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);

I am getting exception at this line :

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

解决方案

@AlexKlyubin is right, you do not need to use the fingerprint manager for encryption, only decryption. In order to encrypt the text, all you need to do is call the encrypt(String password) method above.

For decryption, you should be using FingerprintManagerCompat instead of FingerprintManager. In order to listen for fingerprint events and decrypt the password, you need to extend the FingerprintManagerCompat.AuthenticationCallback. I extended this class, and implemented a callback interface:

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();
    }
}

With this you can implement the Callback interface in your Fragment or Activity, then start listening for events:

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);
    }
}

Lastly, only after the fingerprint authentication has succeeded can you decrypt the password:

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

Basically, when the user first signs in, you want to show an option for them to "use fingerprint in the future":

If the user selects this option and clicks login, this is when you call encrypt(). Then, the next time the user is required to login, you present the fingerprint dialog instead:

This is when you call startListening(initializeCipher(Cipher.DECRYPT_MODE)).

这篇关于初始化FingerpringManager.Crypto对象,获取Crypto原语未被AndroidKeyStore提供程序支持?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆