java 将 AndroidKeyStoreRSAPrivateKey 转换为 RSAPrivateKey 时崩溃

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32400689/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 20:09:05  来源:igfitidea点击:

Crash casting AndroidKeyStoreRSAPrivateKey to RSAPrivateKey

javaandroidcryptographyjava-securityandroid-6.0-marshmallow

提问by James

I'm following this tutorial: How to use the Android Keystore to store passwords and other sensitive information. It (loosely) ties up with the Google Sample app: BasicAndroidKeyStore.

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

I can encrypt my data using the public key, and I can decrypt on devices running Lollipop. However I have a Nexus 6 running marshmallow and this crashes giving the error:

我可以使用公钥加密我的数据,我可以在运行 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

Here is the code it crashes on:

这是它崩溃的代码:

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

I'm reluctant to put this down to an Android M oddity as I see no reason why the java crypto libraries would have changed. If the M release comes around and our app immediately crashes on M I'll be in big trouble.

我不愿意把这归结为 Android M 的古怪,因为我认为没有理由为什么 Java 加密库会改变。如果 M 版本出现并且我们的应用程序立即在 M 上崩溃,我将遇到大麻烦。

I am doing something wrong? The error very specifically says you can't cast to RSAPrivateKey, so does anyone know a better way to get the RSAPrivateKey from the entry?

我做错了什么?该错误非常明确地说您不能转换为 RSAPrivateKey,那么有人知道从条目中获取 RSAPrivateKey 的更好方法吗?

Many many thanks.

非常感谢。

回答by James

I managed to get this working by removing the Provider from Cipher.getInstance and notcasting to a RSAprivateKey.

我设法通过从 Cipher.getInstance 中删除 Provider 而不是转换为 RSAprivateKey 来实现这一点。

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) entry;

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

I'm not 100% but I think the reason for this I believe is the change in marshmallow from OpenSSL to BoringSSL. https://developer.android.com/preview/behavior-changes.html#behavior-apache-http-client

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

Anyway, the above worked for M and below.

无论如何,以上适用于 M 及以下。

回答by Vasanth

Issue

问题

  1. We are trying to parse "java.security.PrivateKeyto java.security.interfaces.RSAPrivateKey" & "java.security.PublicKeyto java.security.interfaces.RSAPublicKey". That's why we are getting ClassCastException.
  1. 我们正试图解析“java.security。专用密钥对java.security.interfaces中。RSAPrivateKey” java.security。 “&公钥来java.security.interfaces中。RSAPublicKey”。这就是我们收到 ClassCastException 的原因。

Solution

解决方案

  1. We don't need to parse the key, we can directly use the "java.security.PrivateKey" & "java.security.PublicKey" for Encryption & Decryption.
  1. 我们并不需要解析的关键,我们可以直接使用“java.security。专用密钥”和“java.security。公钥”加密与解密。

Encryption

加密

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

Decryption

解密

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

回答by Sid

I resolved this issue by also following this(apart from @James answer above): On Android 6.0 you should not use "AndroidOpenSSL" for cipher creation, it would fail with "Need RSA private or public key" at cipher init for decryption. Simply use Cipher.getInstance("RSA/ECB/PKCS1Padding") and it will work.

我还通过以下方法解决了这个问题(除了上面的@James 回答):在 Android 6.0 上,您不应该使用“AndroidOpenSSL”来创建密码,它会在 cipher init 处因“需要 RSA 私钥或公钥”进行解密而失败。只需使用 Cipher.getInstance("RSA/ECB/PKCS1Padding") 即可。

回答by James

I havn't tried it but you should be able to cast the android.security.keystore.AndroidKeyStoreRSAPrivateKey to the following separately. These should be the interfaces you need:

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

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