哈希 HASH·數(shù)字簽名

HASH

現(xiàn)在在處理App的用戶敏感信息方面,大部分都是采用HASH加密的方式來進行處理。

關(guān)于哈希算法 詳細看這篇 轉(zhuǎn)載:哈希算法詳解(附帶iOS開發(fā)中實際應(yīng)用)
概念

  • Hash,一般翻譯做散列,也有直接音譯為哈希的.
    就是把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值
  • 這種轉(zhuǎn)換是一種壓縮映射,也就是散列值的空間通常遠小于輸入的空間,不同的輸入可能會散列成相同的輸出,所以不可能從散列值來確定唯一的輸入值。
    簡單的說,就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數(shù)。
  • 哈希破解(散列碰撞):不同的N多種數(shù)據(jù)哈希之后得到相同的結(jié)果
  • 單向散列函數(shù):又稱單向Hash函數(shù)、雜湊函數(shù),就是把任意長的輸入消息串變化成固定長的輸出串且由輸出串難以得到輸入串的一種函數(shù)。這個輸出串稱為該消息的散列值。一般用于產(chǎn)生消息摘要,密鑰加密等.

特點

  • 算法是公開的
  • 對相同數(shù)據(jù)運算,得到的結(jié)果是一樣的
  • 對不同數(shù)據(jù)運算,如MD5得到的結(jié)果默認是128位,32個字符(16進制標識)。
  • 沒法進行逆運算
  • 信息摘要,信息“指紋”,是用來做數(shù)據(jù)識別的。
  • 加密后密文的長度是定長的

用途

  • 用戶密碼的加密
  • 搜索引擎,關(guān)鍵字識別(搜索多個關(guān)鍵字,先對每個關(guān)鍵字進行散列,然后多個關(guān)鍵字進行或運算,如果值一致則搜索結(jié)果一致)
  • 版權(quán)標注 對文件進行散列判斷該文件是否是正版或原版的
  • 數(shù)字簽名 (文件完整性驗證 對整個文件進行散列,比較散列值判斷文件是否完整或被篡改)

常見的哈希加密算法

MD5,HMAC,SHA1,SHA256

MD5

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

  • 從一段字符串中通過相應(yīng)特征生成一段32位的數(shù)字字母混合碼。對輸入信息生成唯一128位散列值(32個16進制的數(shù)字)
  • 所有的數(shù)據(jù)(視頻、音頻、文件只要存在于硬盤或內(nèi)存中的)都是可以被MD5加密的,得到的都是32個字符。

特征

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

使用第三方框架:NSString+Hash

#pragma mark – MD5 加密
//String轉(zhuǎn)化為md5加密String
+ (NSString *)md5:(NSString *)str
{
const char *cStr = [str UTF8String];
unsigned char result[16];
CC_MD5(cStr, strlen(cStr), result); // This is the md5 call
return [NSString stringWithFormat:
@”%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x”,
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
}

應(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算法來進行文件校驗的方案被大量應(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值不相同)。如果再有一個第三方的認證機構(gòu),用MD5還可以防止文件作者的“抵賴”,這就是所謂的數(shù)字簽名應(yīng)用。
  • 安全訪問認證
    MD5還廣泛用于操作系統(tǒng)的登陸認證上,如Unix、各類BSD系統(tǒng)登錄密碼、數(shù)字簽名等諸多方面。

MD5認證圖解


這里還要注意:

  • 一定要和后臺開發(fā)人員約定好,MD5加密的位數(shù)是16位還是32位(大多數(shù)都是32位的),16位的可以通過32位的轉(zhuǎn)換得到。
  • MD5加密區(qū)分 大小寫,使用時要和后臺約定好。
    MD5是不可逆轉(zhuǎn)和破解的,但是,網(wǎng)上還是有很多暴力破解工具,舉一個例子,這里就有個網(wǎng)站。

    對比輸出結(jié)果,可見是正確的,這里暴力破解并不是算法上的破解,而是將很多組合的MD5存儲,到時候直接查詢和嘗試獲得的結(jié)果。
    MD5加密進階
    1)先加鹽,然后再進行MD5
    2)先亂序,再進行MD5加密
    3)亂序|加鹽,多次MD5加密等
    4)使用消息認證機制,即HMAC-MD5-先對密鑰進行加密,加密之后進行兩次MD5散列
    5)加密命令行
 MD5加密-字符串    $ echo -n "520it" |md5
  MD5加密-文件1     $ md5 abc.png
  SHA1加密:        $ echo -n "520it" |openssl sha -sha1
  SHA256            $ echo -n "520it" |openssl sha -sha256
  SHA512            $ echo -n "520it" |openssl sha -sha512
  hmacMD5加密       $ echo -n "520it" |openssl dgst -md5 -hmac "123"
