diff --git a/main.c b/main.c new file mode 100644 index 0000000..18ca5c4 --- /dev/null +++ b/main.c @@ -0,0 +1,185 @@ +#include +#include + +// memcpy +#include +// uint8_t, uint32_t +#include + +// размер чанка +#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; +}