MD5算法是Hash算法的一種,叫作訊息摘要演算法。所謂摘要,從字面意思理解,是指內容的大概。在MD5算法中,這個摘要是指將任意數據映射成一個128位長的摘要信息。而且其是不可逆的,即從摘要信息沒法反向推演中原文,在演算過程當中,原文的內容也是有丟失的。算法
由於MD5算法最終生成的是一個128位長的數據,從原理上說,有2^128種可能,這是一個很是巨大的數據,約等於3.4乘10的38次方,雖然這個是個天文數字,可是世界上能夠進行加密的數據原則上說是無限的,所以是可能存在不一樣的內容通過MD5加密後獲得一樣的摘要信息,但這個碰中的機率很是小。數據庫
MD5經常使用在密碼加密中,通常爲了保證用戶密碼的安全,在數據庫中存儲的都是用戶的密碼通過MD5加密後的值,在客戶端用戶輸入密碼後,也會使用MD5進行加密,這樣即便用戶的網絡被竊聽,竊聽者依然沒法拿到用戶的原始密碼,而且即便用戶數據庫被盜,沒有存儲明文的密碼對用戶來講也多了一層安全保障。安全
MD5簽名技術還經常使用於防止信息的篡改。使用MD5能夠對信息進行簽名,接收者拿到信息後只要從新計算簽名和原始簽名進行對比,便可知道數據信息是否中途被篡改了。網絡
MD5算法大體分爲4步完成:app
第1步:進行數據填充整理函數
這一步是對要加密的數據進行填充和整理,將要加密的二進制數據對512取模,獲得的結果若是不夠448位,則進行補足,補足的方式是第1位填充1,後面所有填充0。加密
第2步:記錄數據長度spa
通過第一步整理完成後的數據的位數能夠表示爲N*512+448,再向其後追加64位用來存儲數據的長度,好比數據的長度爲16字節,則用10000來填充後64位。這一步作完後,數據的位數將變成(N+1)*512。code
第3步:以標準的幻數做爲輸入對象
MD5的實現須要每512個字節進行一次處理,後一次處理的輸入爲前一次處理的輸出,所以,在循環處理開始以前,須要拿4個標準數做爲輸入,它們分別是:
unsigned int A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476;
第4步:進行N輪循環處理,將最後的結果輸出
這一步重要的是每一輪的處理算法,每一輪處理也要循環64次,這64次循環被分爲4各組,每16次循環爲一組,每組循環使用不一樣的邏輯處理函數,處理完成後,將輸出做爲輸入進入下一輪循環。
這裏演示的是每輪循環的核心算法:
首先進行3個函數的聲明:
//將大端字節序轉換爲小端字節序 void convertToLittleEndian(unsigned int *data, int len); //進行循環左移函數 void ROL(unsigned int *s, unsigned short cx); //MD5加密函數 void MD5(NSString *str);
MD5算法中處理的數據都是小端字節序的,而使用Objective-C處理的NSData對象的字節序是大端字節序,所以咱們須要作一下轉換。函數實現以下:
void convertToLittleEndian(unsigned int *data, int len) { for (int index = 0; index < len; index ++) { *data = ((*data & 0xff000000) >> 24) | ((*data & 0x00ff0000) >> 8) | ((*data & 0x0000ff00) << 8) | ((*data & 0x000000ff) << 24); data ++; } }
在MD5中有須要對字節數據進行循環左移的操做,循環左移函數實現以下:
void ROL(unsigned int *s, unsigned short cx) { if (cx > 32)cx %= 32; *s = (*s << cx) | (*s >> (32 - cx)); return; }
下面是MD5函數的核心實現:
void MD5(NSString *str){ const void * bytes[str.length]; //字符串轉字節流 [str getBytes:bytes maxLength:str.length usedLength:nil encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, str.length) remainingRange:nil]; //使用NSData存儲 NSMutableData * data = [[NSMutableData alloc] initWithBytes:bytes length:str.length]; BOOL first = YES; //進行數據填充 if (data.length<56) { do { if (first) { int byte = 0b10000000; [data appendBytes:&byte length:1]; first = NO; }else{ int byte = 0b00000000; [data appendBytes:&byte length:1]; } } while (data.length<56); } int length = (int)str.length*8%((int)pow(2, 64)); [data appendBytes:&length length:8]; void * newBytes[64]; memcpy(newBytes, [data bytes], 64); //大小端轉換 convertToLittleEndian(newBytes, 64); NSData * newData = [NSData dataWithBytes:newBytes length:data.length]; NSMutableArray * subData = [NSMutableArray array]; //進行分組 for (int i = 0; i<16; i++) { [subData addObject: [newData subdataWithRange:NSMakeRange(i*4, 4)]]; } //初始輸入 unsigned int A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476; unsigned int a=A,b=B,c=C,d=D; unsigned int s[64] = { 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 }; unsigned int k[64] = { 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 }; //64次循環處理 for (int i = 0; i <= 64; i++) { if (i<64) { unsigned int f; unsigned int g; if (i<16) { f = (b&c)|((~b)&d); g = i; }else if(i<32) { f = (b&d)|((~d)&c); g = (5*i+1)%16; }else if(i<48){ f = b^c^d; g = (3*i+5)%16; }else{ f = c^((~d)|b); g = (7*i)%16; } unsigned int * temp = (unsigned int *) [subData[g] bytes]; unsigned int *tem = malloc(sizeof(unsigned int)); memcpy(tem, temp, 4); convertToLittleEndian(tem, 4); unsigned int res = (a+f+*tem+k[i]); ROL(&res,s[i]); unsigned int t = res+b; a = d; d = c; c = b; b = t; }else{ A = a+A; B = b+B; C = c+C; D = d+D; } } //大小端轉換 unsigned int * newA = malloc(sizeof(unsigned int)); memcpy(newA, &A, 4); NSLog(@"%0x",*newA); convertToLittleEndian(newA, 4); unsigned int * newB = malloc(sizeof(unsigned int)); memcpy(newB, &B, 4); convertToLittleEndian(newB, 4); unsigned int * newC = malloc(sizeof(unsigned int)); memcpy(newC, &C, 4); convertToLittleEndian(newC, 4); unsigned int * newD = malloc(sizeof(unsigned int)); memcpy(newD, &D, 4); convertToLittleEndian(newD, 4); NSLog(@"AAA:%0x %0x %0x %0x ",*newA,*newB,*newC,*newD); }