基于RSAPrivateKeySpec的Java RSA密钥解密遇BadPaddingException问题求助
javax.crypto.BadPaddingException: Decryption error的常见原因 结合你提到的场景——自定义RSA实现原本正常,但用Java标准库的RSAPrivateKeySpec构建私钥解密时触发填充异常,大概率是以下几个环节出了问题,你可以逐一排查:
填充模式不匹配:Java标准库的RSA解密默认采用
RSA/ECB/PKCS1Padding填充方式。如果你的自定义实现加密时用的是无填充(NoPadding)、自定义非标准填充,或者PKCS1填充的实现不符合规范(比如没有遵循0x00 0x02 + 随机非零字节 + 0x00 + 明文的格式),那标准库解密时就会因为无法验证填充格式而抛出异常。建议你比对自定义加密的填充逻辑和PKCS#1 v1.5的规范,确保两端填充方式完全一致。密钥参数不一致:用
RSAPrivateKeySpec构建私钥时,必须保证传入的modulus(n)和private exponent(d)和自定义密钥生成时的参数完全相同。如果密钥在存储、序列化或字节数组转换过程中出现了截断、字节序错误,或者自定义实现生成d时计算错误(比如逆元计算有误),都会导致标准库拿到的私钥无法正确解密数据,最终表现为填充异常。你可以手动验证:用自定义公钥加密一段已知明文,分别用自定义私钥和标准库私钥解密,看结果是否一致,以此定位是否是密钥参数的问题。数据长度不符合要求:RSA加密的数据长度受密钥长度和填充方式限制,比如1024位密钥用PKCS1填充时,单次加密的明文最多是117字节(
密钥长度/8 - 11),加密后的数据长度必须等于密钥对应的字节数(1024位对应128字节)。如果你的自定义实现允许加密超过限制长度的数据,或者解密时传入的数据长度不对(比如被截断、拼接错误),也会触发填充校验失败。要检查加密后的数据长度是否符合密钥规格,解密时是否正确处理了分段加密的数据(如果有的话)。BigInteger与字节数组转换的符号问题:Java中
BigInteger.toByteArray()会返回带符号的字节数组(若最高位为1,会自动添加一个前导0字节),而标准库的密钥参数要求的是无符号的模和指数。如果你的自定义实现在生成密钥时,对n、d的字节数组处理方式和标准库不一致(比如截断了前导0,或者没有用无符号方式构建BigInteger),会导致密钥参数实际值不匹配,进而解密失败。建议用new BigInteger(1, byteArray)的方式从无符号字节数组构建BigInteger,避免符号位干扰。密钥生成的逻辑漏洞:你的自定义密钥生成方法里,p和q是强素数,但要确认phi的计算是否正确(
(p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE))),e的选择是否满足与phi互质,d是否是e的模phi逆元。如果这些计算环节出错,私钥本身就是无效的,解密出的内容必然是乱码,无法通过填充校验,最终抛出异常。可以手动计算验证这些参数的正确性,比如检查e.multiply(d).mod(phi)是否等于BigInteger.ONE。
内容的提问来源于stack exchange,提问作者user9676331

