main.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define IS_APATH(p) (*(p) == '/')
#define IS_RPATH(p) (!(IS_APATH(p)))
char * md54file(const char * filename, char * md5str, bool isupper);
void calculate_files(const char * dir_path);
int main(int argc, char * argv[])
{
char path[PATH_MAX] = {0};
if((argc == 2 && strcmp(argv[1], "--help") == 0)
|| argc != 2)
{
printf("Usage: %s <path>\n", argv[0]);
return EXIT_SUCCESS;
}
if(strlen(argv[1]) >= PATH_MAX)
{
fprintf(stderr, "Path length is too long!\n");
return EXIT_FAILURE;
}
if(IS_RPATH(argv[1]))
realpath(argv[1], path);
else
strncpy(path, argv[1], PATH_MAX);
calculate_files(path);
return EXIT_SUCCESS;
}
void calculate_files(const char * dir_path)
{
DIR * dirp;
struct dirent * dp;
bool is_root;
char path[PATH_MAX] = {0};
char md5str[33] = {0};
is_root = strcmp(dir_path, "/") == 0;
if((dirp = opendir(dir_path)) == NULL)
{
perror("opendir");
return;
}
while(true)
{
errno = 0;
if((dp = readdir(dirp)) == NULL)
break;
if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue;
snprintf(path, PATH_MAX, "%s/%s", (is_root ? "" : dir_path), dp->d_name);
if(dp->d_type == DT_DIR)
calculate_files(path);
else if(dp->d_type == DT_REG)
{
if(md54file(path, md5str, false))
printf("%s %s\n", md5str, path);
}
}
if(closedir(dirp) != 0)
{
perror("closedir");
return;
}
}
md54file.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.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))))
#define BUF_SIZE 1024
static unsigned char read_buf[BUF_SIZE + GROUP_SIZE] = {0};
static bool has_init_ti = false;
static unsigned int state_init[] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476
};
static unsigned int ti[64];
static unsigned int round_index[64];
static 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}
};
static int add_bits(unsigned char * buf, size_t src_len);
static void transform(unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE], unsigned int * state);
char * md54file(const char * filename, char * md5str, bool isupper);
static void md5init(void);
static void md5init(void)
{
if(!has_init_ti)
{
for(int i = 0; i < 64; i++)
ti[i] = (1UL << 32) * ABS(sin(i + 1));
has_init_ti = true;
}
}
char * md54file(const char * filename, char * md5str, bool isupper)
{
unsigned char * group_start = NULL;
size_t dest_len = 0;
unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE] = {0};
unsigned int state[4] = {0};
unsigned char * pstate = (unsigned char *)state;
char * poutput = md5str;
md5init();
FILE * fp;
size_t count;
if((fp = fopen(filename, "r")) == NULL)
{
perror("fopen");
return NULL;
}
memcpy(state, state_init, sizeof(int) * 4);
memset(read_buf, 0, BUF_SIZE + GROUP_SIZE);
while((count = fread(read_buf, 1, BUF_SIZE, fp)) > 0)
{
dest_len += count;
group_start = read_buf;
for(int i = 0;
i < count / GROUP_SIZE;
i++, group_start += GROUP_SIZE)
{
memcpy((unsigned char *)sub_group, group_start, GROUP_SIZE);
transform(sub_group, state);
}
if(count % GROUP_SIZE != 0)
{
count %= GROUP_SIZE;
break;
}
memset(read_buf, 0, BUF_SIZE);
}
if(ferror(fp))
{
perror("fread");
return NULL;
}
else if(feof(fp))
{
int times = 0;
if(count == 0)
{
memset(read_buf, 0, BUF_SIZE);
group_start = read_buf;
}
else
memset(group_start + count, 0, GROUP_SIZE - count);
times = add_bits(group_start, dest_len);
for(int i = 0; i < times; i++)
{
memcpy((unsigned char *)sub_group, group_start, GROUP_SIZE);
transform(sub_group, state);
group_start += GROUP_SIZE;
}
}
if(fclose(fp) != 0)
{
perror("fclose");
return NULL;
}
for(int i = 0; i < 16; i++)
{
if(isupper)
snprintf(poutput, 3, "%02X", *pstate);
else
snprintf(poutput, 3, "%02x", *pstate);
poutput += 2;
pstate++;
}
return md5str;
}
static int add_bits(unsigned char * buf, size_t src_len)
{
size_t current_len;
size_t rest_len;
size_t dest_len;
unsigned char * dest;
int times = 1;
current_len = src_len % GROUP_SIZE;
if(current_len == 0)
dest_len = GROUP_SIZE;
else
dest_len = (current_len + GROUP_SIZE - 1) / GROUP_SIZE * GROUP_SIZE;
rest_len = GROUP_SIZE - current_len % GROUP_SIZE;
if(rest_len <= VAR_INPUT_LEN_SIZE)
{
dest_len += GROUP_SIZE;
memset(read_buf + BUF_SIZE, 0, GROUP_SIZE);
times++;
}
buf[current_len] = 0x80;
*(unsigned long long *)(buf + dest_len - VAR_INPUT_LEN_SIZE) = (unsigned long long)src_len * BITS_PER_BYTE;
return times;
}
/*
* transform: 轉換分組
*/
static void transform(unsigned char sub_group[SUBGROUPS_PER_GROUP][SUBGROUP_SIZE], unsigned int * state)
{
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;
}
Makefile:
all: md54file
md54file: main.c md54file.c
gcc $^ -o $@ -g -lm