//先加密,后亂序

- (void)MD5Reorder {

    NSString *pwd = @"123456789";

    NSString *pwdMD5 = [pwd md5String];

    NSLog(@"oldpwdMD5=%@",pwdMD5);

    NSString *prefix = [pwdMD5 substringFromIndex:3]; //從下標為3的開始截取(包含3)

    NSString *subfix = [pwdMD5 substringToIndex:3];   //截取0到3的字符串(不包含3)

    pwdMD5 = [prefix stringByAppendingString:subfix];

    NSLog(@"newpwdMD5=%@",pwdMD5);

}
 // md5加密調(diào)用
 NSLog(@"%@",[@"520it" md5String]);
 // (明文+加鹽)MD5加密調(diào)用
 NSLog(@"%@",[[@"520it" stringByAppendingString:salt] md5String]);
 // hmacMD5加密調(diào)用(先加密+亂序)
 NSLog(@"%@",[@"520it" hmacMD5StringWithKey:@"xiaomage"]);

傳統(tǒng)方法是加鹽(Salt):
在明文的固定位置插入位數(shù)足夠多、足夠復(fù)雜的隨機串,然后再進行MD5。

NSString *salt = @"fdsfjf)*&*JRhuhew7HUH^&udn&&86&*";

NSString *str = @"123456";    // md5 加密

str = [str stringByAppendingString:salt];

str = [str md5String];

NSLog(@"%@",str);

缺點:鹽是固定不變的,一旦泄露后果不堪設(shè)想;使用加鹽通過MD5解密之后,很容易發(fā)現(xiàn)規(guī)律從而破解。

image
解決方案
HMAC :使用一個密鑰加密并且兩次的散列!

消息認證機制(HMAC)簡單說明
1)原理
①消息的發(fā)送者和接收者有一個共享密鑰
②發(fā)送者使用共享密鑰對消息加密計算得到MAC值(消息認證碼)
③消息接收者使用共享密鑰對消息加密計算得到MAC值
④比較兩個MAC值是否一致
2)使用
①客戶端需要在發(fā)送的時候把(消息)+(消息·HMAC)一起發(fā)送給服務(wù)器
②服務(wù)器接收到數(shù)據(jù)后,對拿到的消息用共享的KEY進行HMAC,比較是否一致,如果一致則信任

/** HMAC
     *  使用一個密鑰加密,并且做兩次散列!
     *  在實際開發(fā)中,密鑰(KEY)來自于服務(wù)器(動態(tài)的)!
     *  一個賬號,對應(yīng)一個KEY,而且還可以跟新!
     */
    NSString*serverKey =@"chh";
    pwd = [pwd hmacMD5StringWithKey:serverKey];

HMAC優(yōu)化

     /** HMAC優(yōu)化
      * 由于直接一直使用HMAC的話,容易被逆向獲取HMAC,
      * 所以考慮在傳輸HMAC的前向服務(wù)器請求時間戳(忽略秒),
      * 然后在HMAC基礎(chǔ)上加上服務(wù)器的時間戳并進行md5加密后進行傳輸 
      * 服務(wù)器存儲的是HMAC(密碼+KEY)的值和KEY,key用于返給客戶端,校驗的時候只需拿HMAC這個值再加上時間戳進行MD5進行比較
     */
    pwd = [[pwd hmacMD5StringWithKey:serverKey] stringByAppendingString:@"服務(wù)器時間戳"].md5String;

簡單示例

#pragma mark - md5加密方法
 - (NSString *)md5String {
     const char *str = self.UTF8String;
     uint8_t buffer[CC_MD5_DIGEST_LENGTH];
     CC_MD5(str, (CC_LONG)strlen(str), buffer);
     return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
 }
 #pragma mark - HMACMD5加密方法
 - (NSString *)hmacMD5StringWithKey:(NSString *)key {
     const char *keyData = key.UTF8String;
     const char *strData = self.UTF8String;
     uint8_t buffer[CC_MD5_DIGEST_LENGTH];
     CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
     return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
 }
  
 /**
  *  返回二進制 Bytes 流的字符串表示形式
  *  @param bytes  二進制 Bytes 數(shù)組
  *  @param length 數(shù)組長度
  *  @return 字符串表示形式
  */
 - (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
     NSMutableString *strM = [NSMutableString string];
     for (int i = 0; i < length; i++) {
         [strM appendFormat:@"%02x", bytes[i]];
     }
     return [strM copy];
 }

