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

同一证书在C#与SQL Server中签名结果不一致的问题求助

问题:SQL Server与C#跨平台签名验证不匹配

操作步骤

  1. 证书创建与导入
    在IIS中创建自签名证书并导出为PFX格式,通过pvkconverter生成cer和pvk文件,再用以下SQL语句导入LocalDB:
CREATE CERTIFICATE test3   
FROM FILE = 'c:\sql\pvkder.cer'   
    WITH PRIVATE KEY (FILE = 'c:\sql\pvkder.pvk',   
    DECRYPTION BY PASSWORD = '********');  

导入操作成功完成。

  1. SQL Server签名
    使用SIGNBYCERT对字符串Philip签名:
select SIGNBYCERT(Cert_Id( 'test3' ),'Philip');

得到签名结果:

0x01000502040000006D545003C12AAB0C900B932698CCCD4F117DAE5621EA36CFC63ACF388E44FDEFCCE576286056BA0504DB5D96C1811E5769B21560D4E455F59D3FFBE7CDBD71AC4EE222FC5F6D8960C1EA7649BED4292EE8199C18B01EE5644B8D83FE81F8747FC760E0765BB1FC67933218E7D359F7226E6639B99E6728C507AF05BB68E147627328794A12FDBDCCD30118F4A60F516F9FD29CAF24F64EADAB568523364930A9FE81670D6EF75AD431AC28C169718C36F2F9377B1A0DAF5EA58493AC2CC0342E1C90A9E746C65E8D3535C4AB9D7C364F4FEC2DA3BC691636BA9846D7E6B310FDA665EF16C29A24DDCE6C141610D53B5FE924EE93C6713C875FEB780260EC1888
  1. C#签名代码
    使用同一份PFX证书在C#中签名:
string password = "*******";
X509Certificate2 certificate = new X509Certificate2("C:\\SQL\\ChipSoftCertificate.pfx", password);
    
RSA provider = certificate.GetRSAPrivateKey();
var data = Encoding.UTF8.GetBytes("Philip");
var signature = provider.SignData(data, HashAlgorithmName.MD5, RSASignaturePadding.Pkcs1);
var ssignature = Convert.ToHexString(signature);
signature = provider.SignData(data, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
ssignature = Convert.ToHexString(signature);
signature = provider.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
ssignature = Convert.ToHexString(signature);
signature = provider.SignData(data, HashAlgorithmName.SHA384, RSASignaturePadding.Pkcs1);
ssignature = Convert.ToHexString(signature);
signature = provider.SignData(data, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
ssignature = Convert.ToHexString(signature);

核心问题

C#生成的所有签名均与SQL Server生成的不一致,导致跨平台签名验证失败。目前SQL Server内部、C#内部的签名验证均正常,但跨平台组合无法生效。需要明确:

  • 操作中存在哪些错误?
  • SQL Server使用的哈希算法和填充方式是什么?

环境信息

SQL Server版本:

Microsoft SQL Server 2019 (RTM-CU12) (KB5004524) - 15.0.4153.1 (X64)   Jul 19 2021 15:37:34   Copyright (C) 2019 Microsoft Corporation  Express Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 19045: )

问题原因与解决方法

1. 核心差异点

  • 签名结构差异:SQL Server的SIGNBYCERT返回的签名包含自定义元数据前缀(如结果开头的0x0100050204000000),并非纯RSA签名值;而C#生成的是标准RSA签名字节,直接对比必然不一致。
  • 编码差异:SQL Server中SIGNBYCERT对字符串参数默认使用UTF-16LE(对应nvarchar编码),但你在C#中用了UTF8.GetBytes,这是导致签名不匹配的关键因素。
  • 默认哈希算法:SIGNBYCERT默认使用SHA-1哈希算法+PKCS#1 v1.5填充。

2. 修正后的C#代码

调整编码为UTF-16LE,并使用SHA-1哈希算法匹配SQL Server默认行为:

string password = "*******";
X509Certificate2 certificate = new X509Certificate2("C:\\SQL\\ChipSoftCertificate.pfx", password);
    
RSA provider = certificate.GetRSAPrivateKey();
// 使用UTF-16LE编码,对应SQL Server的默认字符串编码
var data = Encoding.Unicode.GetBytes("Philip");
// 使用SHA-1哈希算法,匹配SIGNBYCERT默认设置
var signature = provider.SignData(data, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
// 转换为带0x前缀的十六进制字符串,方便SQL语句使用
var sqlCompatibleSignature = "0x" + Convert.ToHexString(signature);

3. SQL Server验证语句

使用VERIFYSIGNEDBYCERT函数验证C#生成的签名,不要直接对比签名值:

-- 替换为C#生成的十六进制签名值
SELECT VERIFYSIGNEDBYCERT(Cert_Id('test3'), N'Philip', 0x你的C#签名十六进制值)

返回1表示验证成功,0表示失败。

4. 确认SQL Server的哈希算法

  • 可以通过SIGNBYCERT的第三个参数指定哈希算法,支持SHA1、SHA2_256、SHA2_384、SHA2_512,示例:
select SIGNBYCERT(Cert_Id('test3'), 'Philip', 'SHA2_256');
  • 如果需要使用非默认哈希算法,C#代码中也要对应使用相同的哈希算法,同时保持编码一致。

内容的提问来源于stack exchange,提问作者Philip Stuyck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 14:55:58