天天看點

MD5加密原了解析及OC版原理實作

MD5加密原了解析及OC版原理實作

一、MD5算法基礎概念

      MD5算法是Hash算法的一種,叫做訊息摘要演算法。所謂摘要,從字面意思了解,是指内容的大概。在MD5算法中,這個摘要是指将任意資料映射成一個128位長的摘要資訊。并且其是不可逆的,即從摘要資訊無法反向推演中原文,在演算過程中,原文的内容也是有丢失的。

      因為MD5算法最終生成的是一個128位長的資料,從原理上說,有2^128種可能,這是一個非常巨大的資料,約等于3.4乘10的38次方,雖然這個是個天文數字,但是世界上可以進行加密的資料原則上說是無限的,是以是可能存在不同的内容經過MD5加密後得到同樣的摘要資訊,但這個碰中的機率非常小。

二、MD5的使用場景

      MD5常用在密碼加密中,一般為了保證使用者密碼的安全,在資料庫中存儲的都是使用者的密碼經過MD5加密後的值,在用戶端使用者輸入密碼後,也會使用MD5進行加密,這樣即使使用者的網絡被竊聽,竊聽者依然無法拿到使用者的原始密碼,并且即使使用者資料庫被盜,沒有存儲明文的密碼對使用者來說也多了一層安全保障。

      MD5簽名技術還常用于防止資訊的篡改。使用MD5可以對資訊進行簽名,接收者拿到資訊後隻要重新計算簽名和原始簽名進行對比,即可知道資料資訊是否中途被篡改了。

三、MD5算法原理

      MD5算法大緻分為4步完成:

第1步:進行資料填充整理

      這一步是對要加密的資料進行填充和整理,将要加密的二進制資料對512取模,得到的結果如果不夠448位,則進行補足,補足的方式是第1位填充1,後面全部填充0。

第2步:記錄資料長度

     經過第一步整理完成後的資料的位數可以表示為N*512+448,再向其後追加64位用來存儲資料的長度,比如資料的長度為16位元組,則用10000來填充後64位。這一步做完後,資料的位數将變成(N+1)*512。

第3步:以标準的幻數作為輸入

    MD5的實作需要每512個位元組進行一次處理,後一次處理的輸入為前一次處理的輸出,是以,在循環處理開始之前,需要拿4個标準數作為輸入,它們分别是:

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

第4步:進行N輪循環處理,将最後的結果輸出

    這一步重要的是每一輪的處理算法,每一輪處理也要循環64次,這64次循環被分為4各組,每16次循環為一組,每組循環使用不同的邏輯處理函數,處理完成後,将輸出作為輸入進入下一輪循環。

四、MD5核心算法的實作

   這裡示範的是每輪循環的核心算法:

首先進行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);
}