Search code examples
c#guidsha1

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


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)?


Solution

  • 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;
    }