You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android KeyStore RSA解密抛出Invalid input length异常排查

问题:Android KeyStore RSA解密抛出Invalid input length异常

开发Android应用时基于Android KeyStore实现RSA加解密,密钥生成、加密流程运行正常,解密环节抛出android.security.KeyStoreException: Invalid input length异常,耗时两天排查各类方案未解决。

现有实现代码

密钥生成代码

private var provider = 
fun generateKeys(): KeyPair {
    val keyStore = KeyStore.getInstance(provider)
    val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, provider);
    val parmeterSpec = KeyGenParameterSpec.Builder(
        ALIAS,
        KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT
    ).run {
        setUserAuthenticationRequired(false)
        setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
        setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
        // 参考帖子建议添加,用于解决历史问题
        setRandomizedEncryptionRequired(true) 
        build()
    }

    kpg.initialize(parmeterSpec)
    val kp = kpg.generateKeyPair()
    return kp
}

加密代码

private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
fun encrypt(message: String, publicKey: PublicKey) : String? {
    // 参考帖子建议MGF使用SHA1
    val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
    val cipher = Cipher.getInstance(method)
    cipher.init(Cipher.ENCRYPT_MODE, publicKey)

    val encryptedBytes = cipher.doFinal(message.toByteArray())
    return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
}

解密代码

private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
fun decrypt(encrypted: String, privateKey: PrivateKey) : String? {
    val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
    val cipher = Cipher.getInstance(method)
    cipher.init(Cipher.DECRYPT_MODE, privateKey, spec)
    val decryptedBytes = cipher.doFinal(encrypted.toByteArray())
    return Base64.encodeToString(decryptedBytes, Base64.DEFAULT)
}

调用逻辑

val keyPair = generateKeys()
val message = "a simple message"

val encryptedMessage = encrypt(message, keyPair.public)
val result = decrypt(encryptedMessage, keyPair.private)

已尝试排查方案

  • 验证密文长度:RSA 2048位密钥最大支持256字节输入,当前加密后密文长度仅175字节,不存在超长问题
  • 处理Base64换行:解密前替换密文字符串中的\n字符,未解决问题
  • 参考多篇同类问题技术帖调整MGF摘要参数、KeyStore配置,均未生效

异常堆栈

Caused by: javax.crypto.IllegalBlockSizeException
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:513)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055)
    at com.sandwich.testkeystore.MainActivity.decrypt(MainActivity.kt:132)
    at com.sandwich.testkeystore.MainActivity.onCreate(MainActivity.kt:65)
    at android.app.Activity.performCreate(Activity.java:7822)
    at android.app.Activity.performCreate(Activity.java:7811)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1328)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3452)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3620) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2183) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:241) 
    at android.app.ActivityThread.main(ActivityThread.java:7604) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941) 
Caused by: android.security.KeyStoreException: Invalid input length
    at android.security.KeyStore.getKeyStoreException(KeyStore.java:1303)
    at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)
    at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:217)
    at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
    at javax.crypto.Cipher.doFinal(Cipher.java:2055) 
    at com.sandwich.testkeystore.MainActivity.decrypt(MainActivity.kt:132) 
    at com.sandwich.testkeystore.MainActivity.onCreate(MainActivity.kt:65) 
    at android.app.Activity.performCreate(Activity.java:7822) 
    at android.app.Activity.performCreate(Activity.java:7811) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1328) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3452) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3620) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2183) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:241) 
    at android.app.ActivityThread.main(ActivityThread.java:7604) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941) 

解决方案

代码存在3个核心问题,按顺序修复即可:

  1. Base64处理逻辑完全错误
    加密返回的是密文字节经Base64编码后的字符串,解密时需要先对该字符串做Base64解码得到原始密文字节,再传入Cipher解密。当前代码直接调用encrypted.toByteArray()拿到的是Base64字符串本身的字节数组,长度和原始密文不一致,直接触发Invalid input length异常。
    同时解密得到的是明文字节,直接转UTF-8字符串即可,不需要再做Base64编码。
  2. 加密初始化未传入OAEP参数,加解密参数不匹配
    加密函数中定义了OAEPParameterSpec但初始化Cipher时未传入,会导致加密时使用默认MGF参数,和解密时传入的自定义参数不一致,即使修复Base64问题也会抛出填充错误。
  3. KeyStore provider未赋值
    密钥生成代码中provider变量为空,需要固定赋值为"AndroidKeyStore",否则会调用系统默认加密提供者,无法使用KeyStore的安全能力。

修复后代码

密钥生成代码补全

// 固定指定AndroidKeyStore提供者
private var provider = "AndroidKeyStore"
private const val ALIAS = "your_key_alias"

fun generateKeys(): KeyPair {
    val keyStore = KeyStore.getInstance(provider)
    val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, provider)
    val parameterSpec = KeyGenParameterSpec.Builder(
        ALIAS,
        KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT
    ).run {
        setUserAuthenticationRequired(false)
        setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
        setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
        setRandomizedEncryptionRequired(true) 
        build()
    }
    kpg.initialize(parameterSpec)
    return kpg.generateKeyPair()
}

修复后加密函数

private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
fun encrypt(message: String, publicKey: PublicKey) : String? {
    val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
    val cipher = Cipher.getInstance(method)
    // 加密时传入OAEP参数,保证加解密参数一致
    cipher.init(Cipher.ENCRYPT_MODE, publicKey, spec)
    val encryptedBytes = cipher.doFinal(message.toByteArray(Charsets.UTF_8))
    return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
}

修复后解密函数

private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
fun decrypt(encrypted: String, privateKey: PrivateKey) : String? {
    val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
    val cipher = Cipher.getInstance(method)
    cipher.init(Cipher.DECRYPT_MODE, privateKey, spec)
    // 先Base64解码得到原始密文字节
    val encryptedBytes = Base64.decode(encrypted, Base64.DEFAULT)
    val decryptedBytes = cipher.doFinal(encryptedBytes)
    // 明文字节直接转字符串,无需二次Base64编码
    return String(decryptedBytes, Charsets.UTF_8)
}

额外注意事项

  • RSA加密有长度限制,若需加密超过190字节(OAEP填充下2048位密钥的最大明文长度)的内容,不要直接用RSA加密明文,需采用混合加密方案:生成随机AES密钥加密明文,再用RSA公钥加密AES密钥,解密时先RSA解密得到AES密钥,再用AES解密密文。
  • 字符串转字节数组时统一指定Charsets.UTF_8字符集,避免不同系统默认字符集不一致导致的乱码问题。

内容的提问来源于stack exchange,提问作者Horia Pantelimon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:18:43