summaryrefslogtreecommitdiff
path: root/src/utilcode/guidfromname.cpp
blob: 3a6878305e458625e83d7c89d582633519f00f42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// GuidFromName

/**

Algorithm from Internet Draft document "UUIDs and GUIDs"
By Paul J. Leach and Rich Sals, February 4, 1998.

This function has been adapted from the routines in the document
 uuid_create_from_name and format_uuid_v3

Changes from documented routines:
1. Changed all instances of uuid_t to GUID.
     uuid_t field time_low is GUID field Data1.
     uuid_t field time_mid is GUID field Data2.
     uuid_t field time_hi_and_version is GUID field Data3.
     uuid_t field clock_seq_hi_and_reserved is GUID field Data4[0].
     uuid_t field clock_seq_low is GUID field Data4[1].
     uuid_t field node[6] is GUID field Data4[2] through Data4[8].

2. Use a c++ implementation of the md5 cryptographic hash function.

3. Implemented the htonl, htons, ntohl, ntohs socket routines as inlines.

4. Renamed variables and types to suit my biases.


Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
Digital Equipment Corporation, Maynard, Mass.
To anyone who acknowledges that this file is provided "AS IS"
without any express or implied warranty: permission to use, copy,
modify, and distribute this file for any purpose is hereby
granted without fee, provided that the above copyright notices and
this notice appears in all source code copies, and that none of
the names of Open Software Foundation, Inc., Hewlett-Packard
Company, or Digital Equipment Corporation be used in advertising
or publicity pertaining to distribution of the software without
specific, written prior permission.  Neither Open Software
Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
Corporation makes any representations about the suitability of
this software for any purpose.


Copyright(C) The Internet Society 1997. All Rights Reserved.

This document and translations of it may be copied and furnished to others,
and derivative works that comment on or otherwise explain it or assist in
its implementation may be prepared, copied, published and distributed, in
whole or in part, without restriction of any kind, provided that the above
copyright notice and this paragraph are included on all such copies and
derivative works.However, this document itself may not be modified in any
way, such as by removing the copyright notice or references to the Internet
Society or other Internet organizations, except as needed for the purpose of
developing Internet standards in which case the procedures for copyrights
defined in the Internet Standards process must be followed, or as required
to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked
by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS"
basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE
DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY
RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE.
 
*/

#include "stdafx.h"

#include "md5.h"                // cryptographic hash function
#include "guidfromname.h"       // verify our function signature
#include "contract.h"

#if BIGENDIAN
#define BigEndian() true
#else
#define BigEndian() false
#endif

//=============================================================================
// htons, htonl, ntohs, ntohl equivalents copied and adapted from socket library.
//=============================================================================

// HostToNetworkLong converts a 32-bit long to network byte order

inline ULONG HostToNetworkLong(ULONG hostlong)
{
    LIMITED_METHOD_CONTRACT;

    if (BigEndian())
        return hostlong;
    else
        return  ( (hostlong >> 24) & 0x000000FFL) |
                ( (hostlong >>  8) & 0x0000FF00L) |
                ( (hostlong <<  8) & 0x00FF0000L) |
                ( (hostlong << 24) & 0xFF000000L);
}

// HostToNetworkLong converts a 16-bit short to network byte order

inline USHORT HostToNetworkShort(USHORT hostshort)
{
    LIMITED_METHOD_CONTRACT;

    if (BigEndian())
        return hostshort;
    else
        return ((hostshort >> 8) & 0x00FF) | ((hostshort << 8) & 0xFF00);
}

// NetworkToHostLong converts a 32-bit long to local host byte order

inline ULONG NetworkToHostLong(ULONG netlong)
{
    LIMITED_METHOD_CONTRACT;
    
    if (BigEndian())
        return netlong;
    else
        return  ( (netlong >> 24) & 0x000000FFL) |
                ( (netlong >>  8) & 0x0000FF00L) |
                ( (netlong <<  8) & 0x00FF0000L) |
                ( (netlong << 24) & 0xFF000000L);
}

// NetworkToHostShort converts a 16-bit short to local host byte order

