简体   繁体   中英

InvalidKeyException on Google PIxel devices

My app is using Android's keystore to encrypt some data after authenticating with a fingerprint. Users of Google Pixel devices are reporting the following exception being thrown:

java.security.InvalidKeyException: Only SecretKey is supported

My code for encryption basically does this:

_keystore.Load(null);
                _keyGen.Init(new KeyGenParameterSpec.Builder(_keyId,
                    KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
                    .SetBlockModes(KeyProperties.BlockModeCbc)
                    // Require the user to authenticate with a fingerprint to authorize every use
                    // of the key
                    .SetUserAuthenticationRequired(true)
                    .SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
                    .Build());
                _keyGen.GenerateKey();

Cipher _cipher = Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
                                              + KeyProperties.BlockModeCbc + "/"
                                              + KeyProperties.EncryptionPaddingPkcs7);

KeyStore _keystore = KeyStore.GetInstance("AndroidKeyStore");
FingerprintManager _fingerprintManager = (FingerprintManager) Context.GetSystemService(Context.FingerprintService);

_keystore.Load(null);
var key = _keystore.GetKey(_keyId, null);
_cipher.Init(CipherMode.EncryptMode, key);
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
_fingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null);

//OnAuthSucceeded:
var mySecret = _cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt));

It seems like GetKey returns null. Do these new devices only support asymmetric encryption? Does this mean I need to generate a key pair or is there another solution?

try this code of mine if it can help

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/ECB/OAEPWithSHA-256AndMGF1Padding");
    } catch(NoSuchAlgorithmException | NoSuchPaddingException exception) {
        throw new RuntimeException("Failed to get an instance of Cipher", exception);
    }
}

private void createKeyPair() {
    try {
        mKeyPairGenerator.initialize(
                new KeyGenParameterSpec.Builder(KEY_ALIAS, 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("Failed to generate key pair", exception);
    }
}

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

        if(opmode == Cipher.ENCRYPT_MODE) {
            PublicKey key = mKeyStore.getCertificate(KEY_ALIAS).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_ALIAS, null);
            mCipher.init(opmode, key);
        }

        return true;
    } catch (KeyPermanentlyInvalidatedException exception) {
        return false;
    } catch(KeyStoreException | CertificateException | UnrecoverableKeyException
            | IOException | NoSuchAlgorithmException | InvalidKeyException
            | 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());
        String encrypted = Base64.encodeToString(bytes, Base64.NO_WRAP);
        mPreferences.getString("password").set(encrypted);
    } catch(IllegalBlockSizeException | BadPaddingException exception) {
        throw new RuntimeException("Failed to encrypt password", exception);
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM