SQL Uniqueidentifier 和 hashbytes 与 c# 不匹配
Posted
技术标签:
【中文标题】SQL Uniqueidentifier 和 hashbytes 与 c# 不匹配【英文标题】:SQL Uniqueidentifier and hashbytes does not match with c# 【发布时间】:2021-12-09 01:34:20 【问题描述】:在 SQL Server 中使用 c# 创建哈希是不同的。为什么不一样?
using (SHA1Managed sha1 = new SHA1Managed())
Guid g = new Guid("81FE483B-39ED-4052-8FFC-55A710907D9B");
var appGateId = g.ToString();
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(appGateId));
var sb = new StringBuilder();
foreach (byte b in hash)
sb.Append(b.ToString("x2"));
Console.WriteLine(sb.ToString());
这里的结果是ebb52fefab48f428b6ee03174276c8ade0b4ef1a
。
使用 SQL Server 和此代码:
declare @a uniqueidentifier = '81FE483B-39ED-4052-8FFC-55A710907D9B', @b nvarchar(50)
select @b = CONVERT(nvarchar(50), @a)
select convert(varchar(50), hashbytes('SHA1', @b), 2)
结果是CC34B1E702F6E7FE0EE92ED4D5390BB4765B9A21
【问题讨论】:
我希望在 sql server 中创建的哈希应该和在 c# 中创建的一样 计算 guid 字符串的 UTF8 哈希与计算 guid 的哈希非常不同;一个 guid 是 16 个字节 - 你正在散列 36 个字节;然后需要考虑字节顺序; guid 的字节顺序是……复杂,不同的系统使用不同的规则;但是:如果您乐于在此处使用字符串:还需要区分大小写;您的 TSQL 版本以大写结尾,C# 版本以小写结尾 最后:为什么要在这里散列? guid 更短 【参考方案1】:@Marc Gravell 的评论解释了这里的问题。在 C# 中,您使用的是 UTF-8 字符串,但在 SQL Server 中,您使用的是 nvarchar
,它是 UTF-16;这些没有可比性。
但是,如果您实际使用 varchar
,并将字符更改为小写(因为在 T-SQL 中转换为基于字符串的数据类型时,uniqueidentifier
会更改为大写)您这样做 em> 得到相同的值。您也可以(如果您在 2019 年以上)将该值显式整理为 UTF-8 值,但考虑到 GUID 仅由十六进制字符 (0-9A-F) 组成,这似乎有点毫无意义:
DECLARE @a uniqueidentifier = '81FE483B-39ED-4052-8FFC-55A710907D9B', @b varchar(50);
SELECT @b = LOWER(CONVERT(varchar(50), @a));
SELECT @b, LOWER(CONVERT(varchar(50), HASHBYTES('SHA1', @b), 2));
【讨论】:
【参考方案2】:要使它们等效,您有两个问题:
如前所述,您请求的是 UTF-8,而 SQL Server 使用的是 UTF-16 C# 生成小写,SQL Server 生成大写您可以更改 C# 代码
using (SHA1Managed sha1 = new SHA1Managed())
Guid g = new Guid("81FE483B-39ED-4052-8FFC-55A710907D9B");
var appGateId = g.ToString().ToUpper().Dump();
var hash = sha1.ComputeHash(Encoding.Unicode.GetBytes(appGateId));
var sb = new StringBuilder();
foreach (byte b in hash)
sb.Append(b.ToString("x2"));
Console.WriteLine(sb.ToString());
dotnetfiddle
或者您可以更改 SQL Server 代码
declare @a uniqueidentifier = '81FE483B-39ED-4052-8FFC-55A710907D9B', @b varchar(50)
select @b = LOWER(CONVERT(varchar(50), @a))
select convert(varchar(50), hashbytes('SHA1', @b COLLATE Latin1_General_100_BIN2_UTF8 ), 2)
db<>fiddle
说实话,我不明白你为什么要散列 字符串表示。您可以轻松地散列实际的 Guid 字节。
【讨论】:
以上是关于SQL Uniqueidentifier 和 hashbytes 与 c# 不匹配的主要内容,如果未能解决你的问题,请参考以下文章
使用laravel从sql server生成UUID数据类型(uniqueidentifier)失败
SQL插入后,PHP返回ID [uniqueidentifier]