APP安全機制(四)—— MD5加密

版本記錄

版本號 時間
V1.0 2017.08.19

前言

在這個信息爆炸的年代,特別是一些敏感的行業(yè),比如金融業(yè)和銀行卡相關(guān)等等,這都對app的安全機制有更高的需求,很多大公司都有安全 部門,用于檢測自己產(chǎn)品的安全性,但是及時是這樣,安全問題仍然被不斷曝出,接下來幾篇我們主要說一下app的安全機制。感興趣的看我上面幾篇。
1. APP安全機制(一)—— 幾種和安全性有關(guān)的情況
2. APP安全機制(二)—— 使用Reveal查看任意APP的UI
3. APP安全機制(三)—— Base64加密

MD5基本了解

下面很大一部分內(nèi)容來自百度百科

MD5Message - Digest Algorithm 5(信息-摘要算法5),用于確保信息傳輸完整一致。是計算機廣泛使用的雜湊算法之一(又譯摘要算法、哈希算法),主流編程語言普遍已有MD5實現(xiàn)。將數(shù)據(jù)(如漢字)運算為另一固定長度值,是雜湊算法的基礎(chǔ)原理,MD5的前身有MD2MD3MD4

MD5主要特征

MD5主要有一以下特征。

  • 壓縮性:任意長度的數(shù)據(jù),算出的MD5值長度都是固定的。
  • 容易計算:從原數(shù)據(jù)計算出MD5值很容易。
  • 抗修改性:對原數(shù)據(jù)進(jìn)行任何改動,哪怕只修改1個字節(jié),所得到的MD5值都有很大區(qū)別。
  • 強抗碰撞:已知原數(shù)據(jù)和其MD5值,想找到一個具有相同MD5值的數(shù)據(jù)(即偽造數(shù)據(jù))是非常困難的。

MD5的作用是讓大容量信息在用數(shù)字簽名軟件簽署私人密鑰前被"壓縮"成一種保密的格式(就是把一個任意長度的字節(jié)串變換成一定長的十六進(jìn)制數(shù)字串)。除了MD5以外,其中比較有名的還有sha-1RIPEMD以及Haval等。

MD5應(yīng)用領(lǐng)域

下面看一下MD5主要應(yīng)用的方面。

  • 一致性驗證
    md5典型應(yīng)用是對一段信息(Message)產(chǎn)生信息摘要(Message-Digest),以防止被篡改。我們常常在某些軟件下載站點的某軟件信息中看到其MD5值,它的作用就在于我們可以在下載該軟件后,對下載回來的文件用專門的軟件(如Windows MD5 Check等)做一次MD5校驗,以確保我們獲得的文件與該站點提供的文件為同一文件。
    具體來說文件的MD5值就像是這個文件的“數(shù)字指紋”。每個文件的MD5值是不同的,如果任何人對文件做了任何改動,其MD5值也就是對應(yīng)的“數(shù)字指紋”就會發(fā)生變化。比如下載服務(wù)器針對一個文件預(yù)先提供一個MD5值,用戶下載完該文件后,用我這個算法重新計算下載文件的MD5值,通過比較這兩個值是否相同,就能判斷下載的文件是否出錯,或者說下載的文件是否被篡改了。
    利用MD5算法來進(jìn)行文件校驗的方案被大量應(yīng)用到軟件下載站、論壇數(shù)據(jù)庫、系統(tǒng)文件安全等方面。

  • 數(shù)字簽名
    MD5的典型應(yīng)用是對一段Message(字節(jié)串)產(chǎn)生fingerprint(指紋),以防止被“篡改”。舉個例子,你將一段話寫在一個叫 readme.txt文件中,并對這個readme.txt產(chǎn)生一個MD5的值并記錄在案,然后你可以傳播這個文件給別人,別人如果修改了文件中的任何內(nèi)容,你對這個文件重新計算MD5時就會發(fā)現(xiàn)(兩個MD5值不相同)。如果再有一個第三方的認(rèn)證機構(gòu),用MD5還可以防止文件作者的“抵賴”,這就是所謂的數(shù)字簽名應(yīng)用。

  • 安全訪問認(rèn)證
    MD5還廣泛用于操作系統(tǒng)的登陸認(rèn)證上,如Unix、各類BSD系統(tǒng)登錄密碼、數(shù)字簽名等諸多方面。


MD5算法原理

下面我們就看一下MD5的算法原理。

對MD5算法簡要的敘述可以為:MD5以512位分組來處理輸入的信息,且每一分組又被劃分為16個32位子分組,經(jīng)過了一系列的處理后,算法的輸出由四個32位分組組成,將這四個32位分組級聯(lián)后將生成一個128位散列值。

總體的流程圖如下所示,表示第i個分組,每次的運算都由前一輪的128位結(jié)果值和第i塊512bit值進(jìn)行運算。

流程圖

1. 填充

