SQL Server HASHBYTES和扩展的Ascii

时间:2016-04-29 15:17:30

标签: c# sql-server hash ascii md5

我正在研究Oracle和SQL Server之间的ETL过程(没有主键 - >没有事务复制),并使用MD5哈希来检测源数据库和目标数据库之间的差异。

这适用于数据属于前127个ASCII字符的记录。但是当有任何'扩展的ascii'*字符,例如½°©时,SQL Server的HASHBYTES函数会以非标准方式散列这些字符(即与Oracle的DBMS_CRYPTO.Hash,.Net加密库等不同。

所以当我在Oracle中运行它时:

select rawtohex(
DBMS_CRYPTO.Hash (
    UTL_I18N.STRING_TO_RAW ('°', 'AL32UTF8'),
    2)
) from dual;

我得到:4723EB5AA8B0CD28C7E09433839B8FAE

当我在SQL Server中运行它时:

SELECT HASHBYTES('md5', '°');

我得到:EC655B6DA8B9264A7C7C5E1A70642FA7

当我运行这个C#代码时:

string password = "°";

// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);

// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm) CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);

// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
   // without dashes
   .Replace("-", string.Empty)
   // make lowercase
   .ToLower();

我得到4723EB5AA8B0CD28C7E09433839B8FAE,即与Oracle和我使用的每个在线工具相同。

是否有针对此问题的基于SQL的解决方案,还是需要创建CLR存储过程并在那里散列数据?

*我意识到这个词有点争议

2 个答案:

答案 0 :(得分:2)

截至目前,MS SQL Server中没有UTF-8支持。因此,在将源字符串切换到最常见的分母(在这种情况下为UTF-16(可能))之前,您的哈希值始终不同。

答案 1 :(得分:0)

我决定通过实现使用.Net加密库的CLR存储过程来解决SQL Server对扩展ASCII的处理问题:

using System;
using System.Security.Cryptography;
using System.Text;
using Microsoft.SqlServer.Server;

public class Functions
{
  [SqlFunction]
  public static string GetMD5Hash (string input)
  {
    var encodedPassword = new UTF8Encoding().GetBytes(input);

    var hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);

    return BitConverter.ToString(hash).Replace("-", string.Empty);
  }
}