MD5的C实现及中间计算数据(学习记录 2020/1/8)

研二


MD5

今年的目标是要实现20个以上的标准,MD5是第一个。
MD5的相关标准我参考的是RFC1321,但RFC好像并不是真正意义上的标准文件,这个之后再去研究。
根据文档上对算法的描述,我编写出了如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define IN
#define OUT

#define LOGE printf
#define LOGD printf
#define LOGI printf

#define ROL(x, n) ((x << n) | ((unsigned int)x >> (32 - n)))

#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 FREE(x) {if (x) free(x); x = NULL;}

#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

#define Block_Process_1(a, b, c, d, x, s, ac) {        \
  (a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \
  (a) = ROL ((a), (s));                                \
  (a) += (b);                                          \
}

#define Block_Process_2(a, b, c, d, x, s, ac) {        \
  (a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \
  (a) = ROL ((a), (s));                                \
  (a) += (b);                                          \
}

#define Block_Process_3(a, b, c, d, x, s, ac) {        \
  (a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \
  (a) = ROL ((a), (s));                                \
  (a) += (b);                                          \
}

#define Block_Process_4(a, b, c, d, x, s, ac) {        \
  (a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \
  (a) = ROL ((a), (s));                                \
  (a) += (b);                                          \
}

unsigned int A = 0x67452301;
unsigned int B = 0xefcdab89;
unsigned int C = 0x98badcfe;
unsigned int D = 0x10325476;


void PrintByte(IN const char *Name, 
               IN unsigned char *Src, IN unsigned int SrcLen)
{
	int i;
	LOGD("%s:\n", Name);
	for (i = 0; i < SrcLen; i++) {
		LOGD("%02X", Src[i]);
	}
	LOGD("\nEND\n");
}

void i2c(IN unsigned int *input, IN unsigned int inputlen, 
		OUT unsigned char *output)
{
	int i, j;
	for (i = j = 0; j < inputlen; j += 4, i++) {
		output[j    ] = (input[i] >>  0) & 0xFF;
		output[j + 1] = (input[i] >>  8) & 0xFF;
		output[j + 2] = (input[i] >> 16) & 0xFF;
		output[j + 3] = (input[i] >> 24) & 0xFF;
	}
}

void c2i(IN unsigned char *input, IN unsigned int inputLen,
		OUT unsigned int *output) 
{
	int i, j;
	for (i = j = 0; i < inputLen; i += 4, j++) {
		output[j] = (((unsigned int)input[i    ]      ) |
				     ((unsigned int)input[i + 1] <<  8) |
				     ((unsigned int)input[i + 2] << 16) |
				     ((unsigned int)input[i + 3] << 24));
	}
}

void Padding(IN unsigned char *Src, IN unsigned int SrcLen, 
			OUT unsigned char *Out, OUT unsigned int *OutLen)
{
	unsigned int KLen = ((SrcLen & 0x3F) < 56 ? 55 : 119) - (SrcLen & 0x3F);
	unsigned char Length_In_Byte[8] = {0};
	unsigned int SrcBitLen = SrcLen << 3;

	i2c(&SrcBitLen, 1, Length_In_Byte);

	memcpy(Out, Src, SrcLen);
	memset(Out + SrcLen, 0x80, 1);
	memset(Out + SrcLen + 1, 0x00, KLen);
	memcpy(Out + SrcLen + 1 + KLen, Length_In_Byte, 8);

	*OutLen = SrcLen + 9 + KLen;
}