在MD5算法中,首先需要對信息進(jìn)行填充,使其位長對512求余的結(jié)果等于448,并且填充必須進(jìn)行,即使其位長對512求余的結(jié)果等于448。因此,信息的位長(Bits Length)將被擴展至N*512+448,N為一個非負(fù)整數(shù),N可以是零。

填充的方法如下:

  • 在信息的后面填充一個1和無數(shù)個0,直到滿足上面的條件時才停止用0對信息的填充。
  • 在這個結(jié)果后面附加一個以64位二進(jìn)制表示的填充前信息長度(單位為Bit),如果二進(jìn)制表示的填充前信息長度超過64位,則取低64位。
  • 經(jīng)過這兩步的處理,信息的位長 = N512 + 448 + 64= (N+1)512,即長度恰好是512的整數(shù)倍。這樣做的原因是為滿足后面處理中對信息長度的要求。

2. 初始化變量

初始的128位值為初試鏈接變量,這些參數(shù)用于第一輪的運算,以大端字節(jié)序來表示,他們分別為:A = 0x01234567,B = 0x89ABCDEF,C = 0xFEDCBA98,D = 0x76543210。(每一個變量給出的數(shù)值是高字節(jié)存于內(nèi)存低地址,低字節(jié)存于內(nèi)存高地址,即大端字節(jié)序。在程序中變量A、B、C、D的值分別為0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476

3. 處理分組數(shù)據(jù)

每一分組的算法流程如下:

第一分組需要將上面四個鏈接變量復(fù)制到另外四個變量中:A到a,B到b,C到c,D到d。從第二分組開始的變量為上一分組的運算結(jié)果,即A = a, B = b, C = c, D = d。主循環(huán)有四輪(MD4只有三輪),每輪循環(huán)都很相似。第一輪進(jìn)行16次操作。每次操作對a、b、c和d中的其中三個作一次非線性函數(shù)運算,然后將所得結(jié)果加上第四個變量,文本的一個子分組和一個常數(shù)。再將所得結(jié)果向左環(huán)移一個不定的數(shù),并加上a、b、c或d中之一。最后用該結(jié)果取代a、b、c或d中之一。

以下是每次操作中用到的四個非線性函數(shù)(每輪一個)。
F( X ,Y ,Z ) = ( X & Y ) | ( (~X) & Z )
G( X ,Y ,Z ) = ( X & Z ) | ( Y & (~Z) )
H( X ,Y ,Z ) =X ^ Y ^ Z
I( X ,Y ,Z ) =Y ^ ( X | (~Z) )

(&是與(And),|是或(Or),~是非(Not),^是異或(Xor))
這四個函數(shù)的說明:如果X、Y和Z的對應(yīng)位是獨立和均勻的,那么結(jié)果的每一位也應(yīng)是獨立和均勻的。

F是一個逐位運算的函數(shù)。即,如果X,那么Y,否則Z。函數(shù)H是逐位奇偶操作符。假設(shè)Mj表示消息的第j個子分組(從0到15),常數(shù)ti是4294967296*abs( sin(i) )的整數(shù)部分,i 取值從1到64,單位是弧度。(4294967296=232)

現(xiàn)定義:
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)
II(a ,b ,c ,d ,Mj ,s ,ti)操作為 a = b + ( (a + I(b,c,d) + Mj + ti) << s)
注意:“<<”表示循環(huán)左移位,不是左移位。

這四輪(共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 )
  • 第四輪
II(a ,b ,c ,d ,M0 ,6 ,0xf4292244 )
II(d ,a ,b ,c ,M7 ,10 ,0x432aff97 )
II(c ,d ,a ,b ,M14 ,15 ,0xab9423a7 )
II(b ,c ,d ,a ,M5 ,21 ,0xfc93a039 )
II(a ,b ,c ,d ,M12 ,6 ,0x655b59c3 )
II(d ,a ,b ,c ,M3 ,10 ,0x8f0ccc92 )
II(c ,d ,a ,b ,M10 ,15 ,0xffeff47d )
II(b ,c ,d ,a ,M1 ,21 ,0x85845dd1 )
II(a ,b ,c ,d ,M8 ,6 ,0x6fa87e4f )
II(d ,a ,b ,c ,M15 ,10 ,0xfe2ce6e0 )
II(c ,d ,a ,b ,M6 ,15 ,0xa3014314 )
II(b ,c ,d ,a ,M13 ,21 ,0x4e0811a1 )
II(a ,b ,c ,d ,M4 ,6 ,0xf7537e82 )
II(d ,a ,b ,c ,M11 ,10 ,0xbd3af235 )
II(c ,d ,a ,b ,M2 ,15 ,0x2ad7d2bb )
II(b ,c ,d ,a ,M9 ,21 ,0xeb86d391 )

所有這些完成之后,將a、b、c、d分別在原來基礎(chǔ)上再加上A、B、C、D。即 a = a + A,b = b + B,c = c + C,d = d + D,然后用下一分組數(shù)據(jù)繼續(xù)運行以上算法。

4. 輸出

