此算法存在一些问题,需要与http://blog.youkuaiyun.com/cloudblaze/article/details/51749513一致。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define BITS_PER_BYTE 8
#define GROUP_BITS 512
#define GROUP_SIZE (GROUP_BITS / BITS_PER_BYTE) // 64
#define SUBGROUPS_PER_GROUP 16
#define SUBGROUP_BITS (GROUP_BITS / SUBGROUPS_PER_GROUP) // 32
#define SUBGROUP_SIZE (GROUP_SIZE / SUBGROUPS_PER_GROUP) // 4
#define VAR_INPUT_LEN_SIZE 8
#define ROL(val,n) (((val) << (n)) | ((val) >> (32 - (n))))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
#define G(x,y,z) (((x) & (z)) | ((y) & (~(z))))
#define H(x,y,z) ((x) ^ (y) ^ (z))
#define I(x,y,z) (y ^ ((x) | (~(z))))
unsigned int state[] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476
};
unsigned int ti[64];
unsigned int round_index[64];
const unsigned int s[][4] = {
{7, 12, 17, 22}, {7, 12, 17, 22}, {7, 12, 17, 22}, {7, 12, 17, 22},
{5, 9, 14, 20}, {5, 9, 14, 20}, {5, 9, 14, 20}, {5, 9, 14, 20},
{4, 11, 16, 23}, {4, 11, 16, 23}, {4, 11, 16, 23}, {4, 11, 16, 23},
{6, 10, 15, 21}, {6, 10, 15, 21}, {6, 10, 15, 21}, {6, 10, 15, 21}
};
size_t add_bits(const char * src, unsigned char ** p_dest);
void transform(unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE]);
char * md5(const unsigned char * mem, char * buf);
int main(int argc, char * argv[])
{
const unsigned char * mem = NULL;
char buf[33] = {0};
if(argc > 2)
{
printf("Usage: %s <string>\n", argv[0]);
return EXIT_SUCCESS;
}
if(argc == 1)
mem = "";
else
mem = argv[1];
printf("%s\n", md5(mem, buf));
return EXIT_SUCCESS;
}
char * md5(const unsigned char * mem, char * buf)
{
unsigned char * dest;
unsigned char * group_start;
size_t dest_len;
unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE];
for(int i = 0; i < 64; i++)
ti[i] = (1UL << 32) * ABS(sin(i + 1));
dest_len = add_bits(mem, &dest);
group_start = dest;
for(int i = 0;
i < dest_len / GROUP_SIZE;
i++, group_start += GROUP_SIZE)
{
memcpy((unsigned char *)sub_group, group_start, GROUP_SIZE);
transform(sub_group);
}
unsigned char * pstate = (unsigned char *)state;
char * pbuf = buf;
for(int i = 0; i < 16; i++)
{
snprintf(pbuf, 3, "%02X", *pstate);
pbuf += 2;
pstate++;
}
free(dest);
return buf;
}
/*
* add_bits: 将输入补充二进制位。补充二进制位时,首先使其位长度len满足
* len % 512bits = 448bits(56bytes)。填充时,首先填充一位1,剩余的
* 位均填充0。然后,再填充64bits(8bytes),其值为未填充前的二进制位长
* 度。
* in@src: 原始输入。
* out@p_dest: 指向填充后的内存空间的指针的指针。
* return: 填充后的内存空间大小。
*/
size_t add_bits(const char * src, unsigned char ** p_dest)
{
size_t src_len;
size_t dest_len;
size_t rest_len;
unsigned char * dest;
src_len = strlen(src);
if(src_len == 0)
dest_len = GROUP_SIZE;
else
dest_len = (src_len + GROUP_SIZE - 1) / GROUP_SIZE * GROUP_SIZE;
rest_len = GROUP_SIZE - src_len % GROUP_SIZE;
if(rest_len < VAR_INPUT_LEN_SIZE)
dest_len += GROUP_SIZE;
if((dest = malloc(dest_len)) == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
memset(dest, 0, dest_len);
strncpy(dest, src, src_len);
if(rest_len > VAR_INPUT_LEN_SIZE)
{
dest[src_len] = 0x80;
memset(dest + src_len + 1, 0, rest_len - 1 - VAR_INPUT_LEN_SIZE);
}
else if(rest_len < VAR_INPUT_LEN_SIZE)
{
dest[src_len] = 0x80;
memset(dest + src_len + 1, 0, rest_len - 1 + GROUP_SIZE - VAR_INPUT_LEN_SIZE);
}
*(unsigned long long *)(dest + dest_len - VAR_INPUT_LEN_SIZE) = (unsigned long long)src_len * BITS_PER_BYTE;
*p_dest = dest;
return dest_len;
}
/*
* transform: 转换分组
*/
void transform(unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE])
{
unsigned int a;
unsigned int b;
unsigned int c;
unsigned int d;
unsigned int tmp;
unsigned int result, index;
a = state[0];
b = state[1];
c = state[2];
d = state[3];
for(int i = 0; i < 64; i++)
{
if(i < 16)
{
result = F(b, c, d);
index = i;
}
else if(i < 32)
{
result = G(b, c, d);
index = (5 * i + 1) % 16;
}
else if(i < 48)
{
result = H(b, c, d);
index = (3 * i + 5) % 16;
}
else
{
result = I(b, c, d);
index = (7 * i) % 16;
}
tmp = d;
d = c;
c = b;
b = b + ROL(
a + result + *(unsigned int *)&sub_group[index] + ti[i],
*((const unsigned int *)s + i));
a = tmp;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}