1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | // GuidFromName |
6 | |
7 | /** |
8 | |
9 | Algorithm from Internet Draft document "UUIDs and GUIDs" |
10 | By Paul J. Leach and Rich Sals, February 4, 1998. |
11 | |
12 | This function has been adapted from the routines in the document |
13 | uuid_create_from_name and format_uuid_v3 |
14 | |
15 | Changes from documented routines: |
16 | 1. Changed all instances of uuid_t to GUID. |
17 | uuid_t field time_low is GUID field Data1. |
18 | uuid_t field time_mid is GUID field Data2. |
19 | uuid_t field time_hi_and_version is GUID field Data3. |
20 | uuid_t field clock_seq_hi_and_reserved is GUID field Data4[0]. |
21 | uuid_t field clock_seq_low is GUID field Data4[1]. |
22 | uuid_t field node[6] is GUID field Data4[2] through Data4[8]. |
23 | |
24 | 2. Use a c++ implementation of the md5 cryptographic hash function. |
25 | |
26 | 3. Implemented the htonl, htons, ntohl, ntohs socket routines as inlines. |
27 | |
28 | 4. Renamed variables and types to suit my biases. |
29 | |
30 | |
31 | Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. |
32 | Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & |
33 | Digital Equipment Corporation, Maynard, Mass. |
34 | To anyone who acknowledges that this file is provided "AS IS" |
35 | without any express or implied warranty: permission to use, copy, |
36 | modify, and distribute this file for any purpose is hereby |
37 | granted without fee, provided that the above copyright notices and |
38 | this notice appears in all source code copies, and that none of |
39 | the names of Open Software Foundation, Inc., Hewlett-Packard |
40 | Company, or Digital Equipment Corporation be used in advertising |
41 | or publicity pertaining to distribution of the software without |
42 | specific, written prior permission. Neither Open Software |
43 | Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment |
44 | Corporation makes any representations about the suitability of |
45 | this software for any purpose. |
46 | |
47 | |
48 | Copyright(C) The Internet Society 1997. All Rights Reserved. |
49 | |
50 | This document and translations of it may be copied and furnished to others, |
51 | and derivative works that comment on or otherwise explain it or assist in |
52 | its implementation may be prepared, copied, published and distributed, in |
53 | whole or in part, without restriction of any kind, provided that the above |
54 | copyright notice and this paragraph are included on all such copies and |
55 | derivative works.However, this document itself may not be modified in any |
56 | way, such as by removing the copyright notice or references to the Internet |
57 | Society or other Internet organizations, except as needed for the purpose of |
58 | developing Internet standards in which case the procedures for copyrights |
59 | defined in the Internet Standards process must be followed, or as required |
60 | to translate it into languages other than English. |
61 | |
62 | The limited permissions granted above are perpetual and will not be revoked |
63 | by the Internet Society or its successors or assigns. |
64 | |
65 | This document and the information contained herein is provided on an "AS IS" |
66 | basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE |
67 | DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
68 | ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY |
69 | RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A |
70 | PARTICULAR PURPOSE. |
71 | |
72 | */ |
73 | |
74 | #include "stdafx.h" |
75 | |
76 | #include "md5.h" // cryptographic hash function |
77 | #include "guidfromname.h" // verify our function signature |
78 | #include "contract.h" |
79 | |
80 | #if BIGENDIAN |
81 | #define BigEndian() true |
82 | #else |
83 | #define BigEndian() false |
84 | #endif |
85 | |
86 | //============================================================================= |
87 | // htons, htonl, ntohs, ntohl equivalents copied and adapted from socket library. |
88 | //============================================================================= |
89 | |
90 | // HostToNetworkLong converts a 32-bit long to network byte order |
91 | |
92 | inline ULONG HostToNetworkLong(ULONG hostlong) |
93 | { |
94 | LIMITED_METHOD_CONTRACT; |
95 | |
96 | if (BigEndian()) |
97 | return hostlong; |
98 | else |
99 | return ( (hostlong >> 24) & 0x000000FFL) | |
100 | ( (hostlong >> 8) & 0x0000FF00L) | |
101 | ( (hostlong << 8) & 0x00FF0000L) | |
102 | ( (hostlong << 24) & 0xFF000000L); |
103 | } |
104 | |
105 | // HostToNetworkLong converts a 16-bit short to network byte order |
106 | |
107 | inline USHORT HostToNetworkShort(USHORT hostshort) |
108 | { |
109 | LIMITED_METHOD_CONTRACT; |
110 | |
111 | if (BigEndian()) |
112 | return hostshort; |
113 | else |
114 | return ((hostshort >> 8) & 0x00FF) | ((hostshort << 8) & 0xFF00); |
115 | } |
116 | |
117 | // NetworkToHostLong converts a 32-bit long to local host byte order |
118 | |
119 | inline ULONG NetworkToHostLong(ULONG netlong) |
120 | { |
121 | LIMITED_METHOD_CONTRACT; |
122 | |
123 | if (BigEndian()) |
124 | return netlong; |
125 | else |
126 | return ( (netlong >> 24) & 0x000000FFL) | |
127 | ( (netlong >> 8) & 0x0000FF00L) | |
128 | ( (netlong << 8) & 0x00FF0000L) | |
129 | ( (netlong << 24) & 0xFF000000L); |
130 | } |
131 | |
132 | // NetworkToHostShort converts a 16-bit short to local host byte order |
133 | |
134 | inline USHORT NetworkToHostShort(USHORT netshort) |
135 | { |
136 | LIMITED_METHOD_CONTRACT; |
137 | |
138 | if (BigEndian()) |
139 | return netshort; |
140 | else |
141 | return ((netshort >> 8) & 0x00FF) | ((netshort << 8) & 0xFF00); |
142 | } |
143 | |
144 | //============================================================================= |
145 | // GuidFromName(GUID * pGuidResult, REFGUID refGuidNsid, |
146 | // const void * pvName, DWORD dwcbName); |
147 | //============================================================================= |
148 | |
149 | void GuidFromName |
150 | ( |
151 | GUID * pGuidResult, // resulting GUID |
152 | REFGUID refGuidNsid, // Name Space GUID, so identical names from |
153 | // different name spaces generate different GUIDs |
154 | const void * pvName, // the name from which to generate a GUID |
155 | DWORD dwcbName // name length in bytes |
156 | ) |
157 | { |
158 | STATIC_CONTRACT_NOTHROW; |
159 | STATIC_CONTRACT_GC_NOTRIGGER; |
160 | |
161 | MD5 md5; // Cryptographic hash class instance |
162 | MD5HASHDATA md5HashData; // 128-bit hash result |
163 | GUID guidNsid; // context NameSpace GUID in network byte order |
164 | |
165 | GUID guidTemp; |
166 | |
167 | // put name space ID in network byte order so it hashes the same |
168 | // no matter what endian machine we're on |
169 | guidNsid = refGuidNsid; |
170 | |
171 | // The sample code in the IETF draft document discards the result of |
172 | // htonl and htons. I've implemented what I think is meant and I've |
173 | // sent a note to the author asking for confirmation that this is |
174 | // his intent. |
175 | if (!BigEndian()) // evaluated at compile time in retail builds |
176 | { |
177 | guidNsid.Data1 = HostToNetworkLong (guidNsid.Data1); |
178 | guidNsid.Data2 = HostToNetworkShort(guidNsid.Data2); |
179 | guidNsid.Data3 = HostToNetworkShort(guidNsid.Data3); |
180 | } |
181 | |
182 | md5.Init(); |
183 | md5.HashMore(&guidNsid, sizeof(GUID)); |
184 | md5.HashMore(pvName, dwcbName); |
185 | md5.GetHashValue(&md5HashData); |
186 | |
187 | // the hash is in network byte order at this point |
188 | memcpy(&guidTemp, &md5HashData, sizeof(GUID)); |
189 | |
190 | // Remainder adapted from function "format_uuid_v3" in IETF draft document |
191 | // Construct a version 3 uuid with the pseudo-random number plus a few constants. |
192 | // convert GUID from network order to local byte order |
193 | if (!BigEndian()) // evaluated at compile time in retail builds |
194 | { |
195 | guidTemp.Data1 = NetworkToHostLong (guidTemp.Data1); |
196 | guidTemp.Data2 = NetworkToHostShort(guidTemp.Data2); |
197 | guidTemp.Data3 = NetworkToHostShort(guidTemp.Data3); |
198 | } |
199 | |
200 | // set version number |
201 | guidTemp.Data3 &= 0x0FFF; // clear version number nibble |
202 | guidTemp.Data3 |= (3 << 12);// set version 3 = name-based |
203 | |
204 | // set variant field |
205 | guidTemp.Data4[0] &= 0x3F; // clear variant bits |
206 | guidTemp.Data4[0] |= 0x80; // set variant = 100b |
207 | |
208 | // If two GuidFromName calls were made from different threads with the same parameters, |
209 | // we may get incorrect result even though the expected result is the same, because |
210 | // GuidFromName is operating on the same pGuidResult buffer. |
211 | // Fix this problem by using a temp GUID buffer and then copy to the pGuidResult buffer. |
212 | memcpy(pGuidResult, &guidTemp, sizeof(GUID)); |
213 | } |
214 | |
215 | |
216 | // This guid is used for calling GuidFromName function as COM+ runtime uniqualifier |
217 | // |
218 | // {69F9CBC9-DA05-11d1-9408-0000F8083460} |
219 | static const GUID COMPLUS_RUNTIME_GUID = {0x69f9cbc9, 0xda05, 0x11d1, |
220 | {0x94, 0x8, 0x0, 0x0, 0xf8, 0x8, 0x34, 0x60}}; |
221 | |
222 | void CorGuidFromNameW |
223 | ( |
224 | GUID * pGuidResult, // resulting GUID |
225 | LPCWSTR wzName, // the unicode name from which to generate a GUID |
226 | SIZE_T cchName // name length in count of unicode character |
227 | ) |
228 | { |
229 | WRAPPER_NO_CONTRACT; |
230 | |
231 | GuidFromName( |
232 | pGuidResult, |
233 | COMPLUS_RUNTIME_GUID, |
234 | wzName, |
235 | (DWORD)((cchName == (SIZE_T) -1 ? (wcslen(wzName)+1) : cchName) * sizeof(WCHAR))); |
236 | } |
237 | |