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 
14 namespace __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 
31 typedef unsigned int MD5_u32plus;
32 typedef unsigned long ulong_t;
33 
34 typedef 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 
41 static 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 
149 void 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 
159 void 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 
192 void 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 
242 MD5Hash 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