MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
md5.cpp
1 /*
2  Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to the
15  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
16  MA 02110-1301 USA.
17 */
18 
19 
20 /* based on Wei Dai's md5.cpp from CryptoPP */
21 
22 #include "runtime.hpp"
23 #include "md5.hpp"
24 #ifdef USE_SYS_STL
25  #include <algorithm>
26 #else
27  #include "algorithm.hpp"
28 #endif
29 
30 
31 namespace STL = STL_NAMESPACE;
32 
33 
34 
35 namespace TaoCrypt {
36 
37 void MD5::Init()
38 {
39  digest_[0] = 0x67452301L;
40  digest_[1] = 0xefcdab89L;
41  digest_[2] = 0x98badcfeL;
42  digest_[3] = 0x10325476L;
43 
44  buffLen_ = 0;
45  loLen_ = 0;
46  hiLen_ = 0;
47 }
48 
49 
50 MD5::MD5(const MD5& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32),
51  BLOCK_SIZE)
52 {
53  buffLen_ = that.buffLen_;
54  loLen_ = that.loLen_;
55  hiLen_ = that.hiLen_;
56 
57  memcpy(digest_, that.digest_, DIGEST_SIZE);
58  memcpy(buffer_, that.buffer_, BLOCK_SIZE);
59 }
60 
61 MD5& MD5::operator= (const MD5& that)
62 {
63  MD5 tmp(that);
64  Swap(tmp);
65 
66  return *this;
67 }
68 
69 
70 void MD5::Swap(MD5& other)
71 {
72  STL::swap(loLen_, other.loLen_);
73  STL::swap(hiLen_, other.hiLen_);
74  STL::swap(buffLen_, other.buffLen_);
75 
76  memcpy(digest_, other.digest_, DIGEST_SIZE);
77  memcpy(buffer_, other.buffer_, BLOCK_SIZE);
78 }
79 
80 
81 #ifdef DO_MD5_ASM
82 
83 // Update digest with data of size len
84 void MD5::Update(const byte* data, word32 len)
85 {
86  if (!isMMX) {
87  HASHwithTransform::Update(data, len);
88  return;
89  }
90 
91  byte* local = reinterpret_cast<byte*>(buffer_);
92 
93  // remove buffered data if possible
94  if (buffLen_) {
95  word32 add = min(len, BLOCK_SIZE - buffLen_);
96  memcpy(&local[buffLen_], data, add);
97 
98  buffLen_ += add;
99  data += add;
100  len -= add;
101 
102  if (buffLen_ == BLOCK_SIZE) {
103  Transform();
104  AddLength(BLOCK_SIZE);
105  buffLen_ = 0;
106  }
107  }
108 
109  // at once for asm
110  if (buffLen_ == 0) {
111  word32 times = len / BLOCK_SIZE;
112  if (times) {
113  AsmTransform(data, times);
114  const word32 add = BLOCK_SIZE * times;
115  AddLength(add);
116  len -= add;
117  data += add;
118  }
119  }
120 
121  // cache any data left
122  if (len) {
123  memcpy(&local[buffLen_], data, len);
124  buffLen_ += len;
125  }
126 }
127 
128 
129 
130 
131 /*
132  // w = rotlFixed(w + f(x, y, z) + index[edi] + data, s) + x
133 #define ASMMD5STEP(f, w, x, y, z, index, data, s) \
134  f(x, y, z) \
135  AS2( mov ebp, [edi + index * 4] ) \
136  AS2( lea w, [esi + w + data] ) \
137  AS2( add w, ebp ) \
138  AS2( rol w, s ) \
139  AS2( add w, x )
140 
141 
142  // F1(x, y, z) (z ^ (x & (y ^ z)))
143  // place in esi
144 #define ASMF1(x, y, z) \
145  AS2( mov esi, y ) \
146  AS2( xor esi, z ) \
147  AS2( and esi, x ) \
148  AS2( xor esi, z )
149 
150 
151 #define ASMF2(x, y, z) ASMF1(z, x, y)
152 
153 
154  // F3(x ^ y ^ z)
155  // place in esi
156 #define ASMF3(x, y, z) \
157  AS2( mov esi, x ) \
158  AS2( xor esi, y ) \
159  AS2( xor esi, z )
160 
161 
162 
163  // F4(x, y, z) (y ^ (x | ~z))
164  // place in esi
165 #define ASMF4(x, y, z) \
166  AS2( mov esi, z ) \
167  AS1( not esi ) \
168  AS2( or esi, x ) \
169  AS2( xor esi, y )
170 */
171 
172 
173  // combine above ASMMD5STEP(f w/ each f ASMF1 - F4
174 
175  // esi already set up, after using set for next round
176  // ebp already set up, set up using next round index
177 
178 #define MD5STEP1(w, x, y, z, index, data, s) \
179  AS2( xor esi, z ) \
180  AS2( and esi, x ) \
181  AS2( lea w, [ebp + w + data] ) \
182  AS2( xor esi, z ) \
183  AS2( add w, esi ) \
184  AS2( mov esi, x ) \
185  AS2( rol w, s ) \
186  AS2( mov ebp, [edi + index * 4] ) \
187  AS2( add w, x )
188 
189 #define MD5STEP2(w, x, y, z, index, data, s) \
190  AS2( xor esi, x ) \
191  AS2( and esi, z ) \
192  AS2( lea w, [ebp + w + data] ) \
193  AS2( xor esi, y ) \
194  AS2( add w, esi ) \
195  AS2( mov esi, x ) \
196  AS2( rol w, s ) \
197  AS2( mov ebp, [edi + index * 4] ) \
198  AS2( add w, x )
199 
200 
201 #define MD5STEP3(w, x, y, z, index, data, s) \
202  AS2( xor esi, z ) \
203  AS2( lea w, [ebp + w + data] ) \
204  AS2( xor esi, x ) \
205  AS2( add w, esi ) \
206  AS2( mov esi, x ) \
207  AS2( rol w, s ) \
208  AS2( mov ebp, [edi + index * 4] ) \
209  AS2( add w, x )
210 
211 
212 #define MD5STEP4(w, x, y, z, index, data, s) \
213  AS2( or esi, x ) \
214  AS2( lea w, [ebp + w + data] ) \
215  AS2( xor esi, y ) \
216  AS2( add w, esi ) \
217  AS2( mov esi, y ) \
218  AS2( rol w, s ) \
219  AS1( not esi ) \
220  AS2( mov ebp, [edi + index * 4] ) \
221  AS2( add w, x )
222 
223 
224 
225 #ifdef _MSC_VER
226  __declspec(naked)
227 #endif
228 void MD5::AsmTransform(const byte* data, word32 times)
229 {
230 #ifdef __GNUC__
231  #define AS1(x) asm(#x);
232  #define AS2(x, y) asm(#x ", " #y);
233 
234  #define PROLOG() \
235  asm(".intel_syntax noprefix"); \
236  AS2( movd mm3, edi ) \
237  AS2( movd mm4, ebx ) \
238  AS2( movd mm5, esi ) \
239  AS2( movd mm6, ebp ) \
240  AS2( mov ecx, DWORD PTR [ebp + 8] ) \
241  AS2( mov edi, DWORD PTR [ebp + 12] ) \
242  AS2( mov eax, DWORD PTR [ebp + 16] )
243 
244  #define EPILOG() \
245  AS2( movd ebp, mm6 ) \
246  AS2( movd esi, mm5 ) \
247  AS2( movd ebx, mm4 ) \
248  AS2( mov esp, ebp ) \
249  AS2( movd edi, mm3 ) \
250  AS1( emms ) \
251  asm(".att_syntax");
252 #else
253  #define AS1(x) __asm x
254  #define AS2(x, y) __asm x, y
255 
256  #define PROLOG() \
257  AS1( push ebp ) \
258  AS2( mov ebp, esp ) \
259  AS2( movd mm3, edi ) \
260  AS2( movd mm4, ebx ) \
261  AS2( movd mm5, esi ) \
262  AS2( movd mm6, ebp ) \
263  AS2( mov edi, DWORD PTR [ebp + 8] ) \
264  AS2( mov eax, DWORD PTR [ebp + 12] )
265 
266  #define EPILOG() \
267  AS2( movd ebp, mm6 ) \
268  AS2( movd esi, mm5 ) \
269  AS2( movd ebx, mm4 ) \
270  AS2( movd edi, mm3 ) \
271  AS2( mov esp, ebp ) \
272  AS1( pop ebp ) \
273  AS1( emms ) \
274  AS1( ret 8 )
275 
276 #endif
277 
278 
279  PROLOG()
280 
281  AS2( mov esi, ecx )
282 
283  #ifdef OLD_GCC_OFFSET
284  AS2( add esi, 20 ) // digest_[0]
285  #else
286  AS2( add esi, 16 ) // digest_[0]
287  #endif
288 
289  AS2( movd mm2, eax ) // store times_
290  AS2( movd mm1, esi ) // store digest_
291 
292  AS2( mov eax, [esi] ) // a
293  AS2( mov ebx, [esi + 4] ) // b
294  AS2( mov ecx, [esi + 8] ) // c
295  AS2( mov edx, [esi + 12] ) // d
296 
297 AS1(loopStart:)
298 
299  // set up
300  AS2( mov esi, ecx )
301  AS2( mov ebp, [edi] )
302 
303  MD5STEP1( eax, ebx, ecx, edx, 1, 0xd76aa478, 7)
304  MD5STEP1( edx, eax, ebx, ecx, 2, 0xe8c7b756, 12)
305  MD5STEP1( ecx, edx, eax, ebx, 3, 0x242070db, 17)
306  MD5STEP1( ebx, ecx, edx, eax, 4, 0xc1bdceee, 22)
307  MD5STEP1( eax, ebx, ecx, edx, 5, 0xf57c0faf, 7)
308  MD5STEP1( edx, eax, ebx, ecx, 6, 0x4787c62a, 12)
309  MD5STEP1( ecx, edx, eax, ebx, 7, 0xa8304613, 17)
310  MD5STEP1( ebx, ecx, edx, eax, 8, 0xfd469501, 22)
311  MD5STEP1( eax, ebx, ecx, edx, 9, 0x698098d8, 7)
312  MD5STEP1( edx, eax, ebx, ecx, 10, 0x8b44f7af, 12)
313  MD5STEP1( ecx, edx, eax, ebx, 11, 0xffff5bb1, 17)
314  MD5STEP1( ebx, ecx, edx, eax, 12, 0x895cd7be, 22)
315  MD5STEP1( eax, ebx, ecx, edx, 13, 0x6b901122, 7)
316  MD5STEP1( edx, eax, ebx, ecx, 14, 0xfd987193, 12)
317  MD5STEP1( ecx, edx, eax, ebx, 15, 0xa679438e, 17)
318  MD5STEP1( ebx, ecx, edx, eax, 1, 0x49b40821, 22)
319 
320  MD5STEP2( eax, ebx, ecx, edx, 6, 0xf61e2562, 5)
321  MD5STEP2( edx, eax, ebx, ecx, 11, 0xc040b340, 9)
322  MD5STEP2( ecx, edx, eax, ebx, 0, 0x265e5a51, 14)
323  MD5STEP2( ebx, ecx, edx, eax, 5, 0xe9b6c7aa, 20)
324  MD5STEP2( eax, ebx, ecx, edx, 10, 0xd62f105d, 5)
325  MD5STEP2( edx, eax, ebx, ecx, 15, 0x02441453, 9)
326  MD5STEP2( ecx, edx, eax, ebx, 4, 0xd8a1e681, 14)
327  MD5STEP2( ebx, ecx, edx, eax, 9, 0xe7d3fbc8, 20)
328  MD5STEP2( eax, ebx, ecx, edx, 14, 0x21e1cde6, 5)
329  MD5STEP2( edx, eax, ebx, ecx, 3, 0xc33707d6, 9)
330  MD5STEP2( ecx, edx, eax, ebx, 8, 0xf4d50d87, 14)
331  MD5STEP2( ebx, ecx, edx, eax, 13, 0x455a14ed, 20)
332  MD5STEP2( eax, ebx, ecx, edx, 2, 0xa9e3e905, 5)
333  MD5STEP2( edx, eax, ebx, ecx, 7, 0xfcefa3f8, 9)
334  MD5STEP2( ecx, edx, eax, ebx, 12, 0x676f02d9, 14)
335  MD5STEP2( ebx, ecx, edx, eax, 5, 0x8d2a4c8a, 20)
336 
337  MD5STEP3( eax, ebx, ecx, edx, 8, 0xfffa3942, 4)
338  MD5STEP3( edx, eax, ebx, ecx, 11, 0x8771f681, 11)
339  MD5STEP3( ecx, edx, eax, ebx, 14, 0x6d9d6122, 16)
340  MD5STEP3( ebx, ecx, edx, eax, 1, 0xfde5380c, 23)
341  MD5STEP3( eax, ebx, ecx, edx, 4, 0xa4beea44, 4)
342  MD5STEP3( edx, eax, ebx, ecx, 7, 0x4bdecfa9, 11)
343  MD5STEP3( ecx, edx, eax, ebx, 10, 0xf6bb4b60, 16)
344  MD5STEP3( ebx, ecx, edx, eax, 13, 0xbebfbc70, 23)
345  MD5STEP3( eax, ebx, ecx, edx, 0, 0x289b7ec6, 4)
346  MD5STEP3( edx, eax, ebx, ecx, 3, 0xeaa127fa, 11)
347  MD5STEP3( ecx, edx, eax, ebx, 6, 0xd4ef3085, 16)
348  MD5STEP3( ebx, ecx, edx, eax, 9, 0x04881d05, 23)
349  MD5STEP3( eax, ebx, ecx, edx, 12, 0xd9d4d039, 4)
350  MD5STEP3( edx, eax, ebx, ecx, 15, 0xe6db99e5, 11)
351  MD5STEP3( ecx, edx, eax, ebx, 2, 0x1fa27cf8, 16)
352  MD5STEP3( ebx, ecx, edx, eax, 0, 0xc4ac5665, 23)
353 
354  // setup
355  AS2( mov esi, edx )
356  AS1( not esi )
357 
358  MD5STEP4( eax, ebx, ecx, edx, 7, 0xf4292244, 6)
359  MD5STEP4( edx, eax, ebx, ecx, 14, 0x432aff97, 10)
360  MD5STEP4( ecx, edx, eax, ebx, 5, 0xab9423a7, 15)
361  MD5STEP4( ebx, ecx, edx, eax, 12, 0xfc93a039, 21)
362  MD5STEP4( eax, ebx, ecx, edx, 3, 0x655b59c3, 6)
363  MD5STEP4( edx, eax, ebx, ecx, 10, 0x8f0ccc92, 10)
364  MD5STEP4( ecx, edx, eax, ebx, 1, 0xffeff47d, 15)
365  MD5STEP4( ebx, ecx, edx, eax, 8, 0x85845dd1, 21)
366  MD5STEP4( eax, ebx, ecx, edx, 15, 0x6fa87e4f, 6)
367  MD5STEP4( edx, eax, ebx, ecx, 6, 0xfe2ce6e0, 10)
368  MD5STEP4( ecx, edx, eax, ebx, 13, 0xa3014314, 15)
369  MD5STEP4( ebx, ecx, edx, eax, 4, 0x4e0811a1, 21)
370  MD5STEP4( eax, ebx, ecx, edx, 11, 0xf7537e82, 6)
371  MD5STEP4( edx, eax, ebx, ecx, 2, 0xbd3af235, 10)
372  MD5STEP4( ecx, edx, eax, ebx, 9, 0x2ad7d2bb, 15)
373  MD5STEP4( ebx, ecx, edx, eax, 9, 0xeb86d391, 21)
374 
375  AS2( movd esi, mm1 ) // digest_
376 
377  AS2( add [esi], eax ) // write out
378  AS2( add [esi + 4], ebx )
379  AS2( add [esi + 8], ecx )
380  AS2( add [esi + 12], edx )
381 
382  AS2( add edi, 64 )
383 
384  AS2( mov eax, [esi] )
385  AS2( mov ebx, [esi + 4] )
386  AS2( mov ecx, [esi + 8] )
387  AS2( mov edx, [esi + 12] )
388 
389  AS2( movd ebp, mm2 ) // times
390  AS1( dec ebp )
391  AS2( movd mm2, ebp )
392  AS1( jnz loopStart )
393 
394 
395  EPILOG()
396 }
397 
398 
399 #endif // DO_MD5_ASM
400 
401 
402 void MD5::Transform()
403 {
404 #define F1(x, y, z) (z ^ (x & (y ^ z)))
405 #define F2(x, y, z) F1(z, x, y)
406 #define F3(x, y, z) (x ^ y ^ z)
407 #define F4(x, y, z) (y ^ (x | ~z))
408 
409 #define MD5STEP(f, w, x, y, z, data, s) \
410  w = rotlFixed(w + f(x, y, z) + data, s) + x
411 
412  // Copy context->state[] to working vars
413  word32 a = digest_[0];
414  word32 b = digest_[1];
415  word32 c = digest_[2];
416  word32 d = digest_[3];
417 
418  MD5STEP(F1, a, b, c, d, buffer_[0] + 0xd76aa478, 7);
419  MD5STEP(F1, d, a, b, c, buffer_[1] + 0xe8c7b756, 12);
420  MD5STEP(F1, c, d, a, b, buffer_[2] + 0x242070db, 17);
421  MD5STEP(F1, b, c, d, a, buffer_[3] + 0xc1bdceee, 22);
422  MD5STEP(F1, a, b, c, d, buffer_[4] + 0xf57c0faf, 7);
423  MD5STEP(F1, d, a, b, c, buffer_[5] + 0x4787c62a, 12);
424  MD5STEP(F1, c, d, a, b, buffer_[6] + 0xa8304613, 17);
425  MD5STEP(F1, b, c, d, a, buffer_[7] + 0xfd469501, 22);
426  MD5STEP(F1, a, b, c, d, buffer_[8] + 0x698098d8, 7);
427  MD5STEP(F1, d, a, b, c, buffer_[9] + 0x8b44f7af, 12);
428  MD5STEP(F1, c, d, a, b, buffer_[10] + 0xffff5bb1, 17);
429  MD5STEP(F1, b, c, d, a, buffer_[11] + 0x895cd7be, 22);
430  MD5STEP(F1, a, b, c, d, buffer_[12] + 0x6b901122, 7);
431  MD5STEP(F1, d, a, b, c, buffer_[13] + 0xfd987193, 12);
432  MD5STEP(F1, c, d, a, b, buffer_[14] + 0xa679438e, 17);
433  MD5STEP(F1, b, c, d, a, buffer_[15] + 0x49b40821, 22);
434 
435  MD5STEP(F2, a, b, c, d, buffer_[1] + 0xf61e2562, 5);
436  MD5STEP(F2, d, a, b, c, buffer_[6] + 0xc040b340, 9);
437  MD5STEP(F2, c, d, a, b, buffer_[11] + 0x265e5a51, 14);
438  MD5STEP(F2, b, c, d, a, buffer_[0] + 0xe9b6c7aa, 20);
439  MD5STEP(F2, a, b, c, d, buffer_[5] + 0xd62f105d, 5);
440  MD5STEP(F2, d, a, b, c, buffer_[10] + 0x02441453, 9);
441  MD5STEP(F2, c, d, a, b, buffer_[15] + 0xd8a1e681, 14);
442  MD5STEP(F2, b, c, d, a, buffer_[4] + 0xe7d3fbc8, 20);
443  MD5STEP(F2, a, b, c, d, buffer_[9] + 0x21e1cde6, 5);
444  MD5STEP(F2, d, a, b, c, buffer_[14] + 0xc33707d6, 9);
445  MD5STEP(F2, c, d, a, b, buffer_[3] + 0xf4d50d87, 14);
446  MD5STEP(F2, b, c, d, a, buffer_[8] + 0x455a14ed, 20);
447  MD5STEP(F2, a, b, c, d, buffer_[13] + 0xa9e3e905, 5);
448  MD5STEP(F2, d, a, b, c, buffer_[2] + 0xfcefa3f8, 9);
449  MD5STEP(F2, c, d, a, b, buffer_[7] + 0x676f02d9, 14);
450  MD5STEP(F2, b, c, d, a, buffer_[12] + 0x8d2a4c8a, 20);
451 
452  MD5STEP(F3, a, b, c, d, buffer_[5] + 0xfffa3942, 4);
453  MD5STEP(F3, d, a, b, c, buffer_[8] + 0x8771f681, 11);
454  MD5STEP(F3, c, d, a, b, buffer_[11] + 0x6d9d6122, 16);
455  MD5STEP(F3, b, c, d, a, buffer_[14] + 0xfde5380c, 23);
456  MD5STEP(F3, a, b, c, d, buffer_[1] + 0xa4beea44, 4);
457  MD5STEP(F3, d, a, b, c, buffer_[4] + 0x4bdecfa9, 11);
458  MD5STEP(F3, c, d, a, b, buffer_[7] + 0xf6bb4b60, 16);
459  MD5STEP(F3, b, c, d, a, buffer_[10] + 0xbebfbc70, 23);
460  MD5STEP(F3, a, b, c, d, buffer_[13] + 0x289b7ec6, 4);
461  MD5STEP(F3, d, a, b, c, buffer_[0] + 0xeaa127fa, 11);
462  MD5STEP(F3, c, d, a, b, buffer_[3] + 0xd4ef3085, 16);
463  MD5STEP(F3, b, c, d, a, buffer_[6] + 0x04881d05, 23);
464  MD5STEP(F3, a, b, c, d, buffer_[9] + 0xd9d4d039, 4);
465  MD5STEP(F3, d, a, b, c, buffer_[12] + 0xe6db99e5, 11);
466  MD5STEP(F3, c, d, a, b, buffer_[15] + 0x1fa27cf8, 16);
467  MD5STEP(F3, b, c, d, a, buffer_[2] + 0xc4ac5665, 23);
468 
469  MD5STEP(F4, a, b, c, d, buffer_[0] + 0xf4292244, 6);
470  MD5STEP(F4, d, a, b, c, buffer_[7] + 0x432aff97, 10);
471  MD5STEP(F4, c, d, a, b, buffer_[14] + 0xab9423a7, 15);
472  MD5STEP(F4, b, c, d, a, buffer_[5] + 0xfc93a039, 21);
473  MD5STEP(F4, a, b, c, d, buffer_[12] + 0x655b59c3, 6);
474  MD5STEP(F4, d, a, b, c, buffer_[3] + 0x8f0ccc92, 10);
475  MD5STEP(F4, c, d, a, b, buffer_[10] + 0xffeff47d, 15);
476  MD5STEP(F4, b, c, d, a, buffer_[1] + 0x85845dd1, 21);
477  MD5STEP(F4, a, b, c, d, buffer_[8] + 0x6fa87e4f, 6);
478  MD5STEP(F4, d, a, b, c, buffer_[15] + 0xfe2ce6e0, 10);
479  MD5STEP(F4, c, d, a, b, buffer_[6] + 0xa3014314, 15);
480  MD5STEP(F4, b, c, d, a, buffer_[13] + 0x4e0811a1, 21);
481  MD5STEP(F4, a, b, c, d, buffer_[4] + 0xf7537e82, 6);
482  MD5STEP(F4, d, a, b, c, buffer_[11] + 0xbd3af235, 10);
483  MD5STEP(F4, c, d, a, b, buffer_[2] + 0x2ad7d2bb, 15);
484  MD5STEP(F4, b, c, d, a, buffer_[9] + 0xeb86d391, 21);
485 
486  // Add the working vars back into digest state[]
487  digest_[0] += a;
488  digest_[1] += b;
489  digest_[2] += c;
490  digest_[3] += d;
491 
492  // Wipe variables
493  a = b = c = d = 0;
494 }
495 
496 
497 } // namespace
498