// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset { using System; using System.Net; using System.Security.Cryptography; using System.Text; /// /// Implementation of RFC 4122 - A Universally Unique Identifier (UUID) URN Namespace. /// public static class Uuid { /// /// Creates a version 3 name-based UUID. /// /// The namespace UUID. /// The value. /// Flag to say to use MD5 instead of better SHA1. /// The UUID for the given namespace and value. public static Guid NewUuid(Guid namespaceGuid, string value) { byte[] namespaceBytes = namespaceGuid.ToByteArray(); short uuidVersion = (short)0x5000; // get the fields of the guid which are in host byte ordering int timeLow = BitConverter.ToInt32(namespaceBytes, 0); short timeMid = BitConverter.ToInt16(namespaceBytes, 4); short timeHiAndVersion = BitConverter.ToInt16(namespaceBytes, 6); // convert to network byte ordering timeLow = IPAddress.HostToNetworkOrder(timeLow); timeMid = IPAddress.HostToNetworkOrder(timeMid); timeHiAndVersion = IPAddress.HostToNetworkOrder(timeHiAndVersion); // get the bytes from the value byte[] valueBytes = Encoding.Unicode.GetBytes(value); // fill-in the hash input buffer byte[] buffer = new byte[namespaceBytes.Length + valueBytes.Length]; Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, buffer, 0, 4); Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, buffer, 4, 2); Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, buffer, 6, 2); Buffer.BlockCopy(namespaceBytes, 8, buffer, 8, 8); Buffer.BlockCopy(valueBytes, 0, buffer, 16, valueBytes.Length); // perform the appropriate hash of the namespace and value byte[] hash; using (SHA1 sha1 = SHA1.Create()) { hash = sha1.ComputeHash(buffer); } // get the fields of the hash which are in network byte ordering timeLow = BitConverter.ToInt32(hash, 0); timeMid = BitConverter.ToInt16(hash, 4); timeHiAndVersion = BitConverter.ToInt16(hash, 6); // convert to network byte ordering timeLow = IPAddress.NetworkToHostOrder(timeLow); timeMid = IPAddress.NetworkToHostOrder(timeMid); timeHiAndVersion = IPAddress.NetworkToHostOrder(timeHiAndVersion); // set the version and variant bits timeHiAndVersion &= 0x0FFF; timeHiAndVersion += uuidVersion; hash[8] &= 0x3F; hash[8] |= 0x80; // put back the converted values into a 128-bit value byte[] guidBits = new byte[16]; Buffer.BlockCopy(hash, 0, guidBits, 0, 16); Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, guidBits, 0, 4); Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, guidBits, 4, 2); Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, guidBits, 6, 2); return new Guid(guidBits); } } }