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
14namespace __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
31typedef unsigned int MD5_u32plus;
32typedef unsigned long ulong_t;
33
34typedef 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
41static 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
149void 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
159void 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(dest: &ctx->buffer[used], src: data, n: size);
175 return;
176 }
177
178 internal_memcpy(dest: &ctx->buffer[used], src: data, n: free);
179 data = (const unsigned char *)data + free;
180 size -= free;
181 body(ctx, data: ctx->buffer, size: 64);
182 }
183
184 if (size >= 64) {
185 data = body(ctx, data, size: size & ~(ulong_t)0x3f);
186 size &= 0x3f;
187 }
188
189 internal_memcpy(dest: ctx->buffer, src: data, n: size);
190}
191
192void 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(s: &ctx->buffer[used], c: 0, n: free);
203 body(ctx, data: ctx->buffer, size: 64);
204 used = 0;
205 free = 64;
206 }
207
208 internal_memset(s: &ctx->buffer[used], c: 0, n: 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, data: ctx->buffer, size: 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(s: ctx, c: 0, n: sizeof(*ctx));
240}
241
242MD5Hash md5_hash(const void *data, uptr size) {
243 MD5Hash res;
244 MD5_CTX ctx;
245 MD5_Init(ctx: &ctx);
246 MD5_Update(ctx: &ctx, data, size);
247 MD5_Final(result: (unsigned char*)&res.hash[0], ctx: &ctx);
248 return res;
249}
250} // namespace __tsan
251