xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/tsan/tsan_md5.cc (revision d909946ca08dceb44d7d0f22ec9488679695d976)
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   (*(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 
40 static void *body(MD5_CTX *ctx, void *data, ulong_t size) {
41   unsigned char *ptr;
42   MD5_u32plus a, b, c, d;
43   MD5_u32plus saved_a, saved_b, saved_c, saved_d;
44 
45   ptr = (unsigned char*)data;
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 
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 
152 void MD5_Update(MD5_CTX *ctx, 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 = (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 
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 
235 MD5Hash md5_hash(const void *data, uptr size) {
236   MD5Hash res;
237   MD5_CTX ctx;
238   MD5_Init(&ctx);
239   MD5_Update(&ctx, (void*)data, size);
240   MD5_Final((unsigned char*)&res.hash[0], &ctx);
241   return res;
242 }
243 }  // namespace __tsan
244