Java如何生成可通过openssl pkeyutl恢复数据的封装式RSA签名
可恢复原始数据的RSA签名Java实现
问题原因
你当前使用的SHA256withRSA属于带摘要的分离式签名,签名结果是RSA私钥加密后的「SHA256摘要值+摘要算法标识」结构,本身不包含原始业务数据,因此仅支持结合原始数据做完整性校验,无法通过公钥反解恢复原始内容。
实现方案
要支持openssl pkeyutl -verifyrecover命令恢复原始数据,需要使用无摘要的Raw RSA签名模式,直接对原始数据做PKCS#1 v1.5填充后用私钥签名,仅适用于数据长度小于RSA密钥长度-11字节的小数据场景(比如2048位RSA最大支持245字节内容)。
代码实现
import java.security.Signature; import java.security.PrivateKey; import java.security.interfaces.RSAPrivateKey; public class RSASignGenerator { public byte[] generateRecoverableSign(byte[] content, PrivateKey privateKey) throws Exception { // 计算当前密钥支持的最大可签名内容长度(密钥长度单位为位,转换为字节后减11字节填充开销) int keyBitLength = privateKey instanceof RSAPrivateKey ? ((RSAPrivateKey) privateKey).getModulus().bitLength() : 2048; int maxContentLen = keyBitLength / 8 - 11; if (content.length > maxContentLen) { throw new IllegalArgumentException("内容长度超出最大限制,当前密钥最多支持" + maxContentLen + "字节"); } // 使用无摘要RSA签名,底层自动处理PKCS#1 v1.5签名填充 Signature signature = Signature.getInstance("NONEwithRSA"); signature.initSign(privateKey); signature.update(content); return signature.sign(); } }
异常兼容
如果运行时报找不到NONEwithRSA算法的错误,可引入BouncyCastle安全依赖,替换算法名为NONEWITHRSAPKCS1V15即可。
效果验证
将生成的签名字节写入signature文件后,执行指定OpenSSL命令即可直接输出原始内容:
openssl pkeyutl -verifyrecover -pubin -inkey public.pem -in signature
注意事项
- 该方案仅适用于短内容签名场景,长内容必须使用常规分离式签名
- 若需要同时保留摘要防篡改能力,可自行将「摘要值+原始内容」拼接后再签名,恢复后自行校验摘要一致性即可
内容的提问来源于stack exchange,提问作者mrtowel
相关产品推荐
相关产品推荐

