1//===-- tsan_md5.cc -------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13#include "tsan_defs.h"
14
15namespace __tsan {
16
17#define F(x, y, z)      ((z) ^ ((x) & ((y) ^ (z))))
18#define G(x, y, z)      ((y) ^ ((z) & ((x) ^ (y))))
19#define H(x, y, z)      ((x) ^ (y) ^ (z))
20#define I(x, y, z)      ((y) ^ ((x) | ~(z)))
21
22#define STEP(f, a, b, c, d, x, t, s) \
23  (a) += f((b), (c), (d)) + (x) + (t); \
24  (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
25  (a) += (b);
26
27#define SET(n) \
28  (*(MD5_u32plus *)&ptr[(n) * 4])
29#define GET(n) \
30  SET(n)
31
32typedef unsigned int MD5_u32plus;
33typedef unsigned long ulong_t;  // NOLINT
34
35typedef struct {
36  MD5_u32plus lo, hi;
37  MD5_u32plus a, b, c, d;
38  unsigned char buffer[64];
39  MD5_u32plus block[16];
40} MD5_CTX;
41
42static void *body(MD5_CTX *ctx, void *data, ulong_t size) {
43  unsigned char *ptr;
44  MD5_u32plus a, b, c, d;
45  MD5_u32plus saved_a, saved_b, saved_c, saved_d;
46
47  ptr = (unsigned char*)data;
48
49  a = ctx->a;
50  b = ctx->b;
51  c = ctx->c;
52  d = ctx->d;
53
54  do {
55    saved_a = a;
56    saved_b = b;
57    saved_c = c;
58    saved_d = d;
59
60    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
61    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
62    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
63    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
64    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
65    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
66    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
67    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
68    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
69    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
70    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
71    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
72    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
73    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
74    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
75    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
76
77    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
78    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
79    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
80    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
81    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
82    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
83    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
84    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
85    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
86    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
87    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
88    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
89    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
90    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
91    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
92    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
93
94    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
95    STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
96    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
97    STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
98    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
99    STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
100    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
101    STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
102    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
103    STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
104    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
105    STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
106    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
107    STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
108    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
109    STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
110
111    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
112    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
113    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
114    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
115    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
116    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
117    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
118    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
119    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
120    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
121    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
122    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
123    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
124    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
125    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
126    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
127
128    a += saved_a;
129    b += saved_b;
130    c += saved_c;
131    d += saved_d;
132
133    ptr += 64;
134  } while (size -= 64);
135
136  ctx->a = a;
137  ctx->b = b;
138  ctx->c = c;
139  ctx->d = d;
140
141  return ptr;
142}
143
144void MD5_Init(MD5_CTX *ctx) {
145  ctx->a = 0x67452301;
146  ctx->b = 0xefcdab89;
147  ctx->c = 0x98badcfe;
148  ctx->d = 0x10325476;
149
150  ctx->lo = 0;
151  ctx->hi = 0;
152}
153
154void MD5_Update(MD5_CTX *ctx, void *data, ulong_t size) {
155  MD5_u32plus saved_lo;
156  ulong_t used, free;
157
158  saved_lo = ctx->lo;
159  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
160    ctx->hi++;
161  ctx->hi += size >> 29;
162
163  used = saved_lo & 0x3f;
164
165  if (used) {
166    free = 64 - used;
167
168    if (size < free) {
169      internal_memcpy(&ctx->buffer[used], data, size);
170      return;
171    }
172
173    internal_memcpy(&ctx->buffer[used], data, free);
174    data = (unsigned char *)data + free;
175    size -= free;
176    body(ctx, ctx->buffer, 64);
177  }
178
179  if (size >= 64) {
180    data = body(ctx, data, size & ~(ulong_t)0x3f);
181    size &= 0x3f;
182  }
183
184  internal_memcpy(ctx->buffer, data, size);
185}
186
187void MD5_Final(unsigned char *result, MD5_CTX *ctx) {
188  ulong_t used, free;
189
190  used = ctx->lo & 0x3f;
191
192  ctx->buffer[used++] = 0x80;
193
194  free = 64 - used;
195
196  if (free < 8) {
197    internal_memset(&ctx->buffer[used], 0, free);
198    body(ctx, ctx->buffer, 64);
199    used = 0;
200    free = 64;
201  }
202
203  internal_memset(&ctx->buffer[used], 0, free - 8);
204
205  ctx->lo <<= 3;
206  ctx->buffer[56] = ctx->lo;
207  ctx->buffer[57] = ctx->lo >> 8;
208  ctx->buffer[58] = ctx->lo >> 16;
209  ctx->buffer[59] = ctx->lo >> 24;
210  ctx->buffer[60] = ctx->hi;
211  ctx->buffer[61] = ctx->hi >> 8;
212  ctx->buffer[62] = ctx->hi >> 16;
213  ctx->buffer[63] = ctx->hi >> 24;
214
215  body(ctx, ctx->buffer, 64);
216
217  result[0] = ctx->a;
218  result[1] = ctx->a >> 8;
219  result[2] = ctx->a >> 16;
220  result[3] = ctx->a >> 24;
221  result[4] = ctx->b;
222  result[5] = ctx->b >> 8;
223  result[6] = ctx->b >> 16;
224  result[7] = ctx->b >> 24;
225  result[8] = ctx->c;
226  result[9] = ctx->c >> 8;
227  result[10] = ctx->c >> 16;
228  result[11] = ctx->c >> 24;
229  result[12] = ctx->d;
230  result[13] = ctx->d >> 8;
231  result[14] = ctx->d >> 16;
232  result[15] = ctx->d >> 24;
233
234  internal_memset(ctx, 0, sizeof(*ctx));
235}
236
237MD5Hash md5_hash(const void *data, uptr size) {
238  MD5Hash res;
239  MD5_CTX ctx;
240  MD5_Init(&ctx);
241  MD5_Update(&ctx, (void*)data, size);
242  MD5_Final((unsigned char*)&res.hash[0], &ctx);
243  return res;
244}
245}  // namespace __tsan
246