inline USHORT NetworkToHostShort(USHORT netshort)
{
    LIMITED_METHOD_CONTRACT;
    
    if (BigEndian())
        return netshort;
    else
        return ((netshort >> 8) & 0x00FF) | ((netshort << 8) & 0xFF00);
}

//=============================================================================
// GuidFromName(GUID * pGuidResult, REFGUID refGuidNsid, 
//              const void * pvName, DWORD dwcbName);
//=============================================================================

void GuidFromName
(
    GUID *  pGuidResult,        // resulting GUID
    REFGUID refGuidNsid,        // Name Space GUID, so identical names from
                                // different name spaces generate different GUIDs
    const void * pvName,        // the name from which to generate a GUID
    DWORD dwcbName              // name length in bytes
)
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    
    MD5         md5;            // Cryptographic hash class instance
    MD5HASHDATA md5HashData;    // 128-bit hash result
    GUID        guidNsid;       // context NameSpace GUID in network byte order

    GUID        guidTemp;
    
    // put name space ID in network byte order so it hashes the same
    // no matter what endian machine we're on
    guidNsid = refGuidNsid;

    // The sample code in the IETF draft document discards the result of
    // htonl and htons.  I've implemented what I think is meant and I've
    // sent a note to the author asking for confirmation that this is
    // his intent.
    if (!BigEndian())   // evaluated at compile time in retail builds
    {
        guidNsid.Data1 = HostToNetworkLong (guidNsid.Data1);
        guidNsid.Data2 = HostToNetworkShort(guidNsid.Data2);
        guidNsid.Data3 = HostToNetworkShort(guidNsid.Data3);
    }

    md5.Init();
    md5.HashMore(&guidNsid, sizeof(GUID));
    md5.HashMore(pvName, dwcbName);
    md5.GetHashValue(&md5HashData);

    // the hash is in network byte order at this point
    memcpy(&guidTemp, &md5HashData, sizeof(GUID));

    // Remainder adapted from function "format_uuid_v3" in IETF draft document
    // Construct a version 3 uuid with the pseudo-random number plus a few constants.
    // convert GUID from network order to local byte order
    if (!BigEndian())   // evaluated at compile time in retail builds
    {
        guidTemp.Data1 = NetworkToHostLong (guidTemp.Data1);
        guidTemp.Data2 = NetworkToHostShort(guidTemp.Data2);
        guidTemp.Data3 = NetworkToHostShort(guidTemp.Data3);
    }

    // set version number 
    guidTemp.Data3 &= 0x0FFF;   // clear version number nibble
    guidTemp.Data3 |= (3 << 12);// set version 3 = name-based

    // set variant field
    guidTemp.Data4[0] &= 0x3F;  // clear variant bits
    guidTemp.Data4[0] |= 0x80;  // set variant = 100b

    // If two GuidFromName calls were made from different threads with the same parameters, 
    // we may get incorrect result even though the expected result is the same, because 
    // GuidFromName is operating on the same pGuidResult buffer.
    // Fix this problem by using a temp GUID buffer and then copy to the pGuidResult buffer.
    memcpy(pGuidResult, &guidTemp, sizeof(GUID));
}


// This guid is used for calling GuidFromName function as COM+ runtime uniqualifier
//
// {69F9CBC9-DA05-11d1-9408-0000F8083460}
static const GUID COMPLUS_RUNTIME_GUID = {0x69f9cbc9, 0xda05, 0x11d1, 
        {0x94, 0x8, 0x0, 0x0, 0xf8, 0x8, 0x34, 0x60}};

void CorGuidFromNameW
(
    GUID *  pGuidResult,        // resulting GUID
    LPCWSTR wzName,             // the unicode name from which to generate a GUID
    SIZE_T  cchName             // name length in count of unicode character
)
{
    WRAPPER_NO_CONTRACT;

    GuidFromName(
        pGuidResult, 
        COMPLUS_RUNTIME_GUID, 
        wzName, 
        (DWORD)((cchName == (SIZE_T) -1 ? (lstrlenW(wzName)+1) : cchName) * sizeof(WCHAR)));
}