| 1 | // 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. |
| 2 | |
| 3 | namespace WixToolset.Core.ExtensibilityServices |
| 4 | { |
| 5 | using System; |
| 6 | using System.Net; |
| 7 | using System.Security.Cryptography; |
| 8 | using System.Text; |
| 9 | |
| 10 | /// <summary> |
| 11 | /// Implementation of RFC 4122 - A Universally Unique Identifier (UUID) URN Namespace. |
| 12 | /// </summary> |
| 13 | internal static class Uuid |
| 14 | { |
| 15 | /// <summary> |
| 16 | /// Creates a version 3 name-based UUID. |
| 17 | /// </summary> |
| 18 | /// <param name="namespaceGuid">The namespace UUID.</param> |
| 19 | /// <param name="value">The value.</param> |
| 20 | /// <returns>The UUID for the given namespace and value.</returns> |
| 21 | public static Guid NewUuid(Guid namespaceGuid, string value) |
| 22 | { |
| 23 | byte[] namespaceBytes = namespaceGuid.ToByteArray(); |
| 24 | short uuidVersion = (short)0x5000; |
| 25 | |
| 26 | // get the fields of the guid which are in host byte ordering |
| 27 | int timeLow = BitConverter.ToInt32(namespaceBytes, 0); |
| 28 | short timeMid = BitConverter.ToInt16(namespaceBytes, 4); |
| 29 | short timeHiAndVersion = BitConverter.ToInt16(namespaceBytes, 6); |
| 30 | |
| 31 | // convert to network byte ordering |
| 32 | timeLow = IPAddress.HostToNetworkOrder(timeLow); |
| 33 | timeMid = IPAddress.HostToNetworkOrder(timeMid); |
| 34 | timeHiAndVersion = IPAddress.HostToNetworkOrder(timeHiAndVersion); |
| 35 | |
| 36 | // get the bytes from the value |
| 37 | byte[] valueBytes = Encoding.Unicode.GetBytes(value); |
| 38 | |
| 39 | // fill-in the hash input buffer |
| 40 | byte[] buffer = new byte[namespaceBytes.Length + valueBytes.Length]; |
| 41 | Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, buffer, 0, 4); |
| 42 | Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, buffer, 4, 2); |
| 43 | Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, buffer, 6, 2); |
| 44 | Buffer.BlockCopy(namespaceBytes, 8, buffer, 8, 8); |
| 45 | Buffer.BlockCopy(valueBytes, 0, buffer, 16, valueBytes.Length); |
| 46 | |
| 47 | // perform the appropriate hash of the namespace and value |
| 48 | byte[] hash; |
| 49 | using (SHA1 sha1 = SHA1.Create()) |
| 50 | { |
| 51 | hash = sha1.ComputeHash(buffer); |
| 52 | } |
| 53 | |
| 54 | // get the fields of the hash which are in network byte ordering |
| 55 | timeLow = BitConverter.ToInt32(hash, 0); |
| 56 | timeMid = BitConverter.ToInt16(hash, 4); |
| 57 | timeHiAndVersion = BitConverter.ToInt16(hash, 6); |
| 58 | |
| 59 | // convert to network byte ordering |
| 60 | timeLow = IPAddress.NetworkToHostOrder(timeLow); |
| 61 | timeMid = IPAddress.NetworkToHostOrder(timeMid); |
| 62 | timeHiAndVersion = IPAddress.NetworkToHostOrder(timeHiAndVersion); |
| 63 | |
| 64 | // set the version and variant bits |
| 65 | timeHiAndVersion &= 0x0FFF; |
| 66 | timeHiAndVersion += uuidVersion; |
| 67 | hash[8] &= 0x3F; |
| 68 | hash[8] |= 0x80; |
| 69 | |
| 70 | // put back the converted values into a 128-bit value |
| 71 | byte[] guidBits = new byte[16]; |
| 72 | Buffer.BlockCopy(hash, 0, guidBits, 0, 16); |
| 73 | |
| 74 | Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, guidBits, 0, 4); |
| 75 | Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, guidBits, 4, 2); |
| 76 | Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, guidBits, 6, 2); |
| 77 | |
| 78 | return new Guid(guidBits); |
| 79 | } |
| 80 | } |
| 81 | } |