2010-12-02 81 views
2

我需要基於一個可變長度字符串生成一個哈希值,該字符串可以存儲在不超過16個字段(由於供應商要求)的字段中。是否有一個散列算法,在C#中產生64位散列大小?

我連接在一起正在通過C#腳本轉換傳遞的幾個字符串以計算哈希。我受到供應商的文件規範的約束,因爲散列的輸出不能超過16個。

有沒有人有任何建議?作爲例子,MD5算法的字符串轉換長度爲32.

+2

16什麼?它是二進制還是文本? – 2010-12-02 22:09:23

+0

理想情況下,它會是文本,因爲它會寫入平面文件。 – Matt 2010-12-02 22:16:28

+2

平面文件不一定是文本。 – 2010-12-02 22:19:04

回答

5

加密函數的設計使得可以將輸出截斷爲某種大小,並且截斷的散列函數仍然是安全的加密散列函數。例如,如果將SHA-512輸出的前128位(16字節)應用於某些輸入,則前128位是與其他128位加密散列一樣強的加密散列。

解決方案是選擇一些加密散列函數 - SHA-256,SHA-384和SHA-512是不錯的選擇,truncate the output到128位(16字節)。

- 編輯 -

基於註釋的散列值一定,當編碼爲ASCII,超過16個字符的ASCI配合,解決的辦法是

  • 首先,要選擇一些密碼散列函數(SHA-2系列包括SHA-256,SHA-384和SHA-512)
  • 然後,將所選散列函數的輸出截斷爲96位(12字節) - 也就是保留散列函數輸出的前12個字節並丟棄其餘字節
  • 然後,將截取的輸出基64編碼爲16位ASCII字符(128位)
  • 有效地生成96位強密碼散列。
0

如果您有16個字節存儲128位數字不是問題。將128位值存儲爲16字節值,而不是將16字節值存儲爲十六進制的32個字符的字符串。

作爲說明,我已經在數據庫中使用GUID/UUID字段來存儲MD5散列。雖然不再加密保護,128位的MD5哈希值是罰款校驗(和比64位更好。)

var result = MD5.Create().ComputeHash(new byte[] { 0 }); 

Console.WriteLine(result.Length); 
Console.WriteLine(Convert.ToBase64String(result)); 
Console.WriteLine(result.Aggregate(new StringBuilder(), 
            (sb, v) => sb.Append(v.ToString("x2")))); 

//16 
//k7iFrf4NoInN9jSQT9WfcQ== 
//93b885adfe0da089cdf634904fd59f71 

File.WriteAllBytes("tempfile.dat", result); 

var input = File.ReadAllBytes("tempfile.dat"); 

Console.WriteLine(input.Length); 
Console.WriteLine(Convert.ToBase64String(input)); 
Console.WriteLine(input.Aggregate(new StringBuilder(), 
            (sb, v) => sb.Append(v.ToString("x2")))); 

//16 
//k7iFrf4NoInN9jSQT9WfcQ== 
//93b885adfe0da089cdf634904fd59f71 

請注意,我不顯示文件內容,因爲有一個很好的機會,它將包含「不可打印」字符。

0

你可以很容易地使用MD5哈希值,但是你將不得不改變它的存儲方式。 MD5是128位,通常顯示爲32個4位(十六進制)值。標準字符是8位,但是,16個字符恰好足以存儲MD5散列值。

要轉換,請嘗試以下操作:這段代碼

String hash32 = "d41d8cd98f00b204e9800998ecf8427e" 
String hash16 = "" 

for(int i = 0; i < 32; i+=2) 
{ 
    uint high = Convert.ToUInt32(hash32[i], 16); 
    uint low = Convert.ToUInt32(hash32[i+1], 16); 
    char c = (char) ((high << 4) | low); 

    hash16 += c; 
} 
0

有何評論?似乎很好...

var p = new MD5CryptoServiceProvider(); 
var dic = new Dictionary<long, string>(); 

for (var i = 0; i < 10000000; i++) 
{ 
    if (i%25000 == 0) 
     Console.WriteLine("{0:n0}", i); 

    var h = p.ComputeHash(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())); 
    var b = BitConverter.ToInt64(h, 0); 

    // "b" is hashed Int64 

    if (!dic.ContainsKey(b)) 
     dic.Add(i, null); 
    else 
     throw new Exception("Oops!"); 
} 
0

我注意到這個問題比較老,但我確定有人會發現這個答案對它有價值。

我的建議是使用能夠使用8位到512位的Blake2b。如果沒有使用密鑰大小,則在這種情況下使用默認值「512」。 Blake2的默認值是256位。

 // BLAKE2b 
     // using System.Data.HashFunction; 
     // 
     // String message to use. 
     string str = "The quick brown fox jumps over the lazy dog"; 
     // Initialize 
     System.Data.HashFunction.Blake2B Blake2B = new System.Data.HashFunction.Blake2B(); 
     // Get string hash bytes; create 64 bit hash. 
     var HashBytes = Blake2B.ComputeHash(str, 64); 
     // Convert bytes to string and remove the dashes. 
     string hexString = BitConverter.ToString(HashBytes).Replace("-", string.Empty); 
     // Display results. 
     MessageBox.Show(hexString); 
     /* 
     * "The quick brown fox jumps over the lazy dog" produces a hash value of 
     * "A8ADD4BDDDFD93E4877D2746E62817B116364A1FA7BC148D95090BC7333B3673F82401CF7AA2E4CB1ECD90296E3F14CB5413F8ED77BE73045B13914CDCD6A918" 
     * and "2FD0F3FB3BD58455" hash for 64 bits. 
     */ 

希望這有助於!