void Block_Process(IN unsigned int *M, IN unsigned int MLen)
{
	int i, j;
	unsigned int X[16] = {0};
	unsigned int AA, BB, CC, DD;

	for (i = 0; i < MLen / 16; i++) {
		for (j = 0; j < 16; j++)
			X[j] = M[i * 16 + j];

		AA = A; BB = B; CC = C; DD = D;

		/* Round 1 */
		Block_Process_1(A, B, C, D, X[ 0], S11, 0xd76aa478); /*  1 */
		Block_Process_1(D, A, B, C, X[ 1], S12, 0xe8c7b756); /*  2 */
		Block_Process_1(C, D, A, B, X[ 2], S13, 0x242070db); /*  3 */
		Block_Process_1(B, C, D, A, X[ 3], S14, 0xc1bdceee); /*  4 */
		Block_Process_1(A, B, C, D, X[ 4], S11, 0xf57c0faf); /*  5 */
		Block_Process_1(D, A, B, C, X[ 5], S12, 0x4787c62a); /*  6 */
		Block_Process_1(C, D, A, B, X[ 6], S13, 0xa8304613); /*  7 */
		Block_Process_1(B, C, D, A, X[ 7], S14, 0xfd469501); /*  8 */
		Block_Process_1(A, B, C, D, X[ 8], S11, 0x698098d8); /*  9 */
		Block_Process_1(D, A, B, C, X[ 9], S12, 0x8b44f7af); /* 10 */
		Block_Process_1(C, D, A, B, X[10], S13, 0xffff5bb1); /* 11 */
		Block_Process_1(B, C, D, A, X[11], S14, 0x895cd7be); /* 12 */
		Block_Process_1(A, B, C, D, X[12], S11, 0x6b901122); /* 13 */
		Block_Process_1(D, A, B, C, X[13], S12, 0xfd987193); /* 14 */
		Block_Process_1(C, D, A, B, X[14], S13, 0xa679438e); /* 15 */
		Block_Process_1(B, C, D, A, X[15], S14, 0x49b40821); /* 16 */

		/* Round 2 */
		Block_Process_2(A, B, C, D, X[ 1], S21, 0xf61e2562); /* 17 */
		Block_Process_2(D, A, B, C, X[ 6], S22, 0xc040b340); /* 18 */
		Block_Process_2(C, D, A, B, X[11], S23, 0x265e5a51); /* 19 */
		Block_Process_2(B, C, D, A, X[ 0], S24, 0xe9b6c7aa); /* 20 */
		Block_Process_2(A, B, C, D, X[ 5], S21, 0xd62f105d); /* 21 */
		Block_Process_2(D, A, B, C, X[10], S22,  0x2441453); /* 22 */
		Block_Process_2(C, D, A, B, X[15], S23, 0xd8a1e681); /* 23 */
		Block_Process_2(B, C, D, A, X[ 4], S24, 0xe7d3fbc8); /* 24 */
		Block_Process_2(A, B, C, D, X[ 9], S21, 0x21e1cde6); /* 25 */
		Block_Process_2(D, A, B, C, X[14], S22, 0xc33707d6); /* 26 */
		Block_Process_2(C, D, A, B, X[ 3], S23, 0xf4d50d87); /* 27 */
		Block_Process_2(B, C, D, A, X[ 8], S24, 0x455a14ed); /* 28 */
		Block_Process_2(A, B, C, D, X[13], S21, 0xa9e3e905); /* 29 */
		Block_Process_2(D, A, B, C, X[ 2], S22, 0xfcefa3f8); /* 30 */
		Block_Process_2(C, D, A, B, X[ 7], S23, 0x676f02d9); /* 31 */
		Block_Process_2(B, C, D, A, X[12], S24, 0x8d2a4c8a); /* 32 */

		/* Round 3 */
		Block_Process_3(A, B, C, D, X[ 5], S31, 0xfffa3942); /* 33 */
		Block_Process_3(D, A, B, C, X[ 8], S32, 0x8771f681); /* 34 */
		Block_Process_3(C, D, A, B, X[11], S33, 0x6d9d6122); /* 35 */
		Block_Process_3(B, C, D, A, X[14], S34, 0xfde5380c); /* 36 */
		Block_Process_3(A, B, C, D, X[ 1], S31, 0xa4beea44); /* 37 */
		Block_Process_3(D, A, B, C, X[ 4], S32, 0x4bdecfa9); /* 38 */
		Block_Process_3(C, D, A, B, X[ 7], S33, 0xf6bb4b60); /* 39 */
		Block_Process_3(B, C, D, A, X[10], S34, 0xbebfbc70); /* 40 */
		Block_Process_3(A, B, C, D, X[13], S31, 0x289b7ec6); /* 41 */
		Block_Process_3(D, A, B, C, X[ 0], S32, 0xeaa127fa); /* 42 */
		Block_Process_3(C, D, A, B, X[ 3], S33, 0xd4ef3085); /* 43 */
		Block_Process_3(B, C, D, A, X[ 6], S34,  0x4881d05); /* 44 */
		Block_Process_3(A, B, C, D, X[ 9], S31, 0xd9d4d039); /* 45 */
		Block_Process_3(D, A, B, C, X[12], S32, 0xe6db99e5); /* 46 */
		Block_Process_3(C, D, A, B, X[15], S33, 0x1fa27cf8); /* 47 */
		Block_Process_3(B, C, D, A, X[ 2], S34, 0xc4ac5665); /* 48 */

		/* Round 4 */
		Block_Process_4(A, B, C, D, X[ 0], S41, 0xf4292244); /* 49 */
		Block_Process_4(D, A, B, C, X[ 7], S42, 0x432aff97); /* 50 */
		Block_Process_4(C, D, A, B, X[14], S43, 0xab9423a7); /* 51 */
		Block_Process_4(B, C, D, A, X[ 5], S44, 0xfc93a039); /* 52 */
		Block_Process_4(A, B, C, D, X[12], S41, 0x655b59c3); /* 53 */
		Block_Process_4(D, A, B, C, X[ 3], S42, 0x8f0ccc92); /* 54 */
		Block_Process_4(C, D, A, B, X[10], S43, 0xffeff47d); /* 55 */
		Block_Process_4(B, C, D, A, X[ 1], S44, 0x85845dd1); /* 56 */
		Block_Process_4(A, B, C, D, X[ 8], S41, 0x6fa87e4f); /* 57 */
		Block_Process_4(D, A, B, C, X[15], S42, 0xfe2ce6e0); /* 58 */
		Block_Process_4(C, D, A, B, X[ 6], S43, 0xa3014314); /* 59 */
		Block_Process_4(B, C, D, A, X[13], S44, 0x4e0811a1); /* 60 */
		Block_Process_4(A, B, C, D, X[ 4], S41, 0xf7537e82); /* 61 */
		Block_Process_4(D, A, B, C, X[11], S42, 0xbd3af235); /* 62 */
		Block_Process_4(C, D, A, B, X[ 2], S43, 0x2ad7d2bb); /* 63 */
		Block_Process_4(B, C, D, A, X[ 9], S44, 0xeb86d391); /* 64 */

		A += AA; B += BB; C += CC; D += DD;
	}
}

