web-dev-qa-db-fra.com

Crash casting AndroidKeyStoreRSAPrivateKey vers RSAPrivateKey

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.

40
James

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.

56
James

Problème

  1. Nous essayons d'analyser "Java.security .PrivateKey vers Java.security.interfaces .RSAPrivateKey" & "Java.security .PublicKey vers Java .security.interfaces .RSAPublicKey ". C'est pourquoi nous obtenons ClassCastException.

Solution

  1. Nous n'avons pas besoin d'analyser la clé, nous pouvons utiliser directement "Java.security .PrivateKey" & "Java.security .PublicKey" pour le chiffrement et le déchiffrement.

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
9
Vasanth

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.

5
Sid