How can I generate a Guid from a SHA-1 byte array?

匆匆过客 提交于 2019-12-22 05:33:25

问题


I have this code to generate a SHA-1 hash:

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

Is there a way to turn hash into a Guid (type 5, I guess, to be consistent with SHA-1)?


回答1:


You could use this C# code based on rfc4122.

To prevent link rot, some code here:

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:


As pointed out by Justin, a Guid should be unique every time, whereas a hash will give a consistent result every time for the same value.

Now I'd like to add to that and say that both Guids and hashes (most, if not all algorithms) are subject to collisions, although my gut feeling is that hashing is subject to a greater level of collisions than Guids...although this could be subject to the size of the hash (i.e. 128 bit, 256 bit, 512 bit etc).

Another problem you will encounter is that the byte[] from an SHA1 hash is 20 bytes long, whereas a Guid is 16 bytes long, therefore, creating a Guid from an SHA1 hash will not be accurate.

Example:

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

The example above will create a Guid from your hash, although it uses LINQ to get 16 bytes from the hash array (hence the inaccuracy...the last 4 bytes are simply omitted)

MD5 is a 16-byte hash, so this seems like it could be more suitable for conversion to Guid than SHA1.

Example:

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

This produces an accurate Guid from the MD5 hash, although I will state, all this is, is a Guid representation of the MD5 hash...there should be no actual change in the byte[] data.



来源:https://stackoverflow.com/questions/18362225/how-can-i-generate-a-guid-from-a-sha-1-byte-array

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!