最后的輸出是a、b、c和d的級聯(lián)。當(dāng)你按照我上面所說的方法實現(xiàn)MD5算法以后,你可以用以下幾個信息對你做出來的程序作一個簡單的測試,看看程序有沒有錯誤。

MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =
f29939a25efabaef3b87e2cbfe641315
MD5 ("8a683566bcc7801226b3d8b0cf35fd97") =cf2cb5c89c5e5eeebef4a76becddfcfd

MD5一個簡單實例

下面看一個MD5的實例。

現(xiàn)以字符串“jklmn”為例。

該字符串在內(nèi)存中表示為:6A 6B 6C 6D 6E(從左到右為低地址到高地址,后同),信息長度為40 bits, 即0x28。
對其填充,填充至448位,即56字節(jié)。結(jié)果為:

6A 6B 6C 6D 6E 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

剩下64位,即8字節(jié)填充填充前信息位長,按小端字節(jié)序填充剩下的8字節(jié),結(jié)果為:

6A 6B 6C 6D 6E 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 00 00 00 00 00 00 00

(64字節(jié),512 bits)

初始化A、B、C、D四個變量。
將這64字節(jié)填充后數(shù)據(jù)分成16個小組(程序中對應(yīng)為16個數(shù)組),即:

M0:6A 6B 6C 6D (這是內(nèi)存中的順序,按照小端字節(jié)序原則,對應(yīng)數(shù)組M(0)的值為0x6D6C6B6A,下同)
M1:6E 80 00 00
M2:00 00 00 00
.....
M14:28 00 00 00
M15:00 00 00 00

經(jīng)過3. 分組數(shù)據(jù)處理后,a、b、c、d值分別為0xD8523F60、0x837E0144、0x517726CA、0x1BB6E5FE
在內(nèi)存中為:

a:60 3F 52 D8
b:44 01 7E 83
c:CA 26 77 51
d:FE E5 B6 1B

a、b、c、d按內(nèi)存順序輸出即為最終結(jié)果:603F52D844017E83CA267751FEE5B61B。這就是字符串“jklmn”的MD5值。


MD5在ios系統(tǒng)中的應(yīng)用

下面我們就看一下ios中MD5是如何加密的,下面還是直接看代碼。

#import "JJMD5VC.h"
#import <CommonCrypto/CommonDigest.h>

@interface JJMD5VC ()

@end

@implementation JJMD5VC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor lightGrayColor];
    
    [self beginMD5ProcessWithString:@"jklmn"];
}

#pragma mark - Object Private Function

- (void)beginMD5ProcessWithString:(NSString *)string
{
    //傳入?yún)?shù),轉(zhuǎn)化成char
    const char * str = [string UTF8String];
    
    //開辟一個16字節(jié)(128位:md5加密出來就是128位/bit)的空間(一個字節(jié)=8字位=8個二進(jìn)制數(shù))
    unsigned char md[CC_MD5_DIGEST_LENGTH];
    
     /*
       *extern unsigned char * CC_MD5(const void *data, CC_LONG len, unsigned char *md)官方封裝好的加密方法
      *      把str字符串轉(zhuǎn)換成了32位的16進(jìn)制數(shù)列(這個過程不可逆轉(zhuǎn)) 存儲到了md這個空間中
      *
      */
     CC_MD5(str, (int)strlen(str), md);
    
     //創(chuàng)建一個可變字符串收集結(jié)果
    NSMutableString * ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        
         /**
          X 表示以十六進(jìn)制形式輸入/輸出
          02 表示不足兩位,前面補0輸出;出過兩位不影響
          printf("%02X", 0x123); //打印出:123
          printf("%02X", 0x1); //打印出:01
          
          */
        [ret appendFormat:@"%02X",md[i]];
     }
    
    NSLog(@"%@",ret);
}

@end

注意要引入頭文件

#import <CommonCrypto/CommonDigest.h>

下面看輸出結(jié)果

2017-08-19 18:08:25.595 JJOC[9099:303472] 603F52D844017E83CA267751FEE5B61B

可見,實現(xiàn)了加密,輸出了加密結(jié)果。

MD5是不可逆轉(zhuǎn)和破解的,但是,網(wǎng)上還是有很多暴力破解工具,舉一個例子,這里就有個網(wǎng)站

我們看一下破解結(jié)果

破解結(jié)果

對比輸出結(jié)果,可見是正確的,這里暴力破解并不是算法上的破解,而是將很多組合的MD5存儲,到時候直接查詢和嘗試獲得的結(jié)果。

這里還要注意:

  • 一定要和后臺開發(fā)人員約定好,MD5加密的位數(shù)是16位還是32位(大多數(shù)都是32位的),16位的可以通過32位的轉(zhuǎn)換得到。
  • MD5加密區(qū)分 大小寫,使用時要和后臺約定好。

參考文章

1. iOS MD5加密
2. iOS開發(fā) 關(guān)于MD5加密的相關(guān)使用

后記

未完,待續(xù)~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容