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