以用戶賬號登錄注冊為例
注冊:
1.客戶端向服務(wù)器發(fā)起注冊請求,這時服務(wù)器生成一個密鑰key(并保存),然后將密鑰返回給客戶端。
2.客戶端根據(jù)密鑰對密碼進行HMAC加密生成密文,傳給服務(wù)器,服務(wù)器保存(不允許明文保存用戶的隱私信息)。
3.服務(wù)器返回注冊成功后,客戶端將密鑰保存到手機鑰匙串(減少密鑰傳遞次數(shù),提高安全性)。

登錄:
1.客戶端讀取手機鑰匙串中的密鑰,對密碼進行HMAC加密后,向服務(wù)器發(fā)出登錄請求。
2.服務(wù)器根據(jù)賬號讀取數(shù)據(jù)庫中的密文與客戶端提交的進行比較。
上代碼:

- (NSString *)hmacMD5StringWithKey:(NSString *)key {
    const char *keyData = key.UTF8String;
    const char *strData = self.UTF8String;
    uint8_t buffer[CC_MD5_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer)
    return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}

引申:可以利用這個做出類型于設(shè)備鎖或QQ手機令牌的功能,目的就是為了在他人設(shè)備上無法登錄自己的賬號。
這里說下大致的流程,在客戶端發(fā)出登錄請求時,在手機鑰匙串讀取密鑰,當(dāng)這個密鑰不存在的時,就說明是在他人設(shè)備上操作的,這時可以利用推送通知或短信告訴自己,是否允許他人設(shè)備登錄,只允許此次登錄還是授權(quán)永久登錄。如果僅登陸一次則不保存密鑰到鑰匙串,下次登錄重復(fù)以上操作;如果授權(quán)永久登錄可以再他人設(shè)備保存密鑰。

那么這樣就安全了嗎?too young!??!
如果在第2步中,攔截post內(nèi)容獲取加密后的密文,再模擬客戶端向服務(wù)器發(fā)出請求,就成功黑了!

再次提高安全性:添加時間戳

第一步:客戶端將HMAC得到的數(shù)據(jù)拼接當(dāng)前服務(wù)器時間,再用MD5加密。
(HMAC+201802271633).md5String,將加密后的數(shù)據(jù)post到服務(wù)器。
:201802271633 須為當(dāng)前服務(wù)器時間,避免客戶端時間不統(tǒng)一。

第二步:服務(wù)器開始驗證:根據(jù)賬號在數(shù)據(jù)庫中讀取HMAC,將當(dāng)前服務(wù)器時間拼接后,再用MD5加密,得到32位字符與客戶端提交的32位字符進行比較。這里會有兩種情況,1.服務(wù)器拼接的時間與客戶端拼接的時間一致,得到相同的密文,則通過驗證;2.服務(wù)器拼接的時間與客戶端拼接的時間不一致,得到的密文不相同。這是服務(wù)器就拼接上一個時間,即:客服端密文是:(HMAC+201802271633).md5String,服務(wù)器第一次拼接時間密文是:(HMAC+201802271634).md5String。兩者不一致,服務(wù)器第二次拼接上一個時間段密文:(HMAC+201802271633).md5String,一致則通過。

進行這樣的操作就是讓客戶端發(fā)出的請求的時間有效性只維持1分鐘,如果還覺得不安全可以再拼接時間的時候添加秒,進一步縮短時間的有效性,以提高安全性。

SHA

這篇寫的很全面 轉(zhuǎn)載:http://www.itdecent.cn/p/df04fff20c2b

SHA即Secure Hash Algorithm(安全哈希算法),主要適用于數(shù)字簽名標準(Digital Signature Standard DSS)里面定義的數(shù)字簽名算法(Digital Signature Algorithm DSA)。對于長度小于2^64位的消息,SHA1會產(chǎn)生一個160位的消息摘要。

終端查看SHA函數(shù)散列值

  • 字符串HSA1值
echo -n "string" | openssl sha -sha1
或
echo -n "string" | openssl sha -sha256
或
echo -n "string" | openssl sha -sha512
  • 文件SHA1值
