C/C++ MD5算法的實(shí)現(xiàn)代碼
在逆向程序的時(shí)候,經(jīng)常會(huì)碰到加密的算法的問(wèn)題,前面分析UC的逆向工程師的面試題2的時(shí)候,發(fā)現(xiàn)使用了MD5的加密算法(MD5算法是自己實(shí)現(xiàn)的,不是使用的算法庫(kù)函數(shù))。尤其是在逆向分析網(wǎng)絡(luò)協(xié)議的時(shí)候,一般的程序使用的加密算法都是使用的庫(kù)函數(shù)提供的算法,有些程序使用的算法是自己實(shí)現(xiàn)的;相對(duì)來(lái)說(shuō)使用函數(shù)庫(kù)提供的加密函數(shù)的算法相對(duì)來(lái)說(shuō)比較好識(shí)別,因?yàn)橛兴惴ǔR?jiàn)函數(shù)在;但是如果不是使用的函數(shù)庫(kù)提供的加密的函數(shù)而是自己去實(shí)現(xiàn)某些算法話,識(shí)別起來(lái)有一定的難度,這就需要你對(duì)函數(shù)的加密原理以及流程還算法的特征比較熟悉才能很快識(shí)別出來(lái)。下面就將網(wǎng)上有關(guān)MD5算法一些知識(shí)整理一下,方面自己查閱。
md5簡(jiǎn)介
消息摘要算法第五版(英語(yǔ):Message-Digest Algorithm 5,縮寫(xiě)為MD5),是當(dāng)前計(jì)算機(jī)領(lǐng)域用于確保信息傳輸完整一致而廣泛使用的散列算法之一(又譯哈希算法、摘要算法等),主流編程語(yǔ)言普遍已有MD5的實(shí)現(xiàn)。將數(shù)據(jù) (如一段文字)運(yùn)算變?yōu)榱硪还潭ㄩL(zhǎng)度值,是散列算法的基礎(chǔ)原理,MD5的前身有MD2、MD3和MD4。MD5由MD4、MD3、MD2改進(jìn)而來(lái),主要增強(qiáng)算法復(fù)雜度和不可逆性。目前,MD5算法因其普遍、穩(wěn)定、快速的特點(diǎn),仍廣泛應(yīng)用于普通 數(shù)據(jù)的錯(cuò)誤檢查領(lǐng)域。例如在一些BitTorrent下載中,軟件將通過(guò)計(jì)算MD5檢驗(yàn)下載到的文件片段的完整性。MD5已經(jīng)廣泛使用在為文件傳輸提供一定的可靠性方面。例如,服務(wù)器預(yù)先提供一個(gè)MD5校驗(yàn)和,用戶下載完文件以后, 用MD5算法計(jì)算下載文件的MD5校驗(yàn)和,然后通過(guò)檢查這兩個(gè)校驗(yàn)和是否一致,就能判斷下載的文件是否出錯(cuò)。MD5是輸入不定長(zhǎng)度信息,輸出固定長(zhǎng)度128-bits的算法。經(jīng)過(guò)程序流程,生成四個(gè)32位數(shù)據(jù),最后聯(lián)合起來(lái)成為一個(gè) 128-bits散列?;痉绞綖?,求余、取余、調(diào)整長(zhǎng)度、與鏈接變量進(jìn)行循環(huán)運(yùn)算。得出結(jié)果。
md5算法描述
假設(shè)輸入信息(input message)的長(zhǎng)度為b(bit),我們想要產(chǎn)生它的報(bào)文摘要,在此處b為任意的非負(fù)整數(shù):b也可能為0,也不一定為8的整數(shù)倍,且可能是任意大的長(zhǎng)度。設(shè)該信息的比特流表示如下: M[0] M[1] M[2] ... M[b-1] 計(jì)算此信息的報(bào)文摘要需要如下5步:
1.補(bǔ)位
信息計(jì)算前先要進(jìn)行位補(bǔ)位,設(shè)補(bǔ)位后信息的長(zhǎng)度為L(zhǎng)EN(bit),則LEN%512 = 448(bit),即數(shù)據(jù)擴(kuò)展至 K * 512 + 448(bit)。即K * 64+56(byte),K為整數(shù)。補(bǔ)位操作始終要執(zhí)行,即使補(bǔ)位前信息的長(zhǎng)度對(duì)512求余的結(jié)果是448。具體補(bǔ)位操作:補(bǔ)一個(gè)1,然后補(bǔ)0至滿足上述要求。總共最少要補(bǔ)1bit,最多補(bǔ)512bit。
2.尾部加上信息長(zhǎng)度
將輸入信息的原始長(zhǎng)度b(bit)表示成一個(gè)64-bit的數(shù)字,把它添加到上一步的結(jié)果后面(在32位的機(jī)器上,這64位將用2個(gè)字來(lái)表示并且低位在前)。當(dāng)遇到b大于2^64這種極少的情況時(shí),b的高位被截去,僅使用b的低64位。經(jīng)過(guò)上面兩步,數(shù)據(jù)就被填補(bǔ)成長(zhǎng)度為512(bit)的倍數(shù)。也就是說(shuō),此時(shí)的數(shù)據(jù)長(zhǎng)度是16個(gè)字(32byte)的整數(shù)倍。此時(shí)的數(shù)據(jù)表示為: M[0 ... N-1] 其中的N是16的倍數(shù)。
3.初始化緩存區(qū)
用一個(gè)四個(gè)字的緩沖器(A,B,C,D)來(lái)計(jì)算報(bào)文摘要,A,B,C,D分別是32位的寄存器,初始化使用的是十六進(jìn)制表示的數(shù)字,注意低字節(jié)在前: word A: 01 23 45 67 word B: 89 ab cd ef word C: fe dc ba 98 word D: 76 54 32 10
4.轉(zhuǎn)換
首先定義4個(gè)輔助函數(shù),每個(gè)函數(shù)的輸入是三個(gè)32位的字,輸出是一個(gè)32位的字: F(X,Y,Z) = XY v not(X) Z G(X,Y,Z) = XZ v Y not(Z) H(X,Y,Z) = X xor Y xor Z I(X,Y,Z) = Y xor (X v not(Z))
FF(a,b,c,d,Mj,s,ti)表示 a = b + ((a + F(b,c,d) + Mj + ti) << s) GG(a,b,c,d,Mj,s,ti)表示 a = b + ((a + G(b,c,d) + Mj + ti) << s) HH(a,b,c,d,Mj,s,ti)表示 a = b + ((a + H(b,c,d) + Mj + ti) << s) Ⅱ(a,b,c,d,Mj,s,ti)表示 a = b + ((a + I(b,c,d) + Mj + ti) << s)
這四輪(64步)是:
第一輪
FF(a,b,c,d,M0,7,0xd76aa478) FF(d,a,b,c,M1,12,0xe8c7b756) FF(c,d,a,b,M2,17,0x242070db) FF(b,c,d,a,M3,22,0xc1bdceee) FF(a,b,c,d,M4,7,0xf57c0faf) FF(d,a,b,c,M5,12,0x4787c62a) FF(c,d,a,b,M6,17,0xa8304613) FF(b,c,d,a,M7,22,0xfd469501) FF(a,b,c,d,M8,7,0x698098d8) FF(d,a,b,c,M9,12,0x8b44f7af) FF(c,d,a,b,M10,17,0xffff5bb1) FF(b,c,d,a,M11,22,0x895cd7be) FF(a,b,c,d,M12,7,0x6b901122) FF(d,a,b,c,M13,12,0xfd987193) FF(c,d,a,b,M14,17,0xa679438e) FF(b,c,d,a,M15,22,0x49b40821)
第二輪
GG(a,b,c,d,M1,5,0xf61e2562) GG(d,a,b,c,M6,9,0xc040b340) GG(c,d,a,b,M11,14,0x265e5a51) GG(b,c,d,a,M0,20,0xe9b6c7aa) GG(a,b,c,d,M5,5,0xd62f105d) GG(d,a,b,c,M10,9,0x02441453) GG(c,d,a,b,M15,14,0xd8a1e681) GG(b,c,d,a,M4,20,0xe7d3fbc8) GG(a,b,c,d,M9,5,0x21e1cde6) GG(d,a,b,c,M14,9,0xc33707d6) GG(c,d,a,b,M3,14,0xf4d50d87) GG(b,c,d,a,M8,20,0x455a14ed) GG(a,b,c,d,M13,5,0xa9e3e905) GG(d,a,b,c,M2,9,0xfcefa3f8) GG(c,d,a,b,M7,14,0x676f02d9) GG(b,c,d,a,M12,20,0x8d2a4c8a)
第三輪
HH(a,b,c,d,M5,4,0xfffa3942) HH(d,a,b,c,M8,11,0x8771f681) HH(c,d,a,b,M11,16,0x6d9d6122) HH(b,c,d,a,M14,23,0xfde5380c) HH(a,b,c,d,M1,4,0xa4beea44) HH(d,a,b,c,M4,11,0x4bdecfa9) HH(c,d,a,b,M7,16,0xf6bb4b60) HH(b,c,d,a,M10,23,0xbebfbc70) HH(a,b,c,d,M13,4,0x289b7ec6) HH(d,a,b,c,M0,11,0xeaa127fa) HH(c,d,a,b,M3,16,0xd4ef3085) HH(b,c,d,a,M6,23,0x04881d05) HH(a,b,c,d,M9,4,0xd9d4d039) HH(d,a,b,c,M12,11,0xe6db99e5) HH(c,d,a,b,M15,16,0x1fa27cf8) HH(b,c,d,a,M2,23,0xc4ac5665)
第四輪
Ⅱ(a,b,c,d,M0,6,0xf4292244) Ⅱ(d,a,b,c,M7,10,0x432aff97) Ⅱ(c,d,a,b,M14,15,0xab9423a7) Ⅱ(b,c,d,a,M5,21,0xfc93a039) Ⅱ(a,b,c,d,M12,6,0x655b59c3) Ⅱ(d,a,b,c,M3,10,0x8f0ccc92) Ⅱ(c,d,a,b,M10,15,0xffeff47d) Ⅱ(b,c,d,a,M1,21,0x85845dd1) Ⅱ(a,b,c,d,M8,6,0x6fa87e4f) Ⅱ(d,a,b,c,M15,10,0xfe2ce6e0) Ⅱ(c,d,a,b,M6,15,0xa3014314) Ⅱ(b,c,d,a,M13,21,0x4e0811a1) Ⅱ(a,b,c,d,M4,6,0xf7537e82) Ⅱ(d,a,b,c,M11,10,0xbd3af235) Ⅱ(c,d,a,b,M2,15,0x2ad7d2bb) Ⅱ(b,c,d,a,M9,21,0xeb86d391)
下面是MD5算法的具體的實(shí)現(xiàn)
MD5算法的頭文件Md5.h:
#ifndef MD5_H #define MD5_H typedef struct { unsigned int count[2]; unsigned int state[4]; unsigned char buffer[64]; }MD5_CTX; #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 ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) #define FF(a,b,c,d,x,s,ac) { \ a += F(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define GG(a,b,c,d,x,s,ac) { \ a += G(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define HH(a,b,c,d,x,s,ac) { \ a += H(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define II(a,b,c,d,x,s,ac) { \ a += I(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); void MD5Final(MD5_CTX *context, unsigned char digest[16]); void MD5Transform(unsigned int state[4], unsigned char block[64]); void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); #endif
MD5算法的實(shí)現(xiàn)文件Md5.cpp:
unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //在逆向代碼的時(shí)候,需要關(guān)注下面的特征值 void MD5Init(MD5_CTX *context) { context->count[0] = 0; context->count[1] = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; } void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) { unsigned int i = 0, index = 0, partlen = 0; index = (context->count[0] >> 3) & 0x3F; partlen = 64 - index; context->count[0] += inputlen << 3; if (context->count[0] < (inputlen << 3)) context->count[1]++; context->count[1] += inputlen >> 29; if (inputlen >= partlen) { memcpy(&context->buffer[index], input, partlen); MD5Transform(context->state, context->buffer); for (i = partlen; i + 64 <= inputlen; i += 64) MD5Transform(context->state, &input[i]); index = 0; } else { i = 0; } memcpy(&context->buffer[index], &input[i], inputlen - i); } void MD5Final(MD5_CTX *context, unsigned char digest[16]) { unsigned int index = 0, padlen = 0; unsigned char bits[8]; index = (context->count[0] >> 3) & 0x3F; padlen = (index < 56) ? (56 - index) : (120 - index); MD5Encode(bits, context->count, 8); MD5Update(context, PADDING, padlen); MD5Update(context, bits, 8); MD5Encode(digest, context->state, 16); } void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[j] = input[i] & 0xFF; output[j + 1] = (input[i] >> 8) & 0xFF; output[j + 2] = (input[i] >> 16) & 0xFF; output[j + 3] = (input[i] >> 24) & 0xFF; i++; j += 4; } } void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[i] = (input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24); i++; j += 4; } } void MD5Transform(unsigned int state[4], unsigned char block[64]) { unsigned int a = state[0]; unsigned int b = state[1]; unsigned int c = state[2]; unsigned int d = state[3]; unsigned int x[64]; MD5Decode(x, block, 64); FF(a, b, c, d, x[0], 7, 0xd76aa478); FF(d, a, b, c, x[1], 12, 0xe8c7b756); FF(c, d, a, b, x[2], 17, 0x242070db); FF(b, c, d, a, x[3], 22, 0xc1bdceee); FF(a, b, c, d, x[4], 7, 0xf57c0faf); FF(d, a, b, c, x[5], 12, 0x4787c62a); FF(c, d, a, b, x[6], 17, 0xa8304613); FF(b, c, d, a, x[7], 22, 0xfd469501); FF(a, b, c, d, x[8], 7, 0x698098d8); FF(d, a, b, c, x[9], 12, 0x8b44f7af); FF(c, d, a, b, x[10], 17, 0xffff5bb1); FF(b, c, d, a, x[11], 22, 0x895cd7be); FF(a, b, c, d, x[12], 7, 0x6b901122); FF(d, a, b, c, x[13], 12, 0xfd987193); FF(c, d, a, b, x[14], 17, 0xa679438e); FF(b, c, d, a, x[15], 22, 0x49b40821); GG(a, b, c, d, x[1], 5, 0xf61e2562); GG(d, a, b, c, x[6], 9, 0xc040b340); GG(c, d, a, b, x[11], 14, 0x265e5a51); GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); GG(a, b, c, d, x[5], 5, 0xd62f105d); GG(d, a, b, c, x[10], 9, 0x2441453); GG(c, d, a, b, x[15], 14, 0xd8a1e681); GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); GG(a, b, c, d, x[9], 5, 0x21e1cde6); GG(d, a, b, c, x[14], 9, 0xc33707d6); GG(c, d, a, b, x[3], 14, 0xf4d50d87); GG(b, c, d, a, x[8], 20, 0x455a14ed); GG(a, b, c, d, x[13], 5, 0xa9e3e905); GG(d, a, b, c, x[2], 9, 0xfcefa3f8); GG(c, d, a, b, x[7], 14, 0x676f02d9); GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); HH(a, b, c, d, x[5], 4, 0xfffa3942); HH(d, a, b, c, x[8], 11, 0x8771f681); HH(c, d, a, b, x[11], 16, 0x6d9d6122); HH(b, c, d, a, x[14], 23, 0xfde5380c); HH(a, b, c, d, x[1], 4, 0xa4beea44); HH(d, a, b, c, x[4], 11, 0x4bdecfa9); HH(c, d, a, b, x[7], 16, 0xf6bb4b60); HH(b, c, d, a, x[10], 23, 0xbebfbc70); HH(a, b, c, d, x[13], 4, 0x289b7ec6); HH(d, a, b, c, x[0], 11, 0xeaa127fa); HH(c, d, a, b, x[3], 16, 0xd4ef3085); HH(b, c, d, a, x[6], 23, 0x4881d05); HH(a, b, c, d, x[9], 4, 0xd9d4d039); HH(d, a, b, c, x[12], 11, 0xe6db99e5); HH(c, d, a, b, x[15], 16, 0x1fa27cf8); HH(b, c, d, a, x[2], 23, 0xc4ac5665); II(a, b, c, d, x[0], 6, 0xf4292244); II(d, a, b, c, x[7], 10, 0x432aff97); II(c, d, a, b, x[14], 15, 0xab9423a7); II(b, c, d, a, x[5], 21, 0xfc93a039); II(a, b, c, d, x[12], 6, 0x655b59c3); II(d, a, b, c, x[3], 10, 0x8f0ccc92); II(c, d, a, b, x[10], 15, 0xffeff47d); II(b, c, d, a, x[1], 21, 0x85845dd1); II(a, b, c, d, x[8], 6, 0x6fa87e4f); II(d, a, b, c, x[15], 10, 0xfe2ce6e0); II(c, d, a, b, x[6], 15, 0xa3014314); II(b, c, d, a, x[13], 21, 0x4e0811a1); II(a, b, c, d, x[4], 6, 0xf7537e82); II(d, a, b, c, x[11], 10, 0xbd3af235); II(c, d, a, b, x[2], 15, 0x2ad7d2bb); II(b, c, d, a, x[9], 21, 0xeb86d391); state[0] += a; state[1] += b; state[2] += c; state[3] += d; }
MD5算法的調(diào)用測(cè)試:
int _tmain(int argc, _TCHAR* argv[]) { int i; unsigned char encrypt[] = "admin";//21232f297a57a5a743894a0e4a801fc3 unsigned char decrypt[16]; MD5_CTX md5; MD5Init(&md5); MD5Update(&md5, encrypt, strlen((char *)encrypt)); MD5Final(&md5, decrypt); //Md5加密后的32位結(jié)果 printf("加密前:%s\n加密后16位:", encrypt); for (i = 4; i<12; i++) { printf("%02x", decrypt[i]); } //Md5加密后的32位結(jié)果 printf("\n加密前:%s\n加密后32位:", encrypt); for (i = 0; i<16; i++) { printf("%02x", decrypt[i]); } getchar(); return 0; }
上面的代碼工程的下載地址:Md5Demo201707.zip
破解MD5加密的網(wǎng)址:http://www.cmd5.com/
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)線索二叉樹(shù)的定義與遍歷示例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)線索二叉樹(shù)的定義與遍歷,結(jié)合具體實(shí)例形式分析了基于C語(yǔ)言的線索二叉樹(shù)定義及遍歷操作相關(guān)實(shí)現(xiàn)技巧與注意事項(xiàng),需要的朋友可以參考下2017-06-06C語(yǔ)言編程計(jì)算信噪比SNR理解學(xué)習(xí)
這篇文章主要介紹了C語(yǔ)言編程信噪比SNR計(jì)算的理解學(xué)習(xí),信噪比,英文名稱(chēng)叫做SNR或S/N(SIGNAL-NOISE RATIO)。是指一個(gè)電子設(shè)備或者電子系統(tǒng)中信號(hào)與噪聲的比例2021-10-10位運(yùn)算實(shí)現(xiàn)十進(jìn)制轉(zhuǎn)換為二進(jìn)制
這篇文章主要介紹了位運(yùn)算實(shí)現(xiàn)十進(jìn)制轉(zhuǎn)換為二進(jìn)制的相關(guān)資料,需要的朋友可以參考下2015-03-03使用MinGW使Windows通過(guò)gcc實(shí)現(xiàn)C或C++程序本地編譯執(zhí)行的方法
這篇文章主要介紹了使用MinGW使Windows通過(guò)gcc實(shí)現(xiàn)C或C++程序本地編譯執(zhí)行的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放的方法
當(dāng)我們開(kāi)發(fā)Windows應(yīng)用程序時(shí),通常會(huì)涉及到使用資源(Resource)的情況。資源可以包括圖標(biāo)、位圖、字符串等,它們以二進(jìn)制形式嵌入到可執(zhí)行文件中,這篇文章主要介紹了C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放,需要的朋友可以參考下2023-12-12C語(yǔ)言從txt文件中逐行讀入數(shù)據(jù)存到數(shù)組中的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇C語(yǔ)言從txt文件中逐行讀入數(shù)據(jù)存到數(shù)組中的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12C++中與輸入相關(guān)的istream類(lèi)成員函數(shù)簡(jiǎn)介
這篇文章主要介紹了C++中與輸入相關(guān)的istream類(lèi)成員函數(shù)簡(jiǎn)介,包括eof函數(shù)和peek函數(shù)以及putback函數(shù)還有ignore函數(shù),需要的朋友可以參考下2015-09-09