C_MD5/main.c

186 lines
8.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdio.h>
#include <stdlib.h>
// memcpy
#include <string.h>
// uint8_t, uint32_t
#include <stdint.h>
// размер чанка
#define CHUNK_SIZE 64
// функции раундов
#define funcF(x, y, z) ((x & y) | ((~x) & z))
#define funcG(x, y, z) ((x & z) | ((~z) & y))
#define funcH(x, y, z) (x ^ y ^ z)
#define funcI(x, y, z) (y ^ ((~z) | x))
// битовый сдвиг
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
void md5(uint8_t *data, size_t size, uint32_t *result)
{
// размеры сдвигов
uint32_t r[] = {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};
// таблица констант
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};
// инициализация переменных под результат
result[0] = 0x67452301;
result[1] = 0xefcdab89;
result[2] = 0x98badcfe;
result[3] = 0x10325476;
size_t bits_len = size * 8; // длина хешируемых данных в битах
int chunk_i; // счетчик цикла по чанкам
uint8_t chunk[CHUNK_SIZE]; // чанк (64 байта = 512 бит)
uint8_t sub_chunk[2][CHUNK_SIZE]; // доп. чанк для остатка данных (56 байт = 448 бит + 2 байта bits_len)
int sub_chunk_flag = 0; // флаг наличия доп. чанка, а так же помогает взять нужный чанк на копирование
int chunk_count = size / CHUNK_SIZE; // количество чанков
uint32_t *chunk_4b; // 32 битное представление элемента чанка для мат операций (64 байта в 16 элементах)
uint32_t a, b, c, d; // переменные для расчетов в раундах
uint32_t i; // счетчик цикла для раундов
uint32_t temp; // буфер для перестановки местами значений двух переменных
uint32_t f, g; // результат функции раунда и индекс в массиве чанка
// цикл по чанкам
for (chunk_i = 0; chunk_i <= chunk_count; chunk_i++)
{
// обнуляем чанк
memset(chunk, 0, CHUNK_SIZE);
// если индекс меньше кол-ва чанков - используется полный размер чанка
if (chunk_i < chunk_count)
{
// копируем данные в чанк
memcpy(chunk, data + (chunk_i * CHUNK_SIZE), CHUNK_SIZE);
} // if (chunk_i < chunk_count) then если индекс меньше кол-ва чанков
// иначе требуется сформировать по правилам (добавить бит и в конце дописать размер данных в битах)
else
{
// если флаг не установлен, производится подготовка доп чанка
if (sub_chunk_flag == 0)
{
// установка флага для единичной инициализации
sub_chunk_flag = 1;
// обнулим чанки
memset(sub_chunk, 0, CHUNK_SIZE * 2);
// скопируем данные в первый чанк
memcpy(sub_chunk, data + (chunk_i * CHUNK_SIZE), (size % CHUNK_SIZE));
// допишем в конец данных единичный бит
sub_chunk[0][size % CHUNK_SIZE] = 128;
// если остаток от деления размера данных на размер чанка позволяет записать байт с единичным битом и размер данных (в битах) 8 байт (16 бит)
if ((size % CHUNK_SIZE) <= 55)
{
// то используется только один доп чанк, скопируем размер данных (в битах)
memcpy(&sub_chunk[0][56], &bits_len, sizeof(bits_len));
} // if ((size % CHUNK_SIZE) <= 55) then
else
{
// иначе используется второй доп чанк
memcpy(&sub_chunk[1][56], &bits_len, sizeof(bits_len));
// отнимем единицу у счетчика - еще один заход на доп. чанк
chunk_i--;
} // if ((size % CHUNK_SIZE) <= 55) else
} // if (sub_chunk_flag == 0) если флаг не установлен, производится подготовка доп чанка
// копируется доп чанк в соответсвии с значением флага-1
memcpy(chunk, sub_chunk[sub_chunk_flag - 1], CHUNK_SIZE);
sub_chunk_flag++; // инкремент на случай следующей итерации со вторым доп чанком
} // if (chunk_i < chunk_count) else если индекс больше или равен кол-ву чанков
// 4 байтовый указатель на чанк (16 эл-тов)
chunk_4b = (uint32_t *)chunk;
// инициализируем переменные для расчетов
a = result[0];
b = result[1];
c = result[2];
d = result[3];
// цикл основных преобразований
for (i = 0; i < 64; i++)
{
// определяем раунд
switch (i / 16)
{
case 0:
f = funcF(b, c, d);
g = i;
break;
case 1:
f = funcG(b, c, d);
g = (5 * i + 1) % 16;
break;
case 2:
f = funcH(b, c, d);
g = (3 * i + 5) % 16;
break;
case 3:
f = funcI(b, c, d);
g = (7 * i) % 16;
break;
} // switch(i/16) определяем раунд
// преобразования
temp = d;
d = c;
c = b;
b += LEFTROTATE((a + f + k[i] + chunk_4b[g]), r[i]);
a = temp;
} // for(i) цикл основных преобразований
// после прохода чанка - модифицируем переменную результата
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
} // for(chunk_i) цикл по чанкам
} // void md5(uint8_t *data, size_t size, uint32_t *result)
int main(int argc, char *argv[])
{
char msg[] = "md5";
size_t len = sizeof(msg) - 1; // минус нуль-терминатор
// результат
uint32_t result[4];
// вызов хеш-функции
md5((uint8_t *)msg, len, result);
//вывод результата в формате little-endian
uint8_t *p;
p = (uint8_t *)&result[0];
printf("%2.2x%2.2x%2.2x%2.2x ", p[0], p[1], p[2], p[3]);
p = (uint8_t *)&result[1];
printf("%2.2x%2.2x%2.2x%2.2x ", p[0], p[1], p[2], p[3]);
p = (uint8_t *)&result[2];
printf("%2.2x%2.2x%2.2x%2.2x ", p[0], p[1], p[2], p[3]);
p = (uint8_t *)&result[3];
printf("%2.2x%2.2x%2.2x%2.2x\n", p[0], p[1], p[2], p[3]);
//"1111111111111111111111111111111111111111111111111111111111111111" = 46f04863 257ac804 0905ea00 02183d35
//"1" = c4ca4238 a0b92382 0dcc509a 6f75849b
//"md5" = 1bc29b36 f623ba82 aaf6724f d3b16718
return 0;
}