Question Crash casting AndroidKeyStoreRSAPrivateKey à RSAPrivateKey


Je suis ce tutoriel: Comment utiliser Android Keystore pour stocker des mots de passe et d'autres informations sensibles. Il est (vaguement) lié à l’application Google Sample: BasicAndroidKeyStore.

Je peux chiffrer mes données à l'aide de la clé publique et décrypter sur des appareils exécutant Lollipop. Cependant, j'ai un Nexus 6 en cours d'exécution marshmallow et cela se bloque en 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 plante:

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 le compte de Android M car je ne vois aucune raison pour laquelle les bibliothèques de cryptage Java auraient changé. Si la version M arrive et que notre application se bloque immédiatement sur M, je serai en grande difficulté.

Je fais quelque chose de mal? L'erreur indique très spécifiquement que vous ne pouvez pas utiliser RSAPrivateKey, alors est-ce que quelqu'un connaît un meilleur moyen d'obtenir RSAPrivateKey à partir de l'entrée?

Merci beaucoup.


37
2017-09-04 14:35


origine


Réponses:


J'ai réussi à faire fonctionner ceci en enlevant le fournisseur de Cipher.getInstance et ne pas conversion en 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 en est, je pense, 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.


55
2017-09-10 10:10



Problème

  1. Nous essayons d'analyser "java.security.Clé privée à java.security.interfaces.RSAPrivateKey"&" java.security.Clé publique à java.security.interfaces.RSAPublicKey". C'est pourquoi nous obtenons ClassCastException.

Solution

  1. Nous n'avons pas besoin d'analyser la clé, nous pouvons directement utiliser "java.security".Clé privée"&" java.security.Clé publique"pour le cryptage et le décryptage.

Cryptage

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry; 
PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey(); // Don't TypeCast to RSAPublicKey

Décryptage

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)entry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey(); // Don't TypeCast to RSAPrivateKey

5
2018-02-06 10:30



J'ai résolu ce problème en suivant également ceci (hormis la réponse de @James ci-dessus): Sur Android 6.0, vous ne devez pas utiliser "AndroidOpenSSL" pour la création de chiffrement, il échouerait avec "Besoin de clé privée ou publique RSA" au lancement du chiffrement pour le déchiffrement. Utilisez simplement Cipher.getInstance ("RSA / ECB / PKCS1Padding") et cela fonctionnera.


4
2017-08-10 20:35



Je ne l'ai pas essayé, mais vous devriez être capable de convertir séparément android.security.keystore.AndroidKeyStoreRSAPrivateKey. Celles-ci devraient être les interfaces dont vous avez besoin:

  1. java.security.PrivateKey
  2. java.security.interfaces.RSAKey

-3
2017-09-04 15:52