将 AndroidKeyStoreRSAPrivateKey 崩溃转换为 RSAPrivateKey

Crash casting AndroidKeyStoreRSAPrivateKey to RSAPrivateKey

提问人:James 提问时间:9/4/2015 最后编辑:jwwJames 更新时间:2/6/2017 访问量:15221

问:

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

我可以使用公钥加密我的数据,并且可以在运行 Lollipop 的设备上解密。但是,我有一个运行棉花糖的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 的更好方法?

非常感谢。

android 加密 java-security android-6.0-marshmallow

评论


答:

-4赞 James 9/4/2015 #1

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

  1. java.security.PrivateKey
  2. java.security.interfaces.RSA协议
63赞 James 9/10/2015 #2

我设法通过从 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赞 deviant 8/6/2016
此解决方案适用于棒棒糖。但是在棉花糖上,它会抛出:java.security.InvalidKeyException:需要 RSA 私钥或公钥
4赞 Sid 8/11/2016
@resp78 在 Android 6.0 上,您不应使用“AndroidOpenSSL”创建密码,它会在密码初始化时失败并显示“需要 RSA 私钥或公钥”进行解密。只需使用 Cipher.getInstance(“RSA/ECB/PKCS1Padding”) 即可工作。
0赞 Misagh Emamverdi 8/16/2016
适用于 marshmallow 和 Android N 预览版 5。谢谢。
0赞 Khang Tran 12/15/2016
您的解决方案不足以防止它在 Andr 6 上崩溃。我试过了,做了更多的事情,设置了encryptPadding:setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)替换ENCRYPTION_PADDING_NONE然后它起作用了。
5赞 Sid 8/11/2016 #3

我也通过以下方法解决了这个问题(除了上面@James答案): 在 Android 6.0 上,您不应使用“AndroidOpenSSL”创建密码,它会在密码初始化时失败并显示“需要 RSA 私钥或公钥”进行解密。只需使用 Cipher.getInstance(“RSA/ECB/PKCS1Padding”) 即可工作。

评论

0赞 Jono 12/16/2016
那么你应该使用什么提供商呢?
14赞 Vasanth 2/6/2017 #4

问题

  1. 我们正在尝试解析“java.security.java.security.interfaces 的 PrivateKeyRSAPrivateKey“ & ”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

评论

6赞 Talha 1/21/2018
给出异常消息:需要 RSA 私钥或公钥。