我编写了以下SQL CLR函数,以便散列大于8000字节的字符串值(T-SQL内置HASHBYTES函数的输入值的限制):
[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlBinary HashBytes(SqlString algorithm, SqlString value)
{
HashAlgorithm algorithmType = HashAlgorithm.Create(algorithm.Value);
if (algorithmType == null || value.IsNull)
{
return new SqlBinary();
}
else
{
byte[] bytes = Encoding.UTF8.GetBytes(value.Value);
return new SqlBinary(algorithmType.ComputeHash(bytes));
}
}
它适用于拉丁字符串.例如,以下哈希值是相同的:
SELECT dbo.fn_Utils_GetHashBytes ('MD5', 'test'); -- 0x098F6BCD4621D373CADE4E832627B4F6
SELECT HASHBYTES ('MD5', 'test'); -- 0x098F6BCD4621D373CADE4E832627B4F6
问题是它不适用于西里尔字符串.例如:
SELECT dbo.fn_Utils_GetHashBytes ('MD5 ', N'даровете на влъхвите') -- NULL
SELECT HashBytes ('MD5 ',N'даровете на влъхвите') -- 0x838B1B625A6074B2BE55CDB7FCEA2832
SELECT dbo.fn_Utils_GetHashBytes ('SHA256', N'даровете на влъхвите') -- 0xA1D65374A0B954F8291E00BC3DD9DF655D8A4A6BF127CFB15BBE794D2A098844
SELECT HashBytes ('SHA2_256',N'даровете на влъхвите') -- 0x375F6993E0ECE1864336E565C8E14848F2A4BAFCF60BC0C8F5636101DD15B25A
我为MD5获取NULL,但如果代码作为控制台应用程序执行,则代码返回值.谁能说出我做错了什么?
另外,我从here获得了功能,其中一条评论说:
Careful with CLR SP parameters being silently truncated to 8000 bytes
– I had to tag the parameter with [SqlFacet(MaxSize = -1)] otherwise bytes after the 8000th would simply be ignored!
但我测试了这个,它工作正常.例如,如果我生成一个8000字节字符串的散列和相同字符串的第二个散列加一个符号,我得到的散列是不同的.
DECLARE @A VARCHAR(MAX) = '8000 bytes string...'
DECLARE @B VARCHAR(MAX) = @A + '1'
SELECT LEN(@A), LEN(@B)
SELECT IIF(dbo.fn_Utils_GetHashBytes ('MD5', @A + '1') = dbo.fn_Utils_GetHashBytes ('MD5', @B), 1, 0) -- 0
我应该担心吗?
解决方法:
Encoding.UTF8.GetBytes(...)
SQL Server没有UTF-8的概念.使用UCS-2(UTF-16)或ASCII.使用的编码必须与您传递给HASHBYTES的编码相匹配.您可以很容易地看到HASHBYTES将以不同的方式散列VARCHAR与NVARCHAR:
select HASHBYTES('MD5', 'Foo') -- 0x1356C67D7AD1638D816BFB822DD2C25D
select HASHBYTES('MD5', N'Foo') -- 0xB25FF0AD90D09D395090E8A29FF4C63C
最好的方法是更改SQLCLR函数以接受字节,而不是字符串,并在调用者中处理转换为VARBINARY.
SELECT dbo.fn_Utils_GetHashBytes ('MD5', CAST(N'даровете на влъхвите' AS VARBINARY(MAX));
仅供参考,SQL Server 2016已经解除了对HASHBYTES
的8000字节限制:
For SQL Server 2014 and earlier, allowed input values are limited to 8000 bytes.
标签:c,net,tsql,hash,sqlclr 来源: https://codeday.me/bug/20190611/1220487.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。