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