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