1.1 單向散列函數(shù)
單向散列函數(shù)(One-way hash function),也稱之為消息摘要函數(shù)(Message Digest Function),哈希函數(shù),它可以根據(jù)消息的內(nèi)容計(jì)算出一個(gè)散列值;
輸出的散列值,也被稱為消息摘要(message digest)、指紋(fingerprint);
1.2 單向散列函數(shù)的特點(diǎn)
1.散列值的長(zhǎng)度與消息的長(zhǎng)度<mark>無(wú)關(guān)</mark>,無(wú)論消息是1bit、10M、100G,單向散列函數(shù)都會(huì)計(jì)算出<mark>固定長(zhǎng)度</mark>的散列值,如下圖:

2.計(jì)算速度快,能快速的計(jì)算出散列值;
3.消息不同,散列值也不同;
4.具備單向性:無(wú)法通過(guò)散列值反推出原始消息內(nèi)容

2.1 單向散列函數(shù)常見(jiàn)類(lèi)型
·MD4:具有3輪16步,輸出位長(zhǎng)度為128位。
·MD5:具有4輪16步,輸出位長(zhǎng)128位。
·SHA-1:具有4個(gè)20階的步長(zhǎng)和160位的輸出位長(zhǎng)度。
·SHA-256:具有64輪單步,輸出位長(zhǎng)度為256位。
·SHA-384:實(shí)際上與SHA-512相同,除了輸出被截?cái)酁?83位。
·SHA-512:具有80個(gè)單步的輪數(shù)和512位的輸出位長(zhǎng)度。
2.1.1 MD4:
MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年設(shè)計(jì)的,MD 是 Message Digest 的縮寫(xiě)。它適用在32位字長(zhǎng)的處理器上用高速軟件實(shí)現(xiàn)--它是基于 32 位操作數(shù)的位操作來(lái)實(shí)現(xiàn)的。它的安全性不像RSA那樣基于數(shù)學(xué)假設(shè),盡管 Den Boer、Bosselaers 和 Dobbertin 很快就用分析和差分成功的攻擊了它3輪變換中的 2 輪,證明了它并不像期望的那樣安全,但它的整個(gè)算法并沒(méi)有真正被破解過(guò),Rivest 也很快進(jìn)行了改進(jìn)。
2.1.2 MD5:
MD5(RFC 1321)是 Rivest 于1991年對(duì)MD4的改進(jìn)版本。它對(duì)輸入仍以512位分組,其輸出是4個(gè)32位字的級(jí)聯(lián),與 MD4 相同。它較MD4所做的改進(jìn)是:
- 加入了第四輪
- 每一步都有唯一的加法常數(shù);
- 第二輪中的G函數(shù)從((X ∧ Y) ∨ (X ∧ Z) ∨ (Y ∧ Z)) 變?yōu)?((X ∧ Z) ∨ (Y ∧ ~Z))以減小其對(duì)稱性;
- 每一步都加入了前一步的結(jié)果,以加快"雪崩效應(yīng)";
- 改變了第2輪和第3輪中訪問(wèn)輸入子分組的順序,減小了形式的相似程度;
- 近似優(yōu)化了每輪的循環(huán)左移位移量,以期加快"雪崩效應(yīng)",各輪的循環(huán)左移都不同。
盡管MD5比MD4來(lái)得復(fù)雜,并且速度較之要慢一點(diǎn),但更安全,在抗分析和抗差分方面表現(xiàn)更好。
使用終端查看字符串或者文件的MD5值:
md5 -s 字符串
md5 文件路徑
//字符串
md5 -s 24324
MD5 ("24324") = fb2e636577105f243646d6f1e199f0ba
//文件
MD5 /Users/i/Desktop/2.pdf
MD5 (/Users/i/Desktop/2.pdf) = bd32d590689394cae6a3f234a33ca93c
iOS實(shí)現(xiàn)字符串轉(zhuǎn)MD5:
#import "NSString+MD5.h"
@implementation NSString (MD5)
- (NSString *)MD5String{
//傳入?yún)?shù),轉(zhuǎn)化成char
const char * str = [self UTF8String];
//開(kāi)辟一個(gè)16字節(jié)(128位:md5加密出來(lái)就是128位/bit)的空間(一個(gè)字節(jié)=8字位=8個(gè)二進(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ù)列(這個(gè)過(guò)程不可逆轉(zhuǎn)) 存儲(chǔ)到了md這個(gè)空間中
*/
CC_MD5(str, (int)strlen(str), md);
//創(chuàng)建一個(gè)可變字符串收集結(jié)果
NSMutableString * ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
/**
X 表示以十六進(jìn)制形式輸入/輸出
02 表示不足兩位,前面補(bǔ)0輸出;出過(guò)兩位不影響
printf("%02X", 0x123); //打印出:123
printf("%02X", 0x1); //打印出:01
*/
[ret appendFormat:@"%02X",md[i]];
}
//返回一個(gè)長(zhǎng)度為32的字符串
return ret;
}
@end
ios實(shí)現(xiàn)NSData轉(zhuǎn)H5
#import "NSData+MD5.h"
#import <CommonCrypto/CommonDigest.h>
@implementation NSData (MD5)
-(NSData *)MD5Data{
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(self.bytes, (CC_LONG)self.length, result);
return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}
@end
2.1.3 SHA1-SHA224-SHA256-SHA384-SHA512:
- (NSString *) sha1String{
NSData *data = [self dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (unsigned int)data.length, digest);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i=0; i<CC_SHA1_DIGEST_LENGTH; i++) {
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
-(NSString *)sha224String{
const char *cstr=[self cStringUsingEncoding:NSUTF8StringEncoding];
NSData*data=[NSData dataWithBytes:cstr length:self.length];
uint8_t digest[CC_SHA224_DIGEST_LENGTH];
CC_SHA224(data.bytes, (unsigned int)data.length, digest);
NSMutableString*output=[NSMutableString stringWithCapacity:CC_SHA224_DIGEST_LENGTH*2];
for(int i=0; i < CC_SHA224_DIGEST_LENGTH; i++){
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
- (NSString *)sha256String{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:self.length];
uint8_t digest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256(data.bytes,(CC_LONG)data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++){
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
- (NSString *)sha384String
{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:self.length];
uint8_t digest[CC_SHA384_DIGEST_LENGTH];
CC_SHA384(data.bytes,(CC_LONG) data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA384_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA384_DIGEST_LENGTH; i++){
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
- (NSString *)sha512String
{
const char *cstr = [self cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:self.length];
uint8_t digest[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(data.bytes, (CC_LONG)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;
}
3 單向散列函數(shù)的應(yīng)用
3.1 某些大型軟件的官網(wǎng)會(huì)公布軟件的散列值,防止軟件被篡改

例如: vnc官網(wǎng)下載鏈接,會(huì)有軟件的SHA256生成的散列值:

3.2 服務(wù)器存放的用戶的密碼不是明文的,而是對(duì)應(yīng)密碼的散列值,比如SHA2(密碼)

服務(wù)器中存放的不是用戶密碼的明文,如果存放的是密碼明文,風(fēng)險(xiǎn)太高,一般存放的是對(duì)應(yīng)用戶名的密碼的散列值,在用戶登錄的時(shí)候,通過(guò)散列值與數(shù)據(jù)庫(kù)中的散列值對(duì)比,如果相同則登錄成功.