| /* Md5.c -- MD5 Hash |
| : Igor Pavlov : Public domain |
| This code is based on Colin Plumb's public domain md5.c code */ |
| |
| #include "Precomp.h" |
| |
| #include <string.h> |
| |
| #include "Md5.h" |
| #include "RotateDefs.h" |
| #include "CpuArch.h" |
| |
| #define MD5_UPDATE_BLOCKS(p) Md5_UpdateBlocks |
| |
| Z7_NO_INLINE |
| void Md5_Init(CMd5 *p) |
| { |
| p->count = 0; |
| p->state[0] = 0x67452301; |
| p->state[1] = 0xefcdab89; |
| p->state[2] = 0x98badcfe; |
| p->state[3] = 0x10325476; |
| } |
| |
| #if 0 && !defined(MY_CPU_LE_UNALIGN) |
| // optional optimization for Big-endian processors or processors without unaligned access: |
| // it is intended to reduce the number of complex LE32 memory reading from 64 to 16. |
| // But some compilers (sparc, armt) are better without this optimization. |
| #define Z7_MD5_USE_DATA32_ARRAY |
| #endif |
| |
| #define LOAD_DATA(i) GetUi32((const UInt32 *)(const void *)data + (i)) |
| |
| #ifdef Z7_MD5_USE_DATA32_ARRAY |
| #define D(i) data32[i] |
| #else |
| #define D(i) LOAD_DATA(i) |
| #endif |
| |
| #define F1(x, y, z) (z ^ (x & (y ^ z))) |
| #define F2(x, y, z) F1(z, x, y) |
| #define F3(x, y, z) (x ^ y ^ z) |
| #define F4(x, y, z) (y ^ (x | ~z)) |
| |
| #define R1(i, f, start, step, w, x, y, z, s, k) \ |
| w += D((start + step * (i)) % 16) + k; \ |
| w += f(x, y, z); \ |
| w = rotlFixed(w, s) + x; \ |
| |
| #define R4(i4, f, start, step, s0,s1,s2,s3, k0,k1,k2,k3) \ |
| R1 (i4*4+0, f, start, step, a,b,c,d, s0, k0) \ |
| R1 (i4*4+1, f, start, step, d,a,b,c, s1, k1) \ |
| R1 (i4*4+2, f, start, step, c,d,a,b, s2, k2) \ |
| R1 (i4*4+3, f, start, step, b,c,d,a, s3, k3) \ |
| |
| #define R16(f, start, step, s0,s1,s2,s3, k00,k01,k02,k03, k10,k11,k12,k13, k20,k21,k22,k23, k30,k31,k32,k33) \ |
| R4 (0, f, start, step, s0,s1,s2,s3, k00,k01,k02,k03) \ |
| R4 (1, f, start, step, s0,s1,s2,s3, k10,k11,k12,k13) \ |
| R4 (2, f, start, step, s0,s1,s2,s3, k20,k21,k22,k23) \ |
| R4 (3, f, start, step, s0,s1,s2,s3, k30,k31,k32,k33) \ |
| |
| static |
| Z7_NO_INLINE |
| void Z7_FASTCALL Md5_UpdateBlocks(UInt32 state[4], const Byte *data, size_t numBlocks) |
| { |
| UInt32 a, b, c, d; |
| // if (numBlocks == 0) return; |
| a = state[0]; |
| b = state[1]; |
| c = state[2]; |
| d = state[3]; |
| do |
| { |
| #ifdef Z7_MD5_USE_DATA32_ARRAY |
| UInt32 data32[MD5_NUM_BLOCK_WORDS]; |
| { |
| #define LOAD_data32_x4(i) { \ |
| data32[i ] = LOAD_DATA(i ); \ |
| data32[i + 1] = LOAD_DATA(i + 1); \ |
| data32[i + 2] = LOAD_DATA(i + 2); \ |
| data32[i + 3] = LOAD_DATA(i + 3); } |
| #if 1 |
| LOAD_data32_x4 (0 * 4) |
| LOAD_data32_x4 (1 * 4) |
| LOAD_data32_x4 (2 * 4) |
| LOAD_data32_x4 (3 * 4) |
| #else |
| unsigned i; |
| for (i = 0; i < MD5_NUM_BLOCK_WORDS; i += 4) |
| { |
| LOAD_data32_x4(i) |
| } |
| #endif |
| } |
| #endif |
| |
| R16 (F1, 0, 1, 7,12,17,22, 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, |
| 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, |
| 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, |
| 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821) |
| R16 (F2, 1, 5, 5, 9,14,20, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, |
| 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, |
| 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, |
| 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a) |
| R16 (F3, 5, 3, 4,11,16,23, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, |
| 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, |
| 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, |
| 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665) |
| R16 (F4, 0, 7, 6,10,15,21, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, |
| 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, |
| 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, |
| 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391) |
| |
| a += state[0]; |
| b += state[1]; |
| c += state[2]; |
| d += state[3]; |
| |
| state[0] = a; |
| state[1] = b; |
| state[2] = c; |
| state[3] = d; |
| |
| data += MD5_BLOCK_SIZE; |
| } |
| while (--numBlocks); |
| } |
| |
| |
| #define Md5_UpdateBlock(p) MD5_UPDATE_BLOCKS(p)(p->state, p->buffer, 1) |
| |
| void Md5_Update(CMd5 *p, const Byte *data, size_t size) |
| { |
| if (size == 0) |
| return; |
| { |
| const unsigned pos = (unsigned)p->count & (MD5_BLOCK_SIZE - 1); |
| const unsigned num = MD5_BLOCK_SIZE - pos; |
| p->count += size; |
| if (num > size) |
| { |
| memcpy(p->buffer + pos, data, size); |
| return; |
| } |
| if (pos != 0) |
| { |
| size -= num; |
| memcpy(p->buffer + pos, data, num); |
| data += num; |
| Md5_UpdateBlock(p); |
| } |
| } |
| { |
| const size_t numBlocks = size >> 6; |
| if (numBlocks) |
| MD5_UPDATE_BLOCKS(p)(p->state, data, numBlocks); |
| size &= MD5_BLOCK_SIZE - 1; |
| if (size == 0) |
| return; |
| data += (numBlocks << 6); |
| memcpy(p->buffer, data, size); |
| } |
| } |
| |
| |
| void Md5_Final(CMd5 *p, Byte *digest) |
| { |
| unsigned pos = (unsigned)p->count & (MD5_BLOCK_SIZE - 1); |
| p->buffer[pos++] = 0x80; |
| if (pos > (MD5_BLOCK_SIZE - 4 * 2)) |
| { |
| while (pos != MD5_BLOCK_SIZE) { p->buffer[pos++] = 0; } |
| // memset(&p->buf.buffer[pos], 0, MD5_BLOCK_SIZE - pos); |
| Md5_UpdateBlock(p); |
| pos = 0; |
| } |
| memset(&p->buffer[pos], 0, (MD5_BLOCK_SIZE - 4 * 2) - pos); |
| { |
| const UInt64 numBits = p->count << 3; |
| #if defined(MY_CPU_LE_UNALIGN) |
| SetUi64 (p->buffer + MD5_BLOCK_SIZE - 4 * 2, numBits) |
| #else |
| SetUi32a(p->buffer + MD5_BLOCK_SIZE - 4 * 2, (UInt32)(numBits)) |
| SetUi32a(p->buffer + MD5_BLOCK_SIZE - 4 * 1, (UInt32)(numBits >> 32)) |
| #endif |
| } |
| Md5_UpdateBlock(p); |
| |
| SetUi32(digest, p->state[0]) |
| SetUi32(digest + 4, p->state[1]) |
| SetUi32(digest + 8, p->state[2]) |
| SetUi32(digest + 12, p->state[3]) |
| |
| Md5_Init(p); |
| } |
| |
| #undef R1 |
| #undef R4 |
| #undef R16 |
| #undef D |
| #undef LOAD_DATA |
| #undef LOAD_data32_x4 |
| #undef F1 |
| #undef F2 |
| #undef F3 |
| #undef F4 |