MAC下MD5校驗(yàn)文件完整性
先上代碼:
在.m文件中導(dǎo)入頭文件:#import <CommonCrypto/CommonDigest.h>
直接在.m文件中實(shí)現(xiàn)下列兩個(gè)方法:
校驗(yàn)字符串:
+(NSString*)md5:(NSString*) str
{
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), result );
NSMutableString *hash = [NSMutableString string];
for(int i=0;i<CC_MD5_DIGEST_LENGTH;i++)
{
[hash appendFormat:@"%02X",result[i]];
}
return [hash lowercaseString];
}
校驗(yàn)文件:
#define CHUNK_SIZE 1024
+(NSString *)file_md5:(NSString*) path
{
NSFileHandle* handle = [NSFileHandle fileHandleForReadingAtPath:path];
if(handle == nil)
return nil;
CC_MD5_CTX md5_ctx;
CC_MD5_Init(&md5_ctx);
NSData* filedata;
do {
filedata = [handle readDataOfLength:CHUNK_SIZE];
CC_MD5_Update(&md5_ctx, [filedata bytes], [filedata length]);
}
while([filedata length]);
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(result, &md5_ctx);
[handle closeFile];
NSMutableString *hash = [NSMutableString string];
for(int i=0;i<CC_MD5_DIGEST_LENGTH;i++)
{
[hash appendFormat:@"%02x",result[i]];
}
return [hash lowercaseString];
}
下面介紹原理:
思考一個(gè)問題
用戶需要上傳和下載一個(gè)重要的資料文件啥么,應(yīng)該如何判斷用戶本次是否上傳成功和下載成功了呢矾飞?是否僅僅通過代碼來判斷當(dāng)前次的請求發(fā)送結(jié)束或者收到數(shù)據(jù)結(jié)束就可以了嗎剑梳?
答案是否定的骤素。文件的上傳與下載極易出錯(cuò)饱亮,尤其涉及使用斷點(diǎn)續(xù)傳方式上傳或下載的文件。
因此非常有必要在客戶端與服務(wù)器之間通過一種驗(yàn)證機(jī)制來確保文件上傳下載后的完整性斗幼。那怎么樣才能保證資源的完整性盯串,處理辦法就是用MD5驗(yàn)證文件的完整性娇唯!
當(dāng)客戶端上傳一個(gè)文件的時(shí)候,在請求body里面添加該文件的MD5值來告訴服務(wù)器寂玲,服務(wù)器接受文件完畢以后通過校驗(yàn)收到的文件的MD5值與請求body里面的MD5值來最終確定本次上傳是否成功塔插。
當(dāng)客戶端下載一個(gè)文件的時(shí)候,在響應(yīng)頭里面收到了服務(wù)器附帶的該文件的MD5值拓哟,文件下載結(jié)束以后想许,通過獲取下載后文件的MD5值與本次請求服務(wù)器返回的響應(yīng)頭中的MD5值做一個(gè)比較,來最終判斷本次下載是否成功断序。
你可能覺得不就是下載一個(gè)文件嗎流纹?需要這么麻煩嗎?
那我們還是一起看看一些其他人都是怎么做的吧违诗。
附上mysql的文件下載安裝頁面部分截圖
這里強(qiáng)調(diào)一下漱凝,使用MD5來校驗(yàn)完整性還是非常有必要的,例如該文件比較大较雕,一個(gè)請求并不能快速請求到整個(gè)文件碉哑。文件的下載過程是持續(xù)的挚币,大部分瀏覽在下載支持?jǐn)帱c(diǎn)續(xù)傳請求方式的文件的時(shí)候亮蒋,默認(rèn)都是啟用了斷點(diǎn)續(xù)傳的方式來下載。
既然使用斷點(diǎn)續(xù)傳妆毕,那么不用想慎玖,每一次請求都需要就設(shè)置Content-Range這個(gè)頭部,設(shè)置range字節(jié)開始傳輸?shù)奈恢茫J(rèn)是按字節(jié)算的)笛粘,回應(yīng)使用206狀態(tài)值趁怔,表示現(xiàn)在開始部分傳輸,回復(fù)Content-Length頭部薪前,表示傳輸?shù)牟糠秩笈米止?jié)記,然后就與普通傳輸沒有區(qū)別了示括。這里Content-Range這個(gè)頭部每次都不一樣铺浇,它是通過瀏覽器在每次收一部分?jǐn)?shù)據(jù)后不斷在更新的,文件下載后又涉及一個(gè)I/O操作垛膝,更新緩存進(jìn)度信息操作鳍侣,這樣即使用戶任何時(shí)候關(guān)閉了瀏覽器,下載打開瀏覽器吼拥,文件還是從最近一次操作的最后進(jìn)度開始的倚聚。既然這么復(fù)雜,那么這個(gè)過程其實(shí)就極易出錯(cuò)凿可。因此惑折,很難確保下載后太惠,通過拼接二進(jìn)制數(shù)據(jù)產(chǎn)生的文件就一定是完整的。因此驗(yàn)證文件完整性必不可少婴梧。
細(xì)心的朋友們以后在下載任何文件的時(shí)候蔓倍,都可以關(guān)注一下是否有MD5有關(guān)的信息。其實(shí)游戲里面的補(bǔ)丁敞咧,下載后是一定需要校驗(yàn)的棘捣。設(shè)想一下,用戶下載了一個(gè)不完整的補(bǔ)丁文件休建,去跟一個(gè)舊版本的游戲做補(bǔ)丁合成乍恐,生產(chǎn)的最終的新版本文件,一定是錯(cuò)誤的测砂。那么游戲使用者基本上再也打不開這個(gè)游戲軟件了茵烈,只能刪除重新一個(gè)完整的新版本安裝包。(用戶內(nèi)心一定是千萬只草泥馬奔騰而過????~)砌些。其實(shí)在完整的補(bǔ)丁文件與舊版本做合并新版本的過程中也是容易出錯(cuò)的呜投,任何的差池都會導(dǎo)致最終合并后的最版本有可能是錯(cuò)誤的,那么合并后再次進(jìn)行一次校驗(yàn)(需要服務(wù)器提供新版本完整包的MD5)也是非常有必要的存璃。如果整個(gè)過程都沒有問題仑荐,那么恭喜本次下載補(bǔ)丁,合并補(bǔ)丁的過程是非常OK的纵东,用戶僅僅下載了很小的補(bǔ)丁就實(shí)現(xiàn)了整個(gè)應(yīng)用程序的完整安裝粘招。
那么你肯定想問,文件的MD5值究竟是什么偎球,它能表征寫什么信息呢洒扎?還是先度娘一下吧
MD5校驗(yàn)和通過對接收的傳輸數(shù)據(jù)執(zhí)行散列運(yùn)算來檢查數(shù)據(jù)的正確性。
一個(gè)散列函數(shù)衰絮,比如 MD5袍冷,是一個(gè)將任意長度的數(shù)據(jù)字符串轉(zhuǎn)化成短的固定長度的值的單向操作。任意兩個(gè)字符串不應(yīng)有相同的散列值(即猫牡,有“很大可能”是不一樣的胡诗,并且要人為地創(chuàng)造出來兩個(gè)散列值相同的字符串應(yīng)該是困難的)。
一個(gè) MD5校驗(yàn)和通過對接收的傳輸數(shù)據(jù)執(zhí)行散列運(yùn)算來檢查數(shù)據(jù)的正確性镊掖。計(jì)算出的散列值拿來和隨數(shù)據(jù)傳輸?shù)纳⒘兄当容^乃戈。如果兩個(gè)值相同,說明傳輸?shù)臄?shù)據(jù)完整無誤亩进、沒有被竄改過(前提是散列值沒有被竄改)症虑,從而可以放心使用。
MD5校驗(yàn)可以應(yīng)用在多個(gè)領(lǐng)域归薛,比如說機(jī)密資料的檢驗(yàn)谍憔,下載文件的檢驗(yàn)匪蝙,明文密碼的加密等。MD5校驗(yàn)原理舉例:如客戶往我們數(shù)據(jù)中心同步一個(gè)文件习贫,該文件使用MD5校驗(yàn)逛球,那么客戶在發(fā)送文件的同時(shí)會再發(fā)一個(gè)存有校驗(yàn)碼的文件,我們拿到該文件后做MD5運(yùn)算苫昌,得到的計(jì)算結(jié)果與客戶發(fā)送的校驗(yàn)碼相比較颤绕,如果一致則認(rèn)為客戶發(fā)送的文件沒有出錯(cuò),否則認(rèn)為文件出錯(cuò)需要重新發(fā)送祟身。
簡單總結(jié)一下:其實(shí)就是任何一個(gè)字符串或文件奥务,無論是可執(zhí)行程序、圖像文件袜硫、臨時(shí)文件或者其他任何類型的文件氯葬,也不管它體積多大,都有且只有一個(gè)獨(dú)一無二的MD5信息碼婉陷,并且如果這個(gè)文件被修改過帚称,它的MD5碼也將隨之改變。
Message-Digest泛指字節(jié)串(Message)的Hash變換秽澳,就是把一個(gè)任意長度的字節(jié)串變換成一定長的大整數(shù)闯睹。注意這里說的是“字節(jié)串”而不是“字符串”,因?yàn)檫@種變換只與字節(jié)的值有關(guān)肝集,與字符集或編碼方式無關(guān)瞻坝。
知道了原理蛛壳,那就話不多說杏瞻,趕快操練起來吧!
md5sum命令是Linux平臺下面用來檢測文件完整性的給力工具,維基百科是這樣來解釋 md5sum的:
md5sum是一種計(jì)算機(jī)程序衙荐,用于計(jì)算與校驗(yàn)128位MD5哈希值捞挥,此處MD5散列值(或校驗(yàn)和)作一個(gè)文件的數(shù)字指紋使用。理論上看忧吟,正如其他散列算法一樣砌函,一個(gè)MD5哈希值可對應(yīng)無限個(gè)文件,但從現(xiàn)實(shí)的角度看溜族,兩個(gè)不同的文件幾乎不可能有相同的MD5哈希值讹俊,除非其創(chuàng)建便是刻意為之。一般來說煌抒,任何對一個(gè)文件的非惡意變更都會導(dǎo)致其MD5哈希值改變仍劈,因此md5sum一般用于檢查文件完整性,尤其常用于檢測在文件傳輸寡壮、磁盤錯(cuò)誤或其他無惡意涉入的情況下文件的正確性贩疙。
示例:
以linux下shell為環(huán)境示例讹弯,以下文件皆于同一目錄下。
計(jì)算校驗(yàn)值并輸出至hash.md5
$ md5sum filetohashA.txt filetohashB.txt filetohashC.txt > hash.md5
所得文件这溅,文件內(nèi)包括了哈希值和對應(yīng)的文件名组民。
$ cat hash.md5
595f44fec1e92a71d3e9e77456ba80d1? filetohashA.txt
71f920fa275127a7b60fa4d4d41432a3? filetohashB.txt
43c191bf6d6c3f263a8cd0efd4a058ab? filetohashC.txt
Mac OS可以用md5命令
先看下使用說明
usage: md5 [-pqrtx] [-s string] [files ...]
操練起來:
~ md5 -s woaini
MD5 ("woaini") = 023299564b0db47d5f3e476a254d0c21
MD5命令不能將路徑設(shè)置為文件夾路徑,只能是某一個(gè)具體文件悲靴。
~ MD5 /Users/nuomi/Desktop/OmniPlan-3.3.3.dmg
MD5 (/Users/nuomi/Desktop/OmniPlan-3.3.3.dmg) = c0a01ff9c0a4f0691a46616ab71e3380
還是非常簡單的臭胜。
那么在實(shí)際的移動應(yīng)用開發(fā)中,文件上傳癞尚、下載都是必不可少的功能~
在此附上一個(gè)我總結(jié)的一個(gè)iOS上使用OC寫的獲取文件MD5值得一個(gè)小工具庇楞。
建議大家在重要文件的上傳、下載時(shí)否纬,一定要與后臺同學(xué)協(xié)商吕晌,添加這個(gè)校驗(yàn)過程來保證文件傳輸過程的完整性。