android.security.KeyStoreException:在少数设备上出现未知错误

And*_*dyB 5 android cryptography rsa aes android-keystore

android.security.KeyStoreException: Unknown error在少数具有不同 Android 版本的设备上使用 (6 - 8)

这是我的密钥生成代码:

final KeyPairGenerator keyGenerator = KeyPairGenerator
                        .getInstance(KeyProperties.KEY_ALGORITHM_RSA, 

ANDROID_KEY_STORE);

keyGenerator.initialize(new KeyGenParameterSpec.Builder(ALIAS,
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                    .setKeySize(2048)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .build());

return keyGenerator.generateKeyPair();
Run Code Online (Sandbox Code Playgroud)

这就是我加载 keyPair 的方式:

if (keyStore.containsAlias(ALIAS))
            {
                KeyStore.Entry entry = keyStore.getEntry(ALIAS, null);
                if (entry != null)
                {
                    if (entry instanceof KeyStore.PrivateKeyEntry)
                    {
                        Log.i(TAG, "KeyPair found.");
                        KeyStore.PrivateKeyEntry pke = (KeyStore.PrivateKeyEntry) entry;
                        Certificate cert = pke.getCertificate();

                        if (cert != null)
                        {
                            return new KeyPair(cert.getPublicKey(), pke.getPrivateKey());
                        }

                        Log.w(TAG, "Cert / Public Key is null");
                    }
                }
            }
Run Code Online (Sandbox Code Playgroud)

这是我的解密代码:

Cipher RSACipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");          

RSACipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(RSACipher.doFinal(base64.decode(textToDecrypt)), "UTF-8");
Run Code Online (Sandbox Code Playgroud)

这是一个失败的解密过程的示例跟踪:

Caused by javax.crypto.IllegalBlockSizeException
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
       at javax.crypto.Cipher.doFinal(Cipher.java:1736)
       at com.examplecompany.security.EncryptionController.decryptAsymmetric(EncryptionController.java:297)
       at com.example.crypto.android2.services.CryptoClass.decryptMessage(CryptoClass.java:684)
       at com.example.crypto.android2.services.CryptoClass.handleDecryption(CryptoClass.java:619)
       at com.example.crypto.android2.services.CryptoClass.doInBackgroundInternal(CryptoClass.java:450)
       at com.example.crypto.android2.services.CryptoClass.doInBackground(CryptoClass.java:165)
       at com.example.crypto.android2.services.CryptoClass.doInBackground(CryptoClass.java:84)
       at android.os.AsyncTask$2.call(AsyncTask.java:333)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)

Caused by android.security.KeyStoreException: Unknown error
       at android.security.KeyStore.getKeyStoreException(KeyStore.java:1137)
       at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
       at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
       at javax.crypto.Cipher.doFinal(Cipher.java:1736)
       at com.examplecompany.security.EncryptionController.decryptAsymmetric(EncryptionController.java:297)
       at com.example.crypto.android2.services.CryptoClass.decryptMessage(CryptoClass.java:684)
       at com.example.crypto.android2.services.CryptoClass.handleDecryption(CryptoClass.java:619)
       at com.example.crypto.android2.services.CryptoClass.doInBackgroundInternal(CryptoClass.java:450)
       at com.example.crypto.android2.services.CryptoClass.doInBackground(CryptoClass.java:165)
       at com.example.crypto.android2.services.CryptoClass.doInBackground(CryptoClass.java:84)
       at android.os.AsyncTask$2.call(AsyncTask.java:333)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
       at java.lang.Thread.run(Thread.java:764)
Run Code Online (Sandbox Code Playgroud)

它在 99.999% 的要在数千台设备上加密的所有消息中运行良好,但有时会失败。你能帮助我吗?

Dan*_*iel 1

刚刚在 SO 的其他问题上找到了类似问题的解决方案

我在Android Issue Tracker上找到了答案,据我了解,为PublicKey解决另一个已知问题而创建的不受限制的 .NET 版本与当前的 .NET 版本不兼容 Cipher。解决这个问题的方法是指定 初始化的OAEPParameterSpec时间Cipher

您需要以下内容作为Cipher初始化代码的第三个参数

OAEPParameterSpec spec = new OAEPParameterSpec(
        "SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);


RSACipher.init(Cipher.DECRYPT_MODE, privateKey, spec); // I added the same to the init in Cipher.ENCRYPT_MODE too
Run Code Online (Sandbox Code Playgroud)