首页 > 解决方案 > Android 加密无法使用 KeyStore 解密数据 Generated kaypair KeyStoreException: Unknown error

问题描述

我正在尝试通过 RSA 与 Android 加密和解密数据。这是我的加密/解密代码

fun encryptStringRSA(str: String, publicKey: PublicKey): String{
    val encryptedBytes: ByteArray? = Cipher.getInstance("RSA/NONE/PKCS1Padding").run {
        init(Cipher.ENCRYPT_MODE, publicKey)
        doFinal(str.toByteArray(Charsets.UTF_8))
    }

    return Base64.encodeToString(encryptedBytes, EncryptionConstants.BASE_64_OPTIONS)
}

fun decryptStringRSA(str: String, privateKey: PrivateKey): String{
    val decryptedBytes: ByteArray = Cipher.getInstance("RSA/NONE/PKCS1Padding").run {
        init(Cipher.DECRYPT_MODE, privateKey)
        doFinal(Base64.decode(str, EncryptionConstants.BASE_64_OPTIONS))
    }

    return String(decryptedBytes)
}

当我使用 Node JS 服务器生成的密钥(这是用于同步算法参数)时效果很好,但是现在我需要在 Android 端生成密钥,这就是我这样做的方式:

fun generateRSAKeyPair(keyAlias: String): KeyPair {
    val startDate = GregorianCalendar()
    val endDate = GregorianCalendar()
    endDate.add(Calendar.YEAR, 1)

    val keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE)

    val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(keyAlias,
        KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY or KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT).run {
        setDigests(KeyProperties.DIGEST_SHA256)
        setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
        setKeySize(2048)
        setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
        setCertificateNotBefore(startDate.time)
        setCertificateNotAfter(endDate.time)
        setUserAuthenticationRequired(true)
        setUserAuthenticationValidityDurationSeconds(30)
        build()
    }

    keyPairGenerator.initialize(parameterSpec)
    val keyPair = keyPairGenerator.genKeyPair()

    val publicKey = getPublicKey(
        Base64.encodeToString(
            keyPair.public.encoded,
            EncryptionConstants.BASE_64_OPTIONS
        )
    )
    return KeyPair(publicKey, keyPair.private)
}

然后从 Keystore 获取:

fun initKeyPair(keyAlias: String): KeyPair{
    try {
        val keyStore: KeyStore = KeyStore.getInstance(ANDROID_KEYSTORE).apply {
            load(null)
        }

        val entry: KeyStore.Entry = keyStore.getEntry(keyAlias, null)
        val privateKey: PrivateKey? = (entry as KeyStore.PrivateKeyEntry).privateKey
        val publicKey: PublicKey? = keyStore.getCertificate(keyAlias).publicKey

        return if (privateKey == null || publicKey == null) {
            KeyHolderUtils().generateRSAKeyPair(keyAlias)
        } else {
            val publicKey2 = getPublicKey(
                Base64.encodeToString(
                    publicKey.encoded,
                    EncryptionConstants.BASE_64_OPTIONS
                )
            )
            KeyPair(publicKey2, privateKey)
        }
    }catch (ex: Exception){
        return KeyHolderUtils().generateRSAKeyPair(keyAlias)
    }
}

