Je suis ce tutoriel: Comment utiliser le magasin de clés Android pour stocker les mots de passe et autres informations sensibles . Il est (vaguement) lié à l'application Google Sample: - BasicAndroidKeyStore .
Je peux crypter mes données à l'aide de la clé publique et je peux décrypter sur les appareils exécutant Lollipop. Cependant, j'ai un Nexus 6 exécutant Marshmallow et cela se bloque donnant l'erreur:
Java.lang.RuntimeException: Unable to create application com.Android.test: Java.lang.ClassCastException: Android.security.keystore.AndroidKeyStoreRSAPrivateKey cannot be cast to Java.security.interfaces.RSAPrivateKey
Voici le code sur lequel il se bloque:
KeyStore.Entry entry;
//Get Android KeyStore
ks = KeyStore.getInstance(KeystoreHelper.KEYSTORE_PROVIDER_Android_KEYSTORE);
// Weird artifact of Java API. If you don't have an InputStream to load, you still need to call "load", or it'll crash.
ks.load(null);
// Load the key pair from the Android Key Store
entry = ks.getEntry(mAlias, null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry;
//ERROR OCCURS HERE::
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKeyEntry.getPrivateKey();
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
output.init(Cipher.DECRYPT_MODE, rsaPrivateKey);
Je suis réticent à mettre cela sur une bizarrerie Android M car je ne vois aucune raison pour laquelle les bibliothèques de cryptographie Java auraient changé. Si la version M venait autour et notre application se bloque immédiatement sur M, je vais avoir de gros ennuis.
Je fais quelque chose de mal? L'erreur indique très précisément que vous ne pouvez pas caster vers RSAPrivateKey, alors quelqu'un sait-il une meilleure façon d'obtenir la RSAPrivateKey à partir de l'entrée?
Merci beaucoup.
J'ai réussi à faire fonctionner cela en supprimant le fournisseur de Cipher.getInstance et pas le cast vers une RSAprivateKey.
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry;
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
Je ne suis pas à 100%, mais je pense que la raison de cela, je crois, est le changement de Marshmallow d'OpenSSL à BoringSSL. https://developer.Android.com/preview/behavior-changes.html#behavior-Apache-http-client
Quoi qu'il en soit, ce qui précède a fonctionné pour M et ci-dessous.
Problème
Solution
Cryptage
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey(); // Don't TypeCast to RSAPublicKey
Déchiffrement
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey(); // Don't TypeCast to RSAPrivateKey
J'ai résolu ce problème en suivant également ceci (à part la réponse @James ci-dessus): Sur Android 6.0, vous ne devriez pas utiliser "AndroidOpenSSL" pour la création de chiffrement, il échouerait avec "Besoin de RSA privé ou public "au début du chiffrement pour le déchiffrement. Utilisez simplement Cipher.getInstance (" RSA/ECB/PKCS1Padding ") et cela fonctionnera.