Реализация алгоритма хеширования MD5 на Visual Studio 2019

Загрузить исходный код для Visual Stduio 2005 ЗДЕСЬ.

Алгоритм следующий.

1)Инициализируем MD буффер в функции md5_starts(). Буффер состоит из четырех констант, предназначенный для сбора хэша.


 void  md5_starts( md5_context *ctx )
    {
        ctx->total[ 0] = 0 ;
        ctx->total[ 1] = 0 ;

	//Инициализируем MD буффер
	//Буффер состоит из четырех констант,
	//предназначенный для сбора хэша.

        ctx->state[ 0] = 0x67452301 ;
        ctx->state[ 1] = 0xEFCDAB89 ;
        ctx->state[ 2] = 0x98BADCFE ;
        ctx->state[ 3] = 0x10325476 ;
    }

2)В исходную строку в конец дописывается единичный байт 0х80.

3)Далее в конец исходной строки дописываются 8 байт - длинна исходного сообщения.

4)Далее в функции md5_process() исходная строка по 4 байта копируется в массив uint32 X[ 16 ].

5)Определяем 4 логические функции в функции md5_process().

//Определяем 4 логические функции

#define  F(x,y,z) (z ^ (x & (y ^ z)))

...

#undef  F

#define  F(x,y,z) (y ^ (z & (x ^ y)))

...

#undef  F


#define  F(x,y,z) (x ^ y ^ z)

...

#undef  F


#define  F(x,y,z) (y ^ (x | ~z))

...

#undef  F

5)Затем внутри функции md5_process() происходят так называемые преобразования-раунды, которых всего будет 4. Каждый раунд состоит из 16 элементарных преобразований, которые в общем виде можно представить в виде:


#define  P(a,b,c,d,k,s,t)                                \
    {                                                       \
        a += F(b,c,d) + X[k] + t; a = S(a,s) + b;           \
    }


Эти 4 раунда по 16 элементарных преобразований происходят внутри определенных логических функций #define F (там где троеточие).

6)В конце функции md5_process() у нас есть результирующий хеш:


	ctx->state[ 0 ] += A;
        ctx->state[ 1 ] += B;
        ctx->state[ 2 ] += C;
        ctx->state[ 3 ] += D;

7)В конце функции md5_finish() результирующий хеш записывается в char массив digest:


	PUT_UINT32( ctx->state[ 0], digest,  0  );
        PUT_UINT32( ctx->state[ 1], digest,  4  );
        PUT_UINT32( ctx->state[ 2], digest,  8  );
        PUT_UINT32( ctx->state[ 3], digest, 12  );

В конце функции main() массив digest выводиться на экран. В завершение добавлю - PUT_UINT32 берет 4 int32 ложит в один массив последовательно, GET_UINT32 берет из последовательного массива по 4 байта (int32) и ложит в другой массив uint32 X[ 16 ].