void MD5(IN unsigned char *Msg, IN unsigned int MsgLen,
		OUT unsigned char *Hash)
{
	int i;
	unsigned int PadMsgLen = 128;
	unsigned char *PadMsg = (unsigned char *)calloc(PadMsgLen, sizeof(char));
	unsigned int IntPadMsgLen = PadMsgLen / 4;
	unsigned int *IntPadMsg = (unsigned int *)calloc(IntPadMsgLen, sizeof(int));

	Padding(Msg, MsgLen, PadMsg, &PadMsgLen);

	c2i(PadMsg, PadMsgLen, IntPadMsg);
	Block_Process(IntPadMsg, IntPadMsgLen);

	i2c(&A, 1, Hash);
	i2c(&B, 1, Hash + 4);
	i2c(&C, 1, Hash + 8);
	i2c(&D, 1, Hash + 12);

	FREE(PadMsg); FREE(IntPadMsg);
}

int main(int argc, char *argv[])
{
	unsigned char Hash[16] = { 0 };

	MD5(argv[1], strlen(argv[1]), Hash);
	PrintByte("MD5", Hash, 16);
}

由于第一次写这种程序,很多地方有待改进。该程序中,我将所有代码都放到了一个文件中,没有使用init update以及final三段式的标准写法,因此不能接受过长的输入。而且由于没有采用循环update的形式,所以不得不动态使用malloc函数动态开辟内存空间,显得很蠢。
该RFC文档提供了可借鉴的代码,为之后写杂凑函数以及对称加密函数提供了很好的样板。
另外网上并没有找到MD5的过程数据供对照,因此我将RFC提供的代码的部分计算数据打印了出来供参考。

