aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Uuid.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Uuid.cs')
-rw-r--r--src/WixToolset.Core/Uuid.cs89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Uuid.cs b/src/WixToolset.Core/Uuid.cs
new file mode 100644
index 00000000..2e599793
--- /dev/null
+++ b/src/WixToolset.Core/Uuid.cs
@@ -0,0 +1,89 @@
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
3namespace WixToolset
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 sealed class Uuid
14 {
15 /// <summary>
16 /// Protect the constructor.
17 /// </summary>
18 private Uuid()
19 {
20 }
21
22 /// <summary>
23 /// Creates a version 3 name-based UUID.
24 /// </summary>
25 /// <param name="namespaceGuid">The namespace UUID.</param>
26 /// <param name="value">The value.</param>
27 /// <param name="backwardsCompatible">Flag to say to use MD5 instead of better SHA1.</param>
28 /// <returns>The UUID for the given namespace and value.</returns>
29 public static Guid NewUuid(Guid namespaceGuid, string value)
30 {
31 byte[] namespaceBytes = namespaceGuid.ToByteArray();
32 short uuidVersion = (short)0x5000;
33
34 // get the fields of the guid which are in host byte ordering
35 int timeLow = BitConverter.ToInt32(namespaceBytes, 0);
36 short timeMid = BitConverter.ToInt16(namespaceBytes, 4);
37 short timeHiAndVersion = BitConverter.ToInt16(namespaceBytes, 6);
38
39 // convert to network byte ordering
40 timeLow = IPAddress.HostToNetworkOrder(timeLow);
41 timeMid = IPAddress.HostToNetworkOrder(timeMid);
42 timeHiAndVersion = IPAddress.HostToNetworkOrder(timeHiAndVersion);
43
44 // get the bytes from the value
45 byte[] valueBytes = Encoding.Unicode.GetBytes(value);
46
47 // fill-in the hash input buffer
48 byte[] buffer = new byte[namespaceBytes.Length + valueBytes.Length];
49 Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, buffer, 0, 4);
50 Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, buffer, 4, 2);
51 Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, buffer, 6, 2);
52 Buffer.BlockCopy(namespaceBytes, 8, buffer, 8, 8);
53 Buffer.BlockCopy(valueBytes, 0, buffer, 16, valueBytes.Length);
54
55 // perform the appropriate hash of the namespace and value
56 byte[] hash;
57 using (SHA1 sha1 = SHA1.Create())
58 {
59 hash = sha1.ComputeHash(buffer);
60 }
61
62 // get the fields of the hash which are in network byte ordering
63 timeLow = BitConverter.ToInt32(hash, 0);
64 timeMid = BitConverter.ToInt16(hash, 4);
65 timeHiAndVersion = BitConverter.ToInt16(hash, 6);
66
67 // convert to network byte ordering
68 timeLow = IPAddress.NetworkToHostOrder(timeLow);
69 timeMid = IPAddress.NetworkToHostOrder(timeMid);
70 timeHiAndVersion = IPAddress.NetworkToHostOrder(timeHiAndVersion);
71
72 // set the version and variant bits
73 timeHiAndVersion &= 0x0FFF;
74 timeHiAndVersion += uuidVersion;
75 hash[8] &= 0x3F;
76 hash[8] |= 0x80;
77
78 // put back the converted values into a 128-bit value
79 byte[] guidBits = new byte[16];
80 Buffer.BlockCopy(hash, 0, guidBits, 0, 16);
81
82 Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, guidBits, 0, 4);
83 Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, guidBits, 4, 2);
84 Buffer.BlockCopy(BitConverter.GetBytes(timeHiAndVersion), 0, guidBits, 6, 2);
85
86 return new Guid(guidBits);
87 }
88 }
89}