2013-08-21 66 views
5

我有這樣的代碼來生成SHA-1散列:如何從SHA-1字節數組中生成Guid?

SHA1 sha1 = SHA1CryptoServiceProvider.Create(); 
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString); 
Byte[] hash = sha1.ComputeHash(myStringBytes); 

有沒有辦法把hash成一個GUID(5型,我猜,要符合SHA-1)?

+0

這是有點令人困惑的哈希和一個GUID是不同的東西。每次請求新的GUID時,GUID都會給你一個唯一/不同的字符串。哈希根據相同的輸入爲您提供一致的結果。 – Justin

+0

這將是一個基於散列的確定性和可重複的GUID,它打算根據輸入生成唯一值。更多信息:http://waterjuice.org/2013/06/type-3-and-5-guids/ –

+3

@Justin:你誤解了OP的要求。 GUID不過是一個全球唯一的標識符;這就是GUID的意思。有很多方法可以生成一個GUID。例如,您可以根據當前時間和位置創建一個GUID;這是全球獨一無二的。 (大部分)。這是一種類型的GUID。您可以使用隨機數生成器來統計唯一的GUID;這是一個四類GUID。一個唯一字符串**的加密強哈希**也是唯一性的來源,並且可以用來構造一個GUID。 –

回答

4

您可以根據rfc4122使用此C# code

爲了防止link rot,一些代碼在這裏:

public static Guid Create(Guid namespaceId, string name) 
{ 
    if (name == null) 
     throw new ArgumentNullException("name"); 

    // convert the name to a sequence of octets (as defined by the standard or conventions of its namespace) (step 3) 
    // ASSUME: UTF-8 encoding is always appropriate 
    byte[] nameBytes = Encoding.UTF8.GetBytes(name); 

    // convert the namespace UUID to network order (step 3) 
    byte[] namespaceBytes = namespaceId.ToByteArray(); 
    SwapByteOrder(namespaceBytes); 

    // comput the hash of the name space ID concatenated with the name (step 4) 
    byte[] hash; 
    using (HashAlgorithm algorithm = SHA1.Create()) 
    { 
     algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0); 
     algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length); 
     hash = algorithm.Hash; 
    } 

    // most bytes from the hash are copied straight to the bytes of the new GUID (steps 5-7, 9, 11-12) 
    byte[] newGuid = new byte[16]; 
    Array.Copy(hash, 0, newGuid, 0, 16); 

    // set the four most significant bits (bits 12 through 15) of the time_hi_and_version field to the appropriate 4-bit version number from Section 4.1.3 (step 8) 
    newGuid[6] = (byte)((newGuid[6] & 0x0F) | (5 << 4)); 

    // set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively (step 10) 
    newGuid[8] = (byte)((newGuid[8] & 0x3F) | 0x80); 

    // convert the resulting UUID to local byte order (step 13) 
    SwapByteOrder(newGuid); 
    return new Guid(newGuid); 
} 

/// <summary> 
/// The namespace for fully-qualified domain names (from RFC 4122, Appendix C). 
/// </summary> 
public static readonly Guid DnsNamespace = new Guid("6ba7b810-9dad-11d1-80b4-00c04fd430c8"); 

/// <summary> 
/// The namespace for URLs (from RFC 4122, Appendix C). 
/// </summary> 
public static readonly Guid UrlNamespace = new Guid("6ba7b811-9dad-11d1-80b4-00c04fd430c8"); 

/// <summary> 
/// The namespace for ISO OIDs (from RFC 4122, Appendix C). 
/// </summary> 
public static readonly Guid IsoOidNamespace = new Guid("6ba7b812-9dad-11d1-80b4-00c04fd430c8"); 

// Converts a GUID (expressed as a byte array) to/from network order (MSB-first). 
internal static void SwapByteOrder(byte[] guid) 
{ 
    SwapBytes(guid, 0, 3); 
    SwapBytes(guid, 1, 2); 
    SwapBytes(guid, 4, 5); 
    SwapBytes(guid, 6, 7); 
} 

private static void SwapBytes(byte[] guid, int left, int right) 
{ 
    byte temp = guid[left]; 
    guid[left] = guid[right]; 
    guid[right] = temp; 
} 
2

正如賈斯丁指出的那樣,Guid每次都應該是唯一的,而哈希每次都會給出一致的結果以獲得相同的值。

現在我想補充一點,並說,Guids和哈希(大多數,如果不是所有的算法)都會發生碰撞,儘管我的直覺是哈希碰撞比Guids ...雖然這可能受制於散列的大小(即128位,256位,512位等)。

您將遇到的另一個問題是,來自SHA1哈希的byte[]長度爲20個字節,而Guid長度爲16個字節,因此,從SHA1哈希創建Guid將不準確。

實施例:

string myString = "Hello World"; 
SHA1 sha1 = SHA1CryptoServiceProvider.Create(); 
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString); 
Byte[] hash = sha1.ComputeHash(myStringBytes); 
Console.WriteLine(new Guid(hash.Take(16).ToArray())); 

上面的例子將從你的散列創建一個GUID,儘管它使用LINQ獲得從散列陣列(因此不準確的16字節...的最後4個字節是簡單地省略)

MD5是一個16字節的散列,所以這看起來好像它可能更適合轉換爲Guid而不是SHA1。

例子:

string myString = "Hello World"; 
MD5 md5 = MD5.Create(); 
Byte[] myStringBytes = ASCIIEncoding.Default.GetBytes(myString); 
Byte[] hash = md5.ComputeHash(myStringBytes); 
Console.WriteLine(new Guid(hash)); 

這從MD5哈希生成準確的Guid,但我會說明,這一切,是MD5哈希一個GUID表示......應該是沒有實際更改byte[]數據。

+0

首先,您誤解了爲什麼使用唯一字符串**的加密強度散列**來生成GUID是明智的。看到我上面的評論。其次,這段代碼是錯誤的;它不會設置GUID的版本號,這是GUID格式的記錄要求。 –

+0

@EricLippert,Condider這裏的文本:http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_5_.28SHA-1_hash.29 - 鑑於這表明GUIDv5是從160bit截斷到128bit的SHA1,我猜測我的第一個代碼示例比第二個示例更接近OP的要求? - 大概需要更多的重新工作來設置版本號嗎? – series0ne

+0

這是正確的。 –