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

C#使用RSA验证Node.js生成的签名失败问题咨询

核心问题1:填充模式不匹配

你最初版本的C#代码全部使用RSASignaturePadding.Pkcs1(即PKCS#1 v1.5填充),但Node.js端明确指定了RSA_PKCS1_PSS_PADDING,两种填充模式完全不兼容,不可能互相验证。

核心问题2:PSS参数未对齐

你修改代码使用PSS填充后仍验证失败的原因是PSS填充的附属参数没有对齐:

  • Node.js crypto模块默认PSS填充的saltLength等于哈希算法的输出长度,SHA256对应盐长度为32字节,同时MGF1摘要算法默认和签名哈希一致(即SHA256)
  • 如果你使用BouncyCastle库,不能直接用SHA256WITHRSA作为算法名,这个是对应PKCS#1 v1.5填充的算法标识,PSS模式的算法标识为SHA256WITHRSAANDMGF1,还需要显式指定参数。

核心问题3:早期JS签名逻辑错误

你最开始的JS签名函数存在逻辑错误:没有调用update传入待签名数据,误写了keyLike参数,等于你最初生成的签名本身就是错误的,修改后加了cSign.update(verifyData)才是正确的签名逻辑。


正确可互操作的代码示例

1. Node.js 签名逻辑(固定版本)

function signature(verifyData) {
  const sign = crypto.createSign('sha256');
  sign.update(verifyData, 'utf8');
  return sign.sign({
    key: privateKey,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
    saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST // 显式指定盐长度等于哈希长度,避免环境默认值差异
  }).toString('base64');
}

2. .NET 原生验证逻辑

public bool VerifyData(string rawData, string base64Signature)
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(rawData);
    byte[] signatureBytes = Convert.FromBase64String(base64Signature);
    
    using var rsa = RSA.Create();
    string publicKeyPem = File.ReadAllText("public.txt");
    rsa.ImportFromPem(publicKeyPem);
    
    // 显式指定PSS填充,盐长度默认等于哈希长度,和Node.js配置对齐
    return rsa.VerifyData(dataBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}

3. BouncyCastle 签名/验证逻辑

// 签名
public string SignDataBouncyCastle(string rawData, AsymmetricKeyParameter privateKey)
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(rawData);
    // PSS模式算法标识
    var signer = SignerUtilities.GetSigner("SHA256WITHRSAANDMGF1");
    signer.Init(true, new ParametersWithRandom(privateKey, new SecureRandom()));
    signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
    return Convert.ToBase64String(signer.GenerateSignature());
}

// 验证
public bool VerifyDataBouncyCastle(string rawData, string base64Signature, AsymmetricKeyParameter publicKey)
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(rawData);
    byte[] signatureBytes = Convert.FromBase64String(base64Signature);
    var signer = SignerUtilities.GetSigner("SHA256WITHRSAANDMGF1");
    signer.Init(false, publicKey);
    signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
    return signer.VerifySignature(signatureBytes);
}

额外检查项

  • 确保两边待签名的原始数据完全一致,没有多余的换行、空格、UTF-8 BOM头
  • 确保密钥读取正确,公钥/私钥没有混用,Pem文件的首尾标识没有被截断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 12:24:02