OpenDDS  Snapshot(2023/04/28-20:55)
Hash.cpp
Go to the documentation of this file.
1 /*
2  * Distributed under the OpenDDS License.
3  * See: http://www.opendds.org/license.html
4  */
5 
6 #include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/
7 
8 #include "Hash.h"
9 
10 #include <cstring>
11 
12 using std::memcpy;
13 using std::memset;
14 
16 
17 namespace {
18 /*
19  * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
20  * MD5 Message-Digest Algorithm (RFC 1321).
21  *
22  * Homepage:
23  * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
24  *
25  * Author:
26  * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
27  *
28  * This software was written by Alexander Peslyak in 2001. No copyright is
29  * claimed, and the software is hereby placed in the public domain.
30  * In case this attempt to disclaim copyright and place the software in the
31  * public domain is deemed null and void, then the software is
32  * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
33  * general public under the following terms:
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted.
37  *
38  * There's ABSOLUTELY NO WARRANTY, express or implied.
39  *
40  * (This is a heavily cut-down "BSD license".)
41  *
42  * This differs from Colin Plumb's older public domain implementation in that
43  * no exactly 32-bit integer data type is required (any 32-bit or wider
44  * unsigned integer data type will do), there's no compile-time endianness
45  * configuration, and the function prototypes match OpenSSL's. No code from
46  * Colin Plumb's implementation has been reused; this comment merely compares
47  * the properties of the two independent implementations.
48  *
49  * The primary goals of this implementation are portability and ease of use.
50  * It is meant to be fast, but not as fast as possible. Some known
51  * optimizations are not included to reduce source code size and avoid
52  * compile-time configuration.
53  */
54 
55 
56 /* Any 32-bit or wider unsigned integer data type will do */
57 typedef unsigned int MD5_u32plus;
58 
59 typedef struct {
60  MD5_u32plus lo, hi;
61  MD5_u32plus a, b, c, d;
62  unsigned char buffer[64];
63  MD5_u32plus block[16];
64 } MD5_CTX;
65 
66 
67 /*
68  * The basic MD5 functions.
69  *
70  * F and G are optimized compared to their RFC 1321 definitions for
71  * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
72  * implementation.
73  */
74 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
75 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
76 #define H(x, y, z) ((x) ^ (y) ^ (z))
77 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
78 
79 /*
80  * The MD5 transformation for all four rounds.
81  */
82 #define STEP(f, a, b, c, d, x, t, s) \
83  (a) += f((b), (c), (d)) + (x) + (t); \
84  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
85  (a) += (b);
86 
87 /*
88  * SET reads 4 input bytes in little-endian byte order and stores them
89  * in a properly aligned word in host byte order.
90  *
91  * The check for little-endian architectures that tolerate unaligned
92  * memory accesses is just an optimization. Nothing will break if it
93  * doesn't work.
94  */
95 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
96 #define SET(n) \
97  (*(MD5_u32plus *)&ptr[(n) * 4])
98 #define GET(n) \
99  SET(n)
100 #else
101 #define SET(n) \
102  (ctx->block[(n)] = \
103  (MD5_u32plus)ptr[(n) * 4] | \
104  ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
105  ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
106  ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
107 #define GET(n) \
108  (ctx->block[(n)])
109 #endif
110 
111 /*
112  * This processes one or more 64-byte data blocks, but does NOT update
113  * the bit counters. There are no alignment requirements.
114  */
115 static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
116 {
117  const unsigned char *ptr;
118  MD5_u32plus a, b, c, d;
119  MD5_u32plus saved_a, saved_b, saved_c, saved_d;
120 
121  ptr = (const unsigned char *) data;
122 
123  a = ctx->a;
124  b = ctx->b;
125  c = ctx->c;
126  d = ctx->d;
127 
128  do {
129  saved_a = a;
130  saved_b = b;
131  saved_c = c;
132  saved_d = d;
133 
134 /* Round 1 */
135  STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
136  STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
137  STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
138  STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
139  STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
140  STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
141  STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
142  STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
143  STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
144  STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
145  STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
146  STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
147  STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
148  STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
149  STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
150  STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
151 
152 /* Round 2 */
153  STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
154  STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
155  STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
156  STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
157  STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
158  STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
159  STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
160  STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
161  STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
162  STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
163  STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
164  STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
165  STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
166  STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
167  STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
168  STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
169 
170 /* Round 3 */
171  STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
172  STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
173  STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
174  STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
175  STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
176  STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
177  STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
178  STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
179  STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
180  STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
181  STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
182  STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
183  STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
184  STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
185  STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
186  STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
187 
188 /* Round 4 */
189  STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
190  STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
191  STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
192  STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
193  STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
194  STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
195  STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
196  STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
197  STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
198  STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
199  STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
200  STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
201  STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
202  STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
203  STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
204  STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
205 
206  a += saved_a;
207  b += saved_b;
208  c += saved_c;
209  d += saved_d;
210 
211  ptr += 64;
212  } while (size -= 64);
213 
214  ctx->a = a;
215  ctx->b = b;
216  ctx->c = c;
217  ctx->d = d;
218 
219  return ptr;
220 }
221 
222 void MD5_Init(MD5_CTX *ctx)
223 {
224  ctx->a = 0x67452301;
225  ctx->b = 0xefcdab89;
226  ctx->c = 0x98badcfe;
227  ctx->d = 0x10325476;
228 
229  ctx->lo = 0;
230  ctx->hi = 0;
231 }
232 
233 void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
234 {
235  MD5_u32plus saved_lo;
236  unsigned long used;
237 
238  saved_lo = ctx->lo;
239  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
240  ctx->hi++;
241  ctx->hi += size >> 29;
242 
243  used = saved_lo & 0x3f;
244 
245  if (used) {
246  unsigned long free = 64 - used;
247 
248  if (size < free) {
249  memcpy(&ctx->buffer[used], data, size);
250  return;
251  }
252 
253  memcpy(&ctx->buffer[used], data, free);
254  data = (unsigned char *)data + free;
255  size -= free;
256  body(ctx, ctx->buffer, 64);
257  }
258 
259  if (size >= 64) {
260  data = body(ctx, data, size & ~(unsigned long)0x3f);
261  size &= 0x3f;
262  }
263 
264  memcpy(ctx->buffer, data, size);
265 }
266 
267 void MD5_Final(unsigned char *result, MD5_CTX *ctx)
268 {
269  unsigned long used, free;
270 
271  used = ctx->lo & 0x3f;
272 
273  ctx->buffer[used++] = 0x80;
274 
275  free = 64 - used;
276 
277  if (free < 8) {
278  memset(&ctx->buffer[used], 0, free);
279  body(ctx, ctx->buffer, 64);
280  used = 0;
281  free = 64;
282  }
283 
284  memset(&ctx->buffer[used], 0, free - 8);
285 
286  ctx->lo <<= 3;
287  ctx->buffer[56] = ctx->lo;
288  ctx->buffer[57] = ctx->lo >> 8;
289  ctx->buffer[58] = ctx->lo >> 16;
290  ctx->buffer[59] = ctx->lo >> 24;
291  ctx->buffer[60] = ctx->hi;
292  ctx->buffer[61] = ctx->hi >> 8;
293  ctx->buffer[62] = ctx->hi >> 16;
294  ctx->buffer[63] = ctx->hi >> 24;
295 
296  body(ctx, ctx->buffer, 64);
297 
298  result[0] = ctx->a;
299  result[1] = ctx->a >> 8;
300  result[2] = ctx->a >> 16;
301  result[3] = ctx->a >> 24;
302  result[4] = ctx->b;
303  result[5] = ctx->b >> 8;
304  result[6] = ctx->b >> 16;
305  result[7] = ctx->b >> 24;
306  result[8] = ctx->c;
307  result[9] = ctx->c >> 8;
308  result[10] = ctx->c >> 16;
309  result[11] = ctx->c >> 24;
310  result[12] = ctx->d;
311  result[13] = ctx->d >> 8;
312  result[14] = ctx->d >> 16;
313  result[15] = ctx->d >> 24;
314 
315  memset(ctx, 0, sizeof(*ctx));
316 }
317 
318 } // anonymous namespace
319 
320 namespace OpenDDS {
321 namespace DCPS {
322 
323 void MD5Hash(MD5Result& result, const void* input, size_t size)
324 {
325  MD5_CTX ctx;
326  MD5_Init(&ctx);
327  MD5_Update(&ctx, input, static_cast<unsigned long>(size));
328  MD5_Final(result, &ctx);
329 }
330 
331 }
332 }
333 
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
Definition: Hash.cpp:267
void free(void *)
void MD5Hash(MD5Result &result, const void *input, size_t size)
Definition: Hash.cpp:323
#define I(x, y, z)
Definition: Hash.cpp:77
void * memcpy(void *t, const void *s, size_t len)
#define GET(n)
Definition: Hash.cpp:107
static const void * body(MD5_CTX *ctx, const void *data, unsigned long size)
Definition: Hash.cpp:115
unsigned char MD5Result[16]
Definition: Hash.h:21
#define STEP(f, a, b, c, d, x, t, s)
Definition: Hash.cpp:82
#define SET(n)
Definition: Hash.cpp:101
void * memset(void *s, int c, size_t len)
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
#define F(x, y, z)
Definition: Hash.cpp:74
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
Definition: Hash.cpp:233
#define H(x, y, z)
Definition: Hash.cpp:76
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
#define G(x, y, z)
Definition: Hash.cpp:75