【问题标题】:How do I calculate the equivalent to SQL Server (hashbytes('SHA1',[ColumnName])) in C#?如何在 C# 中计算与 SQL Server (hashbytes('SHA1',[ColumnName])) 等效的值?
【发布时间】:2012-12-18 06:30:51
【问题描述】:

在我的数据库中,我有一个计算列,其中包含一个名为 URLString 的列的 SHA1 哈希,该列包含 URL(例如“http://xxxx.com/index.html”)。

我经常需要查询表以根据 URLString 列找到特定的 URL。 该表包含 100K,这些查询需要几秒钟(使用 SQL Azure)。 由于 URL 可能很长,我无法在此列上创建索引(超过 450 个字节)。

为了加快速度,我想从 C# 计算 SQL Server hashbytes('SHA1',[URLString]) 的等效值,并根据该值进行查询。

我尝试了下面的代码,但我得到的值与数据库计算的值不同。

var urlString = Encoding.ASCII.GetBytes(url.URLString); //UTF8 also fails
var sha1 = new SHA1CryptoServiceProvider();
byte[] hash = sha1.ComputeHash(urlString);

我在这里错过了一些琐碎的事情吗?
我对可以解决相同问题的其他想法持开放态度(只要 SQL Azure 支持它们)。

示例:在数据库中自动计算出的 URLhttp://www.whatismyip.org/ 的 SHA1 值为 0xAE66CA69A157186A511ED462153D7CA65F0C1BF7。

【问题讨论】:

  • 你能发布计算哈希的插入吗?
  • 如果您的输出与服务器端计算不匹配,请尝试使用众多在线哈希计算器之一来验证哪个结果是正确的。如果一个不正确,可能是由于使用了盐
  • 这是一个自动计算的列,当我插入一个新的 URL 时,该值由数据库计算并插入。
  • 如果有盐值,所有 SQL Server 的值是否相同?它可以从某个地方获得吗?
  • 一定有一段 SQL 脚本在某处计算它。除非你发现无法猜测发生了什么

标签: c# sql-server tsql sha


【解决方案1】:

您可能会被字符编码差异所困扰:

http://weblogs.sqlteam.com/mladenp/archive/2009/04/28/Comparing-SQL-Server-HASHBYTES-function-and-.Net-hashing.aspx

您可以尝试通过Encoding.ASCII.GetBytes(url)Encoding.Unicode.GetBytes(url) 获取字节,然后查看您的数据库使用的是哪一个。

【讨论】:

  • 没问题 - 是的,散列算法对编码非常敏感。
  • 一般您可以使用Select TABLE_NAME, COLUMN_NAME, Columns.COLLATION_NAME From INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Yourtable' 来检查用于表/列的排序规则。从排序规则来看,如果是_CP1_(比如SQL_Latin1_General_Cp1_CS_AS)那么它是Windows-1252,如果是_CP###_那么###就是代码页号(比如SQL_Latin1_General_Cp437_CS_AS就是437),否则你必须搜索:-)
  • varchar = UTF8 /(额外的重音等)nvarchar = UNICODE
【解决方案2】:

以下是对字符串和字节进行散列的两种方法。 HashBytes 方法返回结果字节的 Base64,但如果您愿意,也可以只返回字节

public static string HashString(string cleartext)
{
    byte[] clearBytes = Encoding.UTF8.GetBytes(cleartext);
    return HashBytes(clearBytes);
}  

public static string HashBytes(byte[] clearBytes)
{
    SHA1 hasher = SHA1.Create();
    byte[] hashBytes =   hasher.ComputeHash(clearBytes);
    string hash = System.Convert.ToBase64String(hashBytes);
    hasher.Clear();
    return hash;
}

【讨论】:

  • 我会避免使用“cleartext”和“clearbytes”术语,因为这意味着涉及相反的内容(例如“加密字节”/“加密字符串”)。这里没有加密;只有普通的散列。我们都知道encryption != hashing
  • 这是从生产代码中提取的,“clearbytes”是有意义的。这也不矛盾,因为输出没有命名为“encryptedText”或“encryptedBytes”,输入是相同的“明文”并适当地描述了内容
  • 这与我发布的解决方案基本相同,除了使用 SHA1.Create() 而不是我的新 SHA1CryptoServiceProvider()。我试了一下,结果和以前一样(还是和数据库不一样)
【解决方案3】:

下面的代码等价于 SQL Server 的 hashbytes('sha1')

using (SHA1Managed sha1 = new SHA1Managed()) {
    var hash = sha1.ComputeHash(Encoding.Unicode.GetBytes(input));
    var sb = new StringBuilder(hash.Length * 2);

    foreach (byte b in hash) {
        // can be "x2" if you want lowercase
        sb.Append(b.ToString("X2"));
    }

    string output = sb.ToString();
}

【讨论】:

    【解决方案4】:

    Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (X64)

     DECLARE @inputString NVARCHAR(1000)
     set @inputString='Intel(R) Xeon(R) CPU           X5660  @ 2.80GHz  '
     DECLARE @outputHash VARBINARY(8000)
     SET @outputHash = HASHBYTES('SHA1', (@inputString))
     select  @outputhash
    

    退货 0xAE325D7C3D7720846B42CDD488EBEE5D711CB1AE

    C#

    public string SQLServerSha1(string input) {
        SHA1Managed sha1 = new SHA1Managed()
        var hash = sha1.ComputeHash(Encoding.Unicode.GetBytes(input));
        var sb = new StringBuilder(hash.Length * 2);
    
        foreach (byte b in hash) {
            // can be "x2" if you want lowercase
            sb.Append(b.ToString("X2"));
        }
    
        string output = sb.ToString();
        return output;
        }
    

    返回 AE325D7C3D7720846B42CDD488EBEE5D711CB1AE

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多