【问题标题】:Android encryption can't decrypt data with KeyStore Generated kaypair KeyStoreException: Unknown errorAndroid 加密无法使用 KeyStore 解密数据 Generated kaypair KeyStoreException: Unknown error
【发布时间】:2020-08-28 08:58:13
【问题描述】:

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

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就像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 等)

【问题讨论】:

  • 请将您的代码填写到mcvegetPublicKey是如何实现的,EncryptionConstants.BASE_64_OPTIONSANDROID_KEYSTORE的定义是什么?即使其中一些可以猜到,也存在使用不同假设的风险。特别是,发布加密和解密方法的完整调用,这最终引发异常,以便可以重现
  • 抱歉,忘了说 val publicKey2 = getPublicKey( Base64.encodeToString( publicKey.encoded, EncryptionConstants.BASE_64_OPTIONS ) ) 没有这个代码有同样的行为
  • ANDROID_KEYSTORE = "AndroidKeyStore"
  • 还有一个我发现的,如果我将所有这些代码复制到活动中,一切正常,但如果我从另一个类调用它们,则会出错。

标签: android encryption keystore


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    相关资源
    最近更新 更多