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

如何让RSACryptoServiceProvider使用公钥与签名完成消息验证

RSA SHA384 签名C#侧验证正确实现

核心踩坑点

  • 签名填充模式未对齐:Node.js crypto模块使用RSA-SHA384算法签名时,默认采用PKCS#1 v1.5填充,C#侧调用VerifyData时必须显式指定相同填充规则
  • Hex格式签名未正确转码:不能直接对hex字符串调用编码类转字节,需要先将hex字符串解析为原始二进制字节数组
  • 公钥导入方式错误:PKCS1格式的PEM公钥需要正确导入到RSA实例中,不要直接使用未导入公钥的RSACryptoServiceProvider实例

完整实现代码

.NET 5+ / .NET Core 5.0 及以上版本(支持直接导入PEM)

using System;
using System.Security.Cryptography;
using System.Text;

public static bool VerifyLicense(string jsonContent, string hexSignature, string pkcs1PublicKeyPem)
{
    // 1. 将hex格式签名转为二进制字节数组
    byte[] signatureBytes = ConvertHexStringToBytes(hexSignature);
    // 2. 待验证内容转字节,确认和JS端编码一致(默认UTF-8无BOM)
    byte[] contentBytes = Encoding.UTF8.GetBytes(jsonContent);
    
    // 3. 导入PKCS1格式的PEM公钥
    using RSA rsa = RSA.Create();
    rsa.ImportFromPem(pkcs1PublicKeyPem);
    
    // 4. 验证签名,显式指定哈希算法和填充模式,和JS端对齐
    return rsa.VerifyData(
        data: contentBytes,
        signature: signatureBytes,
        hashAlgorithm: HashAlgorithmName.SHA384,
        padding: RSASignaturePadding.Pkcs1
    );
}

// Hex字符串转字节数组工具方法
private static byte[] ConvertHexStringToBytes(string hex)
{
    if (hex.Length % 2 != 0)
        throw new ArgumentException("Hex字符串长度必须为偶数");
    
    byte[] bytes = new byte[hex.Length / 2];
    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }
    return bytes;
}

.NET Framework / .NET Core 3.1 及更低版本(不支持直接导入PEM)

需要先手动处理PEM公钥,提取base64内容后导入:

using System;
using System.Security.Cryptography;
using System.Text;
using System.Linq;

public static bool VerifyLicense(string jsonContent, string hexSignature, string pkcs1PublicKeyPem)
{
    byte[] signatureBytes = ConvertHexStringToBytes(hexSignature);
    byte[] contentBytes = Encoding.UTF8.GetBytes(jsonContent);
    
    // 手动解析PKCS1 PEM公钥
    string publicKeyBase64 = pkcs1PublicKeyPem
        .Replace("-----BEGIN RSA PUBLIC KEY-----", "")
        .Replace("-----END RSA PUBLIC KEY-----", "")
        .Replace("\r", "")
        .Replace("\n", "")
        .Trim();
    byte[] publicKeyBytes = Convert.FromBase64String(publicKeyBase64);
    
    using RSA rsa = RSA.Create();
    rsa.ImportRSAPublicKey(publicKeyBytes, out _);
    
    return rsa.VerifyData(
        contentBytes, 
        signatureBytes, 
        HashAlgorithmName.SHA384, 
        RSASignaturePadding.Pkcs1
    );
}

// Hex字符串转字节数组工具方法
private static byte[] ConvertHexStringToBytes(string hex)
{
    if (hex.Length % 2 != 0)
        throw new ArgumentException("Hex字符串长度必须为偶数");
    
    byte[] bytes = new byte[hex.Length / 2];
    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }
    return bytes;
}

校验点确认

  • 若Node.js端签名时显式指定了PSS填充,C#侧需要对应将填充参数改为RSASignaturePadding.Pss,默认情况下Node.js的crypto.sign('RSA-SHA384', content, privateKey)使用Pkcs1填充
  • 若JS端签名时用了utf16le等非UTF-8编码转换JSON字节,C#侧编码需要同步修改

内容的提问来源于stack exchange,提问作者Kim Sandberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:45:02