崩溃将AndroidKeyStoreRSAPrivateKey转换为RSAPrivateKey

我正在学习本教程: 如何使用Android密钥存储密码和其他敏感信息 。 它(松散地)与Google示例应用程序: BasicAndroidKeyStore绑定 。

我可以使用公钥encryption我的数据,并且可以在运行棒棒糖的设备上解密。 不过,我有一个Nexus 6运行棉花糖,这崩溃给错误:

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 

这是它崩溃的代码:

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

我不情愿把这下降到一个Android M怪异,因为我没有看到为什么Javaencryption库会改变的原因。 如果M版本出现了,我们的应用程序立即在M上崩溃,我会遇到很大的麻烦。

我做错了什么? 该错误非常明确地说,你不能强制转换为RSAPrivateKey,所以有谁知道更好的方式从条目获取RSAPrivateKey?

非常感谢。

我设法得到这个工作,通过从Cipher.getInstance中删除提供程序,而不是转换为RSAprivateKey。

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

我不是100%,但我认为这个原因我相信是从OpenSSL到BoringSSL的棉花糖的变化。 https://developer.android.com/preview/behavior-changes.html#behavior-apache-http-client

无论如何,上述工作为M及以下。

问题

  1. 我们试图parsing“java.security。PrivateKey to java.security.interfaces。RSAPrivateKey”&“java.security。PublicKey to java.security.interfaces。RSAPublicKey”。 这就是为什么我们得到ClassCastException。

  1. 我们不需要parsing密钥,我们可以直接使用“java.security。PrivateKey”和“java.security.PublicKey”来进行encryption和解密。

encryption

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

解密

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

我也解决了这个问题(除了上面的@James答案):在Android 6.0上,你不应该使用“AndroidOpenSSL”来创build密码,它将在密码初始化时使用“需要RSA私钥或公钥”来解密。 只需使用Cipher.getInstance(“RSA / ECB / PKCS1Padding”),它将工作。

我没有试过,但你应该能够将android.security.keystore.AndroidKeyStoreRSAPrivateKey分别转换为以下内容。 这些应该是你需要的接口:

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