commit 843cbdcdf1d73a93f72504bafc6381244bf93f51 Author: Lisoveliy <1986developer@gmail.com> Date: Sat Jun 21 20:25:01 2025 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62fcaf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/settings.json +obj* +bin* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4806faf --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CC = clang +CFLAGS = -Wall -Wextra -pedantic -std=c17 -g +SRCS = src/main.c src/md5.c +OBJS = $(SRCS:src/%.c=obj/%.o) + +TARGET = bin/md5hash + +all: $(TARGET) + +$(TARGET): $(OBJS) + mkdir -p bin + $(CC) $(OBJS) -o $@ + +obj/%.o: src/%.c | obj + $(CC) $(CFLAGS) -c $< -o $@ + +obj: + mkdir -p obj + +clean: + rm -rf ./obj $(TARGET) + +.PHONY: clean \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..eca9af5 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# MD5 Hash Calculator + +Simple MD5 realization for small amounts of data written on pure C for Linux \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..f4c2f43 --- /dev/null +++ b/src/main.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#include "md5.h" + +void returnHash(uint8_t* digest); + +int main(int argc, char** argv){ + if(argc > 1) + { + char* argData = argv[1]; + FILE* sFile = fopen(argData, "rb"); + uint8_t output[16]; //128-bit buffer + + if(sFile == NULL){ + md5((uint8_t*) argData, strlen(argData), output); + } + else{ + //Prepare data for stream into md5 + fseek(sFile, 0, SEEK_END); + unsigned long fileSize = ftell(sFile); + rewind(sFile); + uint8_t *stream = (uint8_t*)malloc(fileSize); + if (!stream) { + fclose(sFile); + errno = -1; + perror("malloc() failed. Maybe file is too big?"); + return errno; + } + size_t readSize = fread(stream, 1, fileSize, sFile); + + fclose(sFile); + if (readSize != fileSize) { + free(stream); + errno = -2; + perror("Failed to read file. Maybe file is too big?"); + return errno; + } + + md5(stream, fileSize, output); + } + returnHash(output); + return 0; + } + errno = 1; + perror("There is no input for generate MD5 hash"); + return 1; +} + +void returnHash(uint8_t* digest){ + for (size_t i = 0; i < 16; i++) { + printf("%02x", digest[i]); + } +} diff --git a/src/md5.c b/src/md5.c new file mode 100644 index 0000000..e370798 --- /dev/null +++ b/src/md5.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +// Левое циклическое вращение (ROTATE LEFT) +#define LEFT_ROTATE(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// Константы для сдвигов +static const uint8_t s[] = { + 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 const uint32_t K[] = { + 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 +}; + +// Функции для раундов +#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))) + +void md5(const uint8_t *initial_msg, size_t initial_len, uint8_t *digest) { + // Инициализация буфера + uint32_t a0 = 0x67452301; + uint32_t b0 = 0xefcdab89; + uint32_t c0 = 0x98badcfe; + uint32_t d0 = 0x10325476; + + // Вычисление необходимой длины сообщения с дополнением + size_t new_len = (((initial_len + 8) / 64) + 1) * 64; + uint8_t *msg = (uint8_t*)malloc(new_len); + memcpy(msg, initial_msg, initial_len); + msg[initial_len] = 0x80; // Добавление бита "1" + + // Заполнение нулями + for (size_t i = initial_len + 1; i < new_len - 8; i++) { + msg[i] = 0; + } + + // Добавление длины сообщения в битах (little-endian) + uint64_t bit_len = (uint64_t)initial_len * 8; + memcpy(msg + new_len - 8, &bit_len, 8); + + // Обработка сообщения блоками по 64 байта + for (size_t offset = 0; offset < new_len; offset += 64) { + // Разбиение текущего блока на 16 слов + uint32_t M[16]; + for (size_t i = 0; i < 16; i++) { + M[i] = *(uint32_t*)(msg + offset + i * 4); + } + + // Инициализация рабочих переменных + uint32_t A = a0; + uint32_t B = b0; + uint32_t C = c0; + uint32_t D = d0; + + // Основной цикл (64 шага) + for (size_t i = 0; i < 64; i++) { + uint32_t F, g; + if (i < 16) { + F = F(B, C, D); + g = i; + } else if (i < 32) { + F = G(B, C, D); + g = (5 * i + 1) % 16; + } else if (i < 48) { + F = H(B, C, D); + g = (3 * i + 5) % 16; + } else { + F = I(B, C, D); + g = (7 * i) % 16; + } + + // Вычисление нового значения + F = F + A + K[i] + M[g]; + A = D; + D = C; + C = B; + B = B + LEFT_ROTATE(F, s[i]); + } + + // Обновление состояния + a0 += A; + b0 += B; + c0 += C; + d0 += D; + } + + free(msg); + + // Формирование итогового дайджеста в порядке little-endian + memcpy(digest, &a0, 4); + memcpy(digest + 4, &b0, 4); + memcpy(digest + 8, &c0, 4); + memcpy(digest + 12, &d0, 4); +} diff --git a/src/md5.h b/src/md5.h new file mode 100644 index 0000000..56ab112 --- /dev/null +++ b/src/md5.h @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +void md5(const uint8_t *initial_msg, size_t initial_len, uint8_t *digest);