对abc进行杂凑:
block[0]: 80636261 /* 填充后的数据 */
block[1]: 00000000
block[2]: 00000000
block[3]: 00000000
block[4]: 00000000
block[5]: 00000000
block[6]: 00000000
block[7]: 00000000
block[8]: 00000000
block[9]: 00000000
block[10]: 00000000
block[11]: 00000000
block[12]: 00000000
block[13]: 00000000
block[14]: 00000018
block[15]: 00000000
Transform过程中A, B, C, D的值
a b c d
D6D117B4 EFCDAB89 98BADCFE 10325476
D6D117B4 EFCDAB89 98BADCFE 344A8432
D6D117B4 EFCDAB89 2F6FBD72 344A8432
D6D117B4 7AD956F2 2F6FBD72 344A8432
C73741EF 7AD956F2 2F6FBD72 344A8432
C73741EF 7AD956F2 2F6FBD72 8BAC3051
C73741EF 7AD956F2 207DC67B 8BAC3051
C73741EF 928D99F6 207DC67B 8BAC3051
854B3712 928D99F6 207DC67B 8BAC3051
854B3712 928D99F6 207DC67B 74E2F284
854B3712 928D99F6 3020401C 74E2F284
854B3712 5ED49596 3020401C 74E2F284
DDA9B9A6 5ED49596 3020401C 74E2F284
DDA9B9A6 5ED49596 3020401C A1051895
DDA9B9A6 5ED49596 E396856B A1051895
DDA9B9A6 72AFF2E0 E396856B A1051895

3E9E9126 72AFF2E0 E396856B A1051895
3E9E9126 72AFF2E0 E396856B 4A1D804E
3E9E9126 72AFF2E0 E25E1652 4A1D804E
3E9E9126 B5B204E4 E25E1652 4A1D804E
59A8FFDA B5B204E4 E25E1652 4A1D804E
59A8FFDA B5B204E4 E25E1652 6D002F1E
59A8FFDA B5B204E4 ABFC7920 6D002F1E
59A8FFDA 47092C07 ABFC7920 6D002F1E
B7F268CF 47092C07 ABFC7920 6D002F1E
B7F268CF 47092C07 ABFC7920 09388EFF
B7F268CF 47092C07 FE1623B1 09388EFF
B7F268CF 786ACB8F FE1623B1 09388EFF
790A77FB 786ACB8F FE1623B1 09388EFF
790A77FB 786ACB8F A62884AA 9F47E4F8
790A77FB 726342D3 A62884AA 9F47E4F8

B3707EBF 726342D3 A62884AA 9F47E4F8
B3707EBF 726342D3 A62884AA 60127B2E
B3707EBF 726342D3 8D212FF5 60127B2E
B3707EBF 3B0875C7 8D212FF5 60127B2E
21B117B9 3B0875C7 8D212FF5 60127B2E
21B117B9 3B0875C7 8D212FF5 6E7429D5
21B117B9 3B0875C7 3575227E 6E7429D5
21B117B9 5A2F5EA5 3575227E 6E7429D5
11DE1779 5A2F5EA5 3575227E 6E7429D5
11DE1779 5A2F5EA5 3575227E FADCAA38
11DE1779 5A2F5EA5 31C465CA FADCAA38
11DE1779 4C6124F4 31C465CA FADCAA38
7F2E507B 4C6124F4 31C465CA FADCAA38
7F2E507B 4C6124F4 31C465CA 99D9679D
7F2E507B 4C6124F4 8FAE6399 99D9679D
7F2E507B 7BEB9700 8FAE6399 99D9679D

7B201DF8 7BEB9700 8FAE6399 99D9679D
7B201DF8 7BEB9700 8FAE6399 F4E8E96E
7B201DF8 7BEB9700 B298CEFD F4E8E96E
7B201DF8 8BF025C4 B298CEFD F4E8E96E
06CC5E8A 8BF025C4 B298CEFD F4E8E96E
06CC5E8A 8BF025C4 B298CEFD 5B0D97AA
06CC5E8A 8BF025C4 7D632DD0 5B0D97AA
06CC5E8A 3BFA2C27 7D632DD0 5B0D97AA
7F81CC35 3BFA2C27 7D632DD0 5B0D97AA
7F81CC35 3BFA2C27 7D632DD0 094454AB
7F81CC35 3BFA2C27 4F9DBE3F 094454AB
7F81CC35 7327D604 4F9DBE3F 094454AB
310ADE8F 7327D604 4F9DBE3F 094454AB
310ADE8F 7327D604 4F9DBE3F 624D8CB2
310ADE8F 7327D604 E484B9D8 624D8CB2
310ADE8F C08226B3 E484B9D8 624D8CB2
杂凑结果:
900150983cd24fb0d6963f7d28e17f72

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值