加密、签名和验证有效,但是当我尝试解密时总是得到 en KeyStoreException: Unknown error

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:526)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 
 Caused by: java.io.IOException: javax.crypto.IllegalBlockSizeException
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:133)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:202)
    at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46)
    at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72)
    at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37)
    at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97)
    at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64)
    at android.view.View.performClick(View.java:7201)
    at android.view.View.performClickInternal(View.java:7170)
    at android.view.View.access$3500(View.java:806)
    at android.view.View$PerformClick.run(View.java:27562)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7682)
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 
 Caused by: javax.crypto.IllegalBlockSizeException
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:519)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:531)
    at javax.crypto.Cipher.doFinal(Cipher.java:2002)
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:130)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:202) 
    at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46) 
    at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72) 
    at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37) 
    at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97) 
    at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64) 
    at android.view.View.performClick(View.java:7201) 
    at android.view.View.performClickInternal(View.java:7170) 
    at android.view.View.access$3500(View.java:806) 
    at android.view.View$PerformClick.run(View.java:27562) 
    at android.os.Handler.handleCallback(Handler.java:883) 
    at android.os.Handler.dispatchMessage(Handler.java:100) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7682) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 
 Caused by: android.security.KeyStoreException: Unknown error
    at android.security.KeyStore.getKeyStoreException(KeyStore.java:1303)
    at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:531) 
    at javax.crypto.Cipher.doFinal(Cipher.java:2002) 
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:130) 
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:202) 
    at com.test.communication.encryption.utils.EncryptionUtils.decryptStringRSA(EncryptionUtils.kt:46) 
    at com.test.communication.encryption.AndroidEncryptionBase.decryptMessage(AndroidEncryptionBase.kt:72) 
    at com.test.communication.encryption.AndroidEncryption.decryptMessage(AndroidEncryption.kt:37) 
    at com.test.communication.server.MessageServiceImpl.send(MessageServiceImpl.kt:97) 
    at com.test.app.presentation.ui.main.CommunicationActivity$initButtons$1.onClick(CommunicationActivity.kt:64) 
    at android.view.View.performClick(View.java:7201) 
    at android.view.View.performClickInternal(View.java:7170) 
    at android.view.View.access$3500(View.java:806) 
    at android.view.View$PerformClick.run(View.java:27562) 
    at android.os.Handler.handleCallback(Handler.java:883) 
    at android.os.Handler.dispatchMessage(Handler.java:100) 
    at android.os.Looper.loop(Looper.java:214) 
    at android.app.ActivityThread.main(ActivityThread.java:7682) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 

我尝试了不同的块(ECB,NONE)和填充(NOPadding,PKCS1Padding,OAEPPadding,OAEPwithSHA-1andMGF1Padding 和 OAEPwithSHA-256andMGF1Padding)组合,并根据组合更改KeyGenParameterSpec参数setEncryptionPaddingssetBlockModes因为我在 SO 中看到了类似Android KeyStoreException Unknown Error的帖子 并尝试更改代码喜欢它,但总是有同样的例外。顺便说一句,在不同的模拟器和真实设备 OnePlus 6 上尝试结果相同 - KeyStoreException:未知错误

更新!!!我发现一些奇怪的想法,如果我将所有这些代码复制到 Activity 一切正常,但是当我从另一个类调用它时会出错。例如:

fun fire(){

    val str = "test"
    val encryptionUtils = EncryptionUtils()

    generateRSAKeyPair("testKeys")

    val encryptStringRSA = encryptionUtils.encryptStringRSA(str, keyPair.public)
    val decryptStringRSA = decryptStringRSA(encryptStringRSA, keyPair.private)
    println(decryptStringRSA)
}

这段代码工作正常,但是

fun fire(){

    val str = "test"
    val encryptionUtils = EncryptionUtils()

    generateRSAKeyPair("testKeys")

    val encryptStringRSA = encryptionUtils.encryptStringRSA(str, keyPair.public)
    val decryptStringRSA = encryptionUtils.decryptStringRSA(encryptStringRSA, keyPair.private)
    println(decryptStringRSA)
}

此代码导致异常。EncryptionUtils 类的代码与 Activity 中的代码 100% 相同(我的意思是 encryptStringRSA、decryptStringRSA 和其他)

标签: androidencryptionkeystore

解决方案


我找到了临时解决方案。我只是重命名 EncryptionUtils -> EncryptionHelper 现在它可以工作了,但是一段时间后错误又回来了,每次重命名都不是解决方案!希望有人对此有所帮助


推荐阅读