Crash casting AndroidKeyStoreRSAPrivateKey to RSAPrivateKey

我正在遵循本教程:如何使用Android密钥库存储密码和其他敏感信息。它(松散地)与Google示例应用程序联系在一起:BasicAndroidKeyStore

我可以使用公钥加密我的数据,并且可以在运行棒棒糖的设备上解密。但是,我有一个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的奇怪之处,因为我看不出Java加密库会改变的原因。如果M版本出现,我们的应用程序立即在M上崩溃,我将遇到大麻烦。

我做错了什么?该错误非常具体地说您无法强制转换为RSAPrivateKey,那么有谁知道从条目中获取RSAPrivateKey的更好方法吗?

非常感谢。


答案 1

我设法通过从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和以下。


答案 2

问题

  1. 我们正试图解析“java.security.PrivateKey to java.security.interfaces.RSAPrivateKey“ & ”java.security.Java.security.interfaces 的 PublicKeyRSAPublicKey”。这就是为什么我们要得到ClassCastException。

溶液

  1. 我们不需要解析密钥,我们可以直接使用“java.security.PrivateKey“ & ”java.security.PublicKey“,用于加密和解密。

加密

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

推荐