Java数字签名验证失败排查:签名生成与验证代码异常
签名验证始终返回false的问题排查
我一眼就看到了最关键的问题——签名生成和验证过程中的编码转换逻辑不匹配,这是导致验证失败的核心原因。咱们一步步拆解:
1. 生成签名的编码流程
你的generateSignature方法里,对签名字节的处理是两步:
byte[] signatureBytes = Base64.encodeBase64(rsa.sign()); // 原始签名字节 → Base64编码字节 String signature = DatatypeConverter.printHexBinary(signatureBytes); // Base64字节 → Hex字符串
最终返回的是Base64编码结果的Hex字符串,既不是直接的Base64字符串,也不是原始签名的Hex字符串。
2. 验证签名的编码流程
但在validateSignature方法里,你对传入的签名字符串处理逻辑完全错误:
isValid = sig.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
这里你把Hex格式的签名字符串直接转成字节,然后尝试用Base64解码——可signature是Hex字符组成的字符串,它对应的字节是Hex字符的ASCII码,根本不是Base64编码后的字节,Base64解码自然得不到原始的签名字节,验证必然失败。
修复方案
你需要让生成和验证的编码流程完全对称,两种可选方案:
方案一:直接使用Base64字符串作为签名返回值
修改generateSignature,去掉多余的Hex转换,直接返回Base64字符串:
public String generateSignature(String payload) throws Exception{ Signature rsa = Signature.getInstance("SHA256WithRSA/PSS", new BouncyCastleProvider()); rsa.initSign(getPrivateKey("Keys/private_key")); rsa.update(payload.getBytes(StandardCharsets.UTF_8)); byte[] rawSignature = rsa.sign(); String signature = Base64.encodeBase64String(rawSignature); // 直接转Base64字符串 return signature; }
验证代码保持不变(现在签名是标准Base64字符串,直接解码即可):
isValid = sig.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
方案二:使用Hex字符串作为签名返回值
如果一定要用Hex格式,那生成和验证都要基于原始签名字节做Hex转换:
修改generateSignature:
public String generateSignature(String payload) throws Exception{ Signature rsa = Signature.getInstance("SHA256WithRSA/PSS", new BouncyCastleProvider()); rsa.initSign(getPrivateKey("Keys/private_key")); rsa.update(payload.getBytes(StandardCharsets.UTF_8)); byte[] rawSignature = rsa.sign(); String signature = DatatypeConverter.printHexBinary(rawSignature); // 原始签名字节 → Hex字符串 return signature; }
然后修改验证代码,把Hex字符串转回原始签名字节:
isValid = sig.verify(DatatypeConverter.parseHexBinary(signature));
其他潜在问题排查
除了编码问题,还要确认以下几点:
- 确保代码中提前注册了BouncyCastle Provider:
Security.addProvider(new BouncyCastleProvider());,虽然你在getInstance里传入了Provider,但部分环境下需要提前注册才能正常工作。 - 确认公私钥对匹配:
getPrivateKey和getPublicKey读取的确实是同一对密钥文件,没有搞混不同的密钥。 - PSS参数一致性:SHA256WithRSA/PSS的默认盐长度在BouncyCastle中通常等于哈希长度(256位),如果生成和验证都用同一个Provider,参数会自动一致;但如果有自定义参数,要确保两边参数完全相同。
内容的提问来源于stack exchange,提问作者usr_11
相关产品推荐
相关产品推荐