openssl sha -sha1 file.dat(文件路徑)
或
openssl sha -sha256 file.dat
或
openssl sha -sha512 file.dat

代碼

- (NSString *)sha1String {
    const char *str = self.UTF8String;
    // 修改參數(shù),變換散列計算SHA1、SHA256、SHA512
    // uint8_t buffer[CC_SHA256_DIGEST_LENGTH];
    // CC_SHA256(str, (CC_LONG)strlen(str), buffer);
    uint8_t buffer[CC_SHA1_DIGEST_LENGTH];
    CC_SHA1(str, (CC_LONG)strlen(str), buffer);
    return [self stringFromBytes:buffer length:CC_SHA1_DIGEST_LENGTH];
}
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
    NSMutableString *strM = [NSMutableString string];
    for (int i = 0; i < length; i++) {
        [strM appendFormat:@"%02x", bytes[i]];
    }
    return [strM copy];
}

Hmac-SHA256加密算法

/**
 Hmac-SHA256加密算法
 */
+ (NSData *)hmacSha256:(NSString *)hashString hmacKey:(NSString *)key {
    NSData *hashData = [hashString dataUsingEncoding:NSUTF8StringEncoding];
    
    unsigned char *digest;
    digest = malloc(CC_SHA256_DIGEST_LENGTH);
    const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
    
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), [hashData bytes], [hashData length], digest);
    
    NSData *data = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    
    free(digest);
    cKey = nil;
    
    return data;
}

SHA512加密

//SHA512加密
+ (NSString) getSHA512String:(NSString)s
{
const char cstr = [s cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:s.length];
uint8_t digest[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(data.bytes, data.length, digest);
NSMutableString output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++)
[output appendFormat:@”%02x”, digest[i]];
return output;
}

數(shù)字簽名

數(shù)字簽名本質(zhì)上是通過HASH算法和RSA加密來實現(xiàn)的。

HASH算法專門用來做文件數(shù)據(jù)的識別.那么在網(wǎng)絡(luò)數(shù)據(jù)傳遞的過程中,我們可以將明文數(shù)據(jù),和數(shù)據(jù)的HASH值一起傳遞給對方.對方可以拿出HASH值來進行驗證。

但是在這個過程中,如何做到數(shù)據(jù)的保護呢?明文數(shù)據(jù)和HASH值如果直接傳遞就有都被篡改的風(fēng)險.所以這里我們要對數(shù)據(jù)進行加密。明文數(shù)據(jù)有時會比較大,不適合使用RSA非對稱加密算法,那么數(shù)據(jù)的HASH值是比較小的。這個數(shù)據(jù)是用于校驗的,它完全可以使用RSA來加密。所以在數(shù)據(jù)傳遞的時候,我們將明文數(shù)據(jù)加上通過RSA加密的校驗數(shù)據(jù)一并傳遞給對方。那么這個通過RSA加密的校驗數(shù)據(jù),我們稱之為簽名.

image

驗證數(shù)字簽名

當(dāng)對方拿到數(shù)據(jù)之后,如何進行驗證呢?

首先傳遞數(shù)據(jù)時會將原始的數(shù)據(jù)和數(shù)字簽名一起發(fā)送

對方拿到數(shù)據(jù)后,先進行校驗,拿到原始數(shù)據(jù),通過同樣的HASH算法得到數(shù)據(jù)的HASH值。

然后通過非對稱加密,將數(shù)字簽名中的校驗HASH值解密出來。

最后對比兩個HASH值是否一致,這樣可以很好的判斷數(shù)據(jù)是否被篡改。

image

MD5算法原理

對MD5算法簡要的敘述可以為:
MD5512位分組來處理輸入的信息,且每一分組又被劃分為1632位子分組,經(jīng)過了一系列的處理后,算法的輸出由432位分組組成,將這432位分組級聯(lián)后將生成一個128位散列值。
總體的流程圖如下所示,
表示第i個分組,每次的運算都由前一輪的128位結(jié)果值和第i塊512bit值進行運算。

流程圖

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

填充的方法如下:

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

第二步· 初始化變量
初始的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

第三步· 處理分組數(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)都很相似。第一輪進行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ù)運行以上算法。

第四步· 輸出
最后的輸出是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一個簡單實例

現(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個二進制數(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進制數(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 表示以十六進制形式輸入/輸出
          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é)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容