2013-08-21 17 views
5

Mam ten kod, aby wygenerować hash SHA-1:Jak wygenerować Guid z tablicy bajtów SHA-1?

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

Czy istnieje sposób, aby włączyć hash do GUID (typu 5, jak sądzę, aby były zgodne z SHA-1)?

+0

To jest trochę mylące, ponieważ hash i guid to dwie różne rzeczy. Guid powinien dać ci unikalny/inny ciąg za każdym razem, gdy poprosisz o nowy Guid. Hashy dają spójne wyniki na podstawie tego samego wejścia. – Justin

+0

Będzie to deterministyczny i powtarzalny identyfikator GUID, oparty na haśle, który ma generować unikalne wartości w zależności od danych wejściowych. Więcej informacji: http://waterjuice.org/2013/06/type-3-and-5-guids/ –

+3

@Justin: Nie rozumiesz, o co chodzi w PO. Identyfikator GUID jest niczym więcej niż globalnie unikalnym identyfikatorem; to jest to, co oznacza GUID. Istnieje wiele sposobów generowania identyfikatora GUID. Można na przykład utworzyć identyfikator GUID na podstawie bieżącego czasu i pozycji; to jest globalnie wyjątkowe. (Głównie.) To jest typ GUID. Można utworzyć identyfikator GUID, który jest statystycznie unikalny w przypadku generatora liczb losowych; to jest identyfikator GUID typu 4. Mocny kryptograficznie hash ** unikatowego ciągu znaków ** jest również źródłem unikalności i można go wykorzystać do skonstruowania GUID. –

Odpowiedz

4

Można użyć tego C# code na podstawie rfc4122.

Aby zapobiec link rot niektóre kod tutaj:

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

Jak zauważył Justin, Guid powinien być niepowtarzalny za każdym razem, podczas gdy hash da spójny wynik za każdym razem dla tej samej wartości.

Teraz chciałbym dodać do tego i powiedzieć, że zarówno Guidy, jak i skróty (większość, jeśli nie wszystkie algorytmy) są podatne na kolizje, chociaż moim zdaniem jest to, że mieszanie podlega wyższemu poziomowi kolizji niż Guids ... chociaż może to być uzależnione od wielkości skrótu (np. 128 bitów, 256 bitów, 512 bitów itd.).

Innym problemem, jaki napotkasz, jest to, że byte[] z sumy SHA1 ma 20 bajtów długości, podczas gdy Guid ma 16 bajtów długości, dlatego tworzenie Guida ze skrótu SHA1 nie będzie dokładne.

Przykład:

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())); 

Powyższy przykład stworzy Guid z hash, choć używa LINQ, aby uzyskać 16 bajtów z tablicy mieszającej (stąd nieścisłości ... ostatnie 4 bajty są po prostu pominięty)

MD5 jest 16-bajtowym hash, więc wydaje się, że może być bardziej odpowiedni do konwersji na Guid niż SHA1.

Przykład:

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

To daje dokładny Guid z mieszania MD5, chociaż będę stwierdzić, to wszystko, to reprezentacja GUID hash MD5 ... nie powinno być rzeczywiste zmienić w danych byte[].

+0

Po pierwsze, nie rozumiesz, dlaczego rozsądnie jest użyć hasha krypto-siły ** unikalnego ciągu ** do wygenerowania identyfikatora GUID. Zobacz mój komentarz powyżej. Po drugie, ten kod jest błędny; nie ustawia numeru wersji GUID, co jest udokumentowanym wymogiem formatu GUID. –

+0

@EricLippert, Przepisuj tutaj: http://en.wikipedia.org/wiki/Universally_unique_identifier#Version_5_.28SHA-1_hash.29 - Biorąc pod uwagę, że GUIDv5 to SHA1, który został skrócony z 160bit do 128bit, I Zgaduję, że mój pierwszy przykład kodu jest bliższy wymaganiom OP niż mój drugi przykład? - Czy w celu ustawienia numeru wersji potrzebne jest tu trochę więcej przeróbek? – series0ne

+0

Zgadza się. –