2014-02-25 66 views
1

在表我有一列URL這我使用保存的網址。我正在通過使用公式(CONVERT([varbinary](20),hashbytes('SHA1',[URL])))計算另一列中的散列。它工作正常。如何使用C#計算hashbyte SHA1?

現在我需要在C#中類似的函數來獲得哈希,這樣我可以比較和確認類似的排犯規存在之前,我插入新行。我嘗試了幾個鏈接,但沒有運氣。

這裏是鏈接:

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

How do I calculate the equivalent to SQL Server (hashbytes('SHA1',[ColumnName])) in C#?

** I found this link working. All I need to do is change formula in the db. but is it possible to make it in one line 
** 

http://forums.asp.net/t/1782626.aspx

DECLARE @HashThis nvarchar(4000); 
DECLARE @BinHash varbinary(4000); 
SELECT @HashThis = CONVERT(nvarchar(4000),'[email protected]'); 
SELECT @BinHash = HashBytes('SHA1', @HashThis); 

SELECT cast(N'' as xml).value('xs:base64Binary(xs:hexBinary(sql:variable("@BinHash")))', 'nvarchar(4000)'); 

在C#

string pwd = "[email protected]"; 
var sha1Provider = HashAlgorithm.Create("SHA1"); 
var binHash = sha1Provider.ComputeHash(Encoding.Unicode.GetBytes(pwd)); 
Console.WriteLine(Convert.ToBase64String(binHash)); 

我使用SQL Server 2012的排序規則的數據庫是SQL_Latin1_General_CP1_CI_AS

感謝

Paraminder

+0

如果您將使用C#顯示您正在嘗試的內容,這將有所幫助,因此我們可以檢查該代碼是否存在錯誤。 –

+0

這兩個鏈接都顯示如何在C#中創建一個哈希,所以你的問題是什麼? – slfan

+0

c#代碼不給我準確的哈希,我在數據庫中有什麼。 – Parminder

回答

4

這是一個編碼問題:

C#/網絡/ CLR字符串,在內部,UTF-16編碼字符串。這意味着每一個字符是至少兩個字節。

SQL服務器不同的是:

  • charvarchar使用的代碼頁綁定至由該列

  • ncharnvarchar表示每個字符所用的collation表示每個字符作爲一個單一的字節2個字節使用[老的和過時] UCS-2編碼的Unicode —東西將其在1996年棄用使用Unicode 2.0的釋放和UTF-16。

    UTF-16與UCS-2最大的區別在於UCS-2只能表示Unicode BMP(Basic Multilingual Plane)中的字符; UTF-16可以代表任何 Unicode字符。據我所知,在BMP中,UCS-2和UTF-16表示是相同的。

這意味着,以計算散列是相同的SQL Server計算一個,你將必須得到一個字節表示這是相同的SQL Server有一個。由於聽起來您正在使用charvarchar以及校對SQL_Latin1_General_CP1_CI_AS,per the documentationCP1部分表示代碼頁1252,其餘部分表示區分大小寫,區分重音。所以......

你可以通過代碼頁1252編碼:

Encoding enc = Encoding.GetEncoding(1252); 

使用該信息,並給予該表:

create table dbo.hash_test 
(
    id   int   not null identity(1,1) primary key clustered , 
    source_text varchar(2000) collate SQL_Latin1_General_CP1_CI_AS not null , 
    hash  as 
       (hashbytes('SHA1' , source_text)) , 
) 
go 
insert dbo.hash_test (source_text) values ('the quick brown fox jumped over the lazy dog.') 
insert dbo.hash_test (source_text) values ('She looked like something that might have occured to Ibsen in one of his less frivolous moments.') 
go 

你會得到這樣的輸出

1: the quick brown fox jumped over the lazy dog. 
    sql: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F 
    c#: 6039D100 3323D483 47DDFDB5 CE2842DF 758FAB5F 

2: She looked like something that might have occured to Ibsen in one of his less frivolous moments. 
    sql: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C 
    c#: D92501ED C462E331 B0E129BF 5B4A854E 8DBC490C 

from this program

class Program 
{ 

    static byte[] Sha1Hash(string s) 
    { 
    SHA1 sha1   = SHA1.Create() ; 
    Encoding windows1252 = Encoding.GetEncoding(1252) ; 
    byte[] octets  = windows1252.GetBytes(s) ; 
    byte[] hash  = sha1.ComputeHash(octets) ; 

    return hash ; 
    } 

    static string HashToString(byte[] bytes) 
    { 
    StringBuilder sb = new StringBuilder() ; 

    for (int i = 0 ; i < bytes.Length ; ++i) 
    { 
     byte b = bytes[i] ; 
     if (i > 0 && 0 == i % 4) sb.Append(' ') ; 
     sb.AppendFormat(b.ToString("X2")) ; 
    } 

    string s = sb.ToString() ; 
    return s ; 
    } 

    private static DataTable ReadDataFromSqlServer() 
    { 
    DataTable dt = new DataTable(); 

    using (SqlConnection conn = new SqlConnection("Server=localhost;Database=sandbox;Trusted_Connection=True;")) 
    using (SqlCommand cmd = conn.CreateCommand()) 
    using (SqlDataAdapter sda = new SqlDataAdapter(cmd)) 
    { 
     cmd.CommandText = "select * from dbo.hash_test" ; 
     cmd.CommandType = CommandType.Text; 
     conn.Open(); 
     sda.Fill(dt) ; 
     conn.Close() ; 
    } 

    return dt ; 
    } 

    static void Main() 
    { 
    DataTable dt = ReadDataFromSqlServer() ; 

    foreach (DataRow row in dt.Rows) 
    { 
     int id   = (int) row[ "id"   ] ; 
     string sourceText = (string) row[ "source_text" ] ; 
     byte[] sqlServerHash = (byte[]) row[ "hash"  ] ; 
     byte[] myHash  = Sha1Hash(sourceText) ; 

     Console.WriteLine(); 
     Console.WriteLine("{0:##0}: {1}" , id , sourceText) ; 
     Console.WriteLine(" sql: {0}" , HashToString(sqlServerHash)) ; 
     Console.WriteLine(" c#: {0}" , HashToString(myHash  )) ; 

     Debug.Assert(sqlServerHash.SequenceEqual(myHash)) ; 

    } 

    return ; 
    } 

} 

簡單!

+0

謝謝你。愛它。它工作得很好,但是如果source_text字段是nvarchar,它就會失敗。任何解決方案。 – Parminder

+0

只是改變這一行使它的工作。 UnicodeEncoding dstEncoding = new UnicodeEncoding(); byte [] octets = dstEncoding.GetBytes(s); – Parminder

+0

非常感謝這項艱苦的工作。我真的很感激。 – Parminder

0

我的建議是,任何時候創建一個哈希,它在一個地方完成。無論是在代碼還是在數據庫中。從長遠來看,它會讓你的生活更輕鬆。這意味着要麼改變你的C#代碼來在插入記錄之前創建哈希,要麼在存儲過程中進行重複檢查。

不管雖然,重複檢查和插入應該是同步的,使得沒有其它插入你能檢查任何重複和記錄時實際插入的時間之間發生。最簡單的方法是在同一個事務中執行它們。

如果你執意要走的邏輯,因爲它代表,那麼我會建議你在數據庫中創建的哈希值,而是通過一個存儲過程或用戶定義的函數,可以從C#代碼調用揭露它。