java android cryptography java-security android-6.0-marshmallow

java - Crash casting AndroidKeyStoreRSAPrivateKey a RSAPrivateKey



cryptography java-security (4)

Estoy siguiendo este tutorial: Cómo usar el Android Keystore para almacenar contraseñas y otra información confidencial . Se relaciona (sin apretar) con la aplicación Google Sample: BasicAndroidKeyStore .

Puedo encriptar mis datos usando la clave pública, y puedo descifrar en dispositivos que ejecutan Lollipop. Sin embargo, tengo un Nexus 6 corriendo malvavisco y este se bloquea al dar el error:

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

Aquí está el código en el que falla:

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

Soy reacio a atribuir esto a una rareza de Android ya que no veo ninguna razón por la que las bibliotecas de cifrado de java habrían cambiado. Si aparece el lanzamiento M y nuestra aplicación se bloquea inmediatamente en M, tendré grandes problemas.

Estoy haciendo algo mal? El error dice muy específicamente que no se puede convertir a RSAPrivateKey, por lo que ¿alguien sabe una mejor manera de obtener el RSAPrivateKey de la entrada?

Muchas muchas gracias.


Logré hacer que esto funcionara al eliminar el proveedor de Cipher.getInstance y no convertirlo a una RSAprivateKey.

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry; Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding"); output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());

No estoy al 100%, pero creo que la razón de esto es el cambio en marshmallow de OpenSSL a BoringSSL. https://developer.android.com/preview/behavior-changes.html#behavior-apache-http-client

De todos modos, lo anterior funcionó para M y abajo.


No lo he probado pero deberías poder lanzar el android.security.keystore.AndroidKeyStoreRSAPrivateKey a lo siguiente por separado. Estas deberían ser las interfaces que necesita:

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

Resolví este problema al seguir esto (aparte de la respuesta de @James anterior): en Android 6.0 no debe usar "Android OpenSSL" para la creación de cifrado, fallaría con "Necesidad de clave RSA privada o pública" en cifrado init para descifrado. Simplemente use Cipher.getInstance ("RSA / ECB / PKCS1Padding") y funcionará.


Problema

  1. Estamos intentando analizar "java.security. PrivateKey para java.security.interfaces. RSAPrivateKey " y "java.security. PublicKey para java.security.interfaces. RSAPublicKey ". Es por eso que estamos obteniendo ClassCastException.

Solución

  1. No es necesario analizar la clave, podemos usar directamente "java.security. PrivateKey " y "java.security. PublicKey " para cifrado y descifrado.

Cifrado

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

Descifrado

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