SQL 服务器 HASHBYTES 和扩展 Ascii

SQL Server HASHBYTES and Extended Ascii

我正在 Oracle 和 SQL 服务器之间进行 ETL 处理(无主键 -> 无事务复制),并使用 MD5 散列来检测源数据库和目标数据库之间的差异。

这适用于数据属于前 127 个 ASCII 字符的那些记录。但是当有任何 'extended ascii'* 字符时,例如 ½°© SQL 服务器的 HASHBYTES 函数将这些字符散列为非-标准方式(即不同于 Oracle 的 DBMS_CRYPTO.Hash、.Net 加密库等)。

所以当我在 Oracle 中 运行 这个时:

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

我得到:4723EB5AA8B0CD28C7E09433839B8FAE.

当我在 SQL 服务器中 运行 时:

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 存储过程并在那里散列数据?


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

截至目前,MS SQL Server 不支持 UTF-8。因此,您的哈希将始终不同,直到您将源字符串切换为最常见的分母,在本例中为 UTF-16(可能)。

我决定通过实施一个使用 .Net 加密库的 CLR 存储过程来围绕 SQL 服务器对扩展 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);
  }
}