#include <stdio.h> #include <stdlib.h> #define A (0x67452301) #define B (0xefcdab89) #define C (0x98badcfe) #define D (0x10325476) #define X(_a, _b, _r, _m, _s, _t) \ ((_a) = (_b) + rol((_a) + (_r) + (_m) + (_t), (_s))) const int N[4][2] = {{0, 1}, {1, 5}, {5, 3}, {0, 7}}; const unsigned long S[4][4] = { {7, 12, 17, 22}, {5, 9, 14, 20}, {4, 11, 16, 23}, {6, 10, 15, 21} }; //(4294967296 * abs(sin(i *16 + j + 1))) const unsigned long T[4][16] = { { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 }, { 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a }, { 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 }, { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 } }; //DESP: MD5 F unsigned long F(unsigned long x, unsigned long y, unsigned long z) { return (x & y) | ((~x) & z); } //DESP: MD5 G unsigned long G(unsigned long x, unsigned long y, unsigned long z) { return (x & z) | (y & (~z)); } //DESP: MD5 H unsigned long H(unsigned long x, unsigned long y, unsigned long z) { return (x ^ y ^ z); } //DESP: MD5 I unsigned long I(unsigned long x, unsigned long y, unsigned long z) { return y ^ (x | (~z)); } //non-line function unsigned long ((*md5nl[4])(unsigned long x, unsigned long y, unsigned long z)) = { F, G, H, I }; //DESP: Rotate Left unsigned long rol(unsigned long n, unsigned long c) { return (n << c) | (n >> (32 - c)); } //DESP: MD5 update void md5_update(unsigned long chain[4], unsigned long msg[16]) { unsigned long state[4]; int i, j, n, k; //DO: copy state for(i = 0; i < 4; i++) state[i] = chain[i]; for(i = 0; i < 4; i++) { n = N[i][0]; for(j = 0; j < 16; j++) { k = ((4 - (j & 3)) & 3); //DO: md5 FF,GG,HH,II X(state[k], state[(k + 1) & 3], md5nl[i](state[(k + 1) & 3], state[(k + 2) & 3], state[(k + 3) & 3]), msg[n & 0x0f], S[i][j & 3], T[i][j]); n += N[i][1]; } } //DO: add to chain for(i = 0; i < 4; i++) chain[i] += state[i]; return; } //DESP: MD5 final void md5_final(unsigned long chain[4], unsigned char *tail, unsigned long len[2]) { unsigned char msg[128]; int i, l, n; //tail length l = len[0] & 0x3f; //buffer size n = (l >= 56)? 120: 56; //copy tail to buffer for(i = 0; i < l; i++) msg[i] = tail[i]; if(n > l) { //DO: fill message msg[l] = 0x80; for(i = l + 1; i < n; i++) msg[i] = 0; } //append bits length to message ((unsigned long *)(msg + n))[0] = len[0] << 3; ((unsigned long *)(msg + n))[1] = len[1] << 3 | len[0] >> 29; md5_update(chain, (unsigned long *)msg); if(n == 120) md5_update(chain, (unsigned long *)&msg[64]); return; } //DESP: MD5 initialize chaining variables void md5_init(unsigned long chain[4]) { chain[0] = A; chain[1] = B; chain[2] = C; chain[3] = D; return; } #define BLOCK_SIZE (0x1000 * sizeof(unsigned char)) #define BLOCK_DWORD (BLOCK_SIZE / sizeof(unsigned long)) #define MSG_SIZE (0x40 * sizeof(unsigned char)) #define MSG_DWORD (MSG_SIZE / sizeof(unsigned long)) //DESP: update chain for echo 4kb void md5_file_block(unsigned long sum[4], unsigned long block[BLOCK_DWORD]) { int i; for(i = 0; i < BLOCK_DWORD; i += MSG_DWORD) md5_update(sum, &block[i]); return; } //DESP: final chain void md5_file_final(unsigned long sum[4], unsigned long *block, unsigned long len[2]) { int i, n; //count of block n = (len[0] % BLOCK_SIZE) / MSG_SIZE; //reserve if((len[0] % MSG_SIZE) == 0) n--; n *= MSG_DWORD; for(i = 0; i < n; i += MSG_DWORD) md5_update(sum, &block[i]); md5_final(sum, (unsigned char *)&block[i], len); return; } //DESP: demo for compute file's MD5 int md5_file(char *file, unsigned char result[16]) { FILE *in; int r; unsigned long n; unsigned long *p; unsigned long l[2]; unsigned long sum[4]; //open file if(fopen_s(&in, file, "rb") != 0) return 0; l[0] = l[1] = 0; p = (unsigned long *)malloc(BLOCK_SIZE); if(!p) { fclose(in); return 0; } r = 1; md5_init(sum); for(;;) { n = fread(p, sizeof(unsigned char), BLOCK_SIZE, in); if(ferror(in)) { r = 0; break; } if(feof(in)) { n += l[0]; if(n < l[0]) l[1]++; md5_final(sum, (unsigned char *)p, l); for(n = 0; n < 4; n++) ((unsigned long *)result)[n] = sum[n]; break; } else { md5_file_block(sum, p); n += l[0]; if(n < l[0]) l[1]++; } } free(p); fclose(in); return r; } int main(int argc, char *argv[]) { int i; unsigned char sum[16]; if(argc == 2) { if(!md5_file(argv[1], sum)) return 1; for(i = 0; i < 16; i++) printf("%02x", sum[i]); putchar(' '); puts(argv[1]); return 0; } return 1; }