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
15 namespace __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
32 typedef unsigned int MD5_u32plus;
33 typedef unsigned long ulong_t; // NOLINT
34
35 typedef 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
body(MD5_CTX * ctx,void * data,ulong_t size)42 static 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
MD5_Init(MD5_CTX * ctx)144 void 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
MD5_Update(MD5_CTX * ctx,void * data,ulong_t size)154 void 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
MD5_Final(unsigned char * result,MD5_CTX * ctx)187 void 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
md5_hash(const void * data,uptr size)237 MD5Hash 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