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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:57:25