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

Android Kotlin RSA 1024公钥解密失败,适配Delphi协议遇阻

问题分析与解决方案

你的核心问题是在Android Kotlin端实现RSA私钥加密内容的公钥解密,这对应RSA的签名验证场景,但由于TurboPower LockBox2(Delphi端)的非标准实现、密钥格式问题,以及不同Padding方案的支持限制,导致解密失败。以下是针对性的解决步骤:


关键限制说明

  1. OAEP Padding的限制:OAEP是标准RSA加密的Padding方案,严格要求「公钥加密、私钥解密」,不支持私钥加密后用公钥解密,因此你尝试的两种OAEP模式必然报错。
  2. PKCS#1 v1.5 Padding的兼容性:PKCS#1 v1.5同时支持两种场景:
    • 加密:公钥加密 → 私钥解密
    • 签名:私钥加密(签名) → 公钥解密(验证)
      你之前用RSA/ECB/PKCS1Padding报错,是因为Delphi端LockBox2的Padding实现与标准Java Provider不匹配,或密钥不符合RSA规范。
  3. 密钥规范问题:你补充的错误(公钥指数偶数、模数偶数、小质因子),说明LockBox2生成的密钥不符合标准RSA要求——标准RSA要求模数是两个大质数的乘积(必须为奇数),公钥指数e必须是奇数(通常用65537即0x10001)。

解决方案步骤

1. 修复密钥规范

放弃使用LockBox2生成密钥,改用标准工具生成符合PKCS#1规范的1024位RSA密钥对:

# 生成PKCS#1格式私钥(PEM)
openssl genrsa -out private.pem 1024
# 导出PKCS#1格式公钥(PEM)
openssl rsa -in private.pem -pubout -out public.pem -RSAPublicKey_out

将PEM文件中的Base64部分(去掉-----BEGIN RSA PUBLIC KEY-----和-----END RSA PUBLIC KEY-----标记)导入到Delphi LockBox2和Android代码中,确保密钥符合标准RSA规范。

2. 确认LockBox2的Padding模式

在Delphi端做测试:用私钥加密一段已知明文(如"test123"),然后用OpenSSL验证解密方式:

  • 若执行以下命令能解密成功,说明LockBox2用的是PKCS#1 v1.5 Padding:
    openssl rsautl -verify -inkey public.pem -pubin -in encrypted.bin -out decrypted.txt -pkcs
    
  • 若用-raw参数能解密,说明LockBox2用的是无Padding的原始RSA:
    openssl rsautl -verify -inkey public.pem -pubin -in encrypted.bin -out decrypted.txt -raw
    

3. Android端代码修正

情况A:LockBox2使用PKCS#1 v1.5 Padding

val publicKeyString = "标准PKCS#1公钥的Base64字符串"
val registerStringFromService = "服务器返回的加密内容Base64"

// 解析PKCS#1格式公钥
val publicKeyBytes = Base64.decode(publicKeyString, Base64.DEFAULT)
val seq = ASN1Sequence.fromByteArray(publicKeyBytes) as DLSequence
val modulus = seq.elementAt(0) as ASN1Integer
val pubExp = seq.elementAt(1) as ASN1Integer
val publicKeySpec = RSAPublicKeySpec(modulus.positiveValue, pubExp.positiveValue)
val kf = KeyFactory.getInstance("RSA")
val publicKey = kf.generatePublic(publicKeySpec)

// 初始化Cipher,使用PKCS#1 v1.5 Padding
val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
cipher.init(Cipher.DECRYPT_MODE, publicKey)

// 解密并转换为字符串
val registerBytesFromService = Base64.decode(registerStringFromService, Base64.DEFAULT)
val decryptedBytes = cipher.doFinal(registerBytesFromService)
val decryptedString = String(decryptedBytes, Charsets.UTF_8)

情况B:LockBox2使用无Padding的原始RSA

// 密钥解析同上
val publicKey = ...

// 初始化无Padding的Cipher
val cipher = Cipher.getInstance("RSA/ECB/NoPadding")
cipher.init(Cipher.DECRYPT_MODE, publicKey)

val registerBytesFromService = Base64.decode(registerStringFromService, Base64.DEFAULT)
val decryptedBytes = cipher.doFinal(registerBytesFromService)

// 去掉LockBox2可能添加的前置填充字节(通常是0),再转字符串
val trimmedBytes = decryptedBytes.dropWhile { it == 0.toByte() }.toByteArray()
val decryptedString = String(trimmedBytes, Charsets.UTF_8)

额外注意事项

  • TurboPower LockBox2是老旧库,其RSA实现可能存在字节序差异(比如小端字节序,而Java默认用大端),若解密后内容乱码,可尝试反转decryptedBytes后再转字符串。
  • 标准场景中,私钥加密/公钥解密应该用Signature类实现签名验证,若后续有机会优化协议,建议调整为「服务器对修改后的内容做签名,客户端验证签名并获取内容」的标准流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 19:35:27