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