密碼學(xué)概論
原則:
- 在網(wǎng)絡(luò)上不允許明文傳輸用戶隱私信息兑宇;
- 在本地不允許明文保存用戶隱私信息朱盐;
base64 編碼
base64 編碼:將二進(jìn)制數(shù)據(jù)編碼成只有65個(gè)字符的文本文件(字符)株搔!
base64 編碼包括的字符:0 ~9, a~z, A~Z, +/=
編碼后文件數(shù)據(jù)會(huì)比原有文件大1/3左右磕昼。
原理
base64 編碼:8位的二進(jìn)制ASCII編碼 —> 6位的base64編碼
base64編碼表:
0~63味廊,64個(gè)字符延都,還有 = 表示空格雷猪,總共65個(gè)字符。
示例:
Man 轉(zhuǎn)換為 base64 編碼:TWFu
M 的 ASCII編碼 十進(jìn)制為 77 晰房,二進(jìn)制為 01001101:
前6位二進(jìn)制 010011 (十進(jìn)制為19)在上面的base64編碼表中為 T 求摇。
因此 M ? T 。
空格情況
因?yàn)槭前?個(gè)字節(jié)轉(zhuǎn)換為6個(gè)字節(jié)進(jìn)行編碼殊者,勢必會(huì)產(chǎn)生位數(shù)不對應(yīng)的問題与境。因此會(huì)使用 0 來補(bǔ)齊,用=表示全0的情況幽污。(注意到base64 總會(huì)編碼補(bǔ)齊為4個(gè)字符一組)
因此嚷辅,單獨(dú)的 M 用base64編碼 ? TQ==
Objective-C 代碼
// base64編碼
- (NSString *)base64Encode:(NSString *)string {
// 1.將字符串轉(zhuǎn)換為二進(jìn)制
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// 2.二進(jìn)制數(shù)據(jù)進(jìn)行編碼
return [data base64EncodedStringWithOptions:0];
}
// base64解碼
- (NSString *)base64Decode:(NSString *)string {
// 1.字符串轉(zhuǎn)換為二進(jìn)制
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
// 2.解碼
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
哈希、對稱加密距误、非對稱加密
上世紀(jì)70年代開始 RSA — 非對稱加密算法
RSA — 非對稱加密算法
- 公鑰加密簸搞,私鑰解密扁位;
- 私鑰加密,公鑰解密趁俊;
哈希(散列)函數(shù)
- MD5
- SHA1\SHA256\SHA512
- HMAC
對稱加密算法
- DES
- 3DES
- RC2域仇、RC4
- AES(高級密碼標(biāo)準(zhǔn),美國國家安全局使用寺擂、Apple 鑰匙串訪問使用暇务、Lastpass 使用了256位的AES密鑰),以目前現(xiàn)階段計(jì)算機(jī)的運(yùn)行效率怔软,要暴力破解AES加密算法垦细,需要上千萬年。
散列函數(shù)
算法都是公開的挡逼。
- 對相同的數(shù)據(jù)加密括改,得到的結(jié)果是一樣的。
- 對不同的數(shù)據(jù)加密家坎,得到的結(jié)果是定長的嘱能。(比如MD5對不同的數(shù)據(jù)加密,得到32個(gè)字符)
- 加密之后的數(shù)據(jù)是沒法解密的虱疏。(不可逆運(yùn)算)
MD5 哈希算法
GitHub源碼:jerilimov/NSHash——NSData惹骂、NSString 的分類,添加了MD5做瞪、SHA1对粪、SHA256、SHA512 加密算法
NSString *pwd = @"123456";
pwd = [pwd MD5];
NSLog(@"MD5 = %@",pwd);
// MD5 = e10adc3949ba59abbe56e057f20f883e
像 MD5 這樣的加密算法是無法反向解密的穿扳,但是對相同的數(shù)據(jù)加密衩侥,得到的結(jié)果是一樣的。
于是 CMD5 利用散列函數(shù)的這種特性矛物,將加密前的數(shù)據(jù)和加密后的數(shù)據(jù)進(jìn)行映射保存,可以實(shí)現(xiàn)反向查詢跪但。
將剛才 123456 加密后的 MD5 輸入履羞,可以反向查詢出原始數(shù)據(jù):
MD5加鹽:對數(shù)據(jù)先加鹽,再進(jìn)行MD5加密屡久,可以增加結(jié)果的復(fù)雜度
/* 鹽忆首,足夠長,足夠復(fù)雜被环,足夠咸*/
static NSString *slat = @"5O9Jc!9%N^6Kd*dcS9Or$&fSVWmC^xku2@Lg0xd8CL0Sl$omN6zQS7c7YrHhtwn@";
NSString *pwd = @"123456";
pwd = [[pwd stringByAppendingString:slat] MD5];
NSLog(@"MD5 = %@",pwd);
// MD5 = 04f60881265e2b240b217f8deaaa8e12
再將此MD5密碼放到該網(wǎng)站上進(jìn)行查詢:
沒有查到糙及,結(jié)果顯示,被反向查詢出來的難度就會(huì)加大筛欢。
缺點(diǎn):鹽是固定的浸锨,如果鹽被泄露唇聘,數(shù)據(jù)就會(huì)不安全。
注:哈希算法&加密算法的區(qū)分
- MD5柱搜、HMAC迟郎、SHA 等所有的哈希算法嚴(yán)格上來說并不能稱之為加密算法,它只能說是密碼學(xué)中的哈希算法聪蘸。
- 加密算法加密之后是可以解密的宪肖,而哈希算法無法反向解出原始數(shù)據(jù)。
- 哈希算法通常用于校驗(yàn)數(shù)據(jù)的完整性健爬,例如:校驗(yàn)下載后的安裝包文件是否被篡改控乾、刪減或植入惡意代碼。
HMAC 哈希算法
//-----------------------------------------------------
#import <Foundation/Foundation.h>
@interface NSString (Hash)
- (NSString *)hmacMD5StringWithKey:(NSString *)key;
- (NSString *)hmacSHA1StringWithKey:(NSString *)key;
- (NSString *)hmacSHA256StringWithKey:(NSString *)key;
- (NSString *)hmacSHA512StringWithKey:(NSString *)key;
@end
#import "NSString+Hash.h"
#import <CommonCrypto/CommonHMAC.h>
@implementation NSString (Hash)
- (NSString *)hmacMD5StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgMD5 withKey:key];
}
- (NSString *)hmacSHA1StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA1 withKey:key];
}
- (NSString *)hmacSHA256StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA256 withKey:key];
}
- (NSString *)hmacSHA512StringWithKey:(NSString *)key
{
return [self hmacStringUsingAlg:kCCHmacAlgSHA512 withKey:key];
}
#pragma mark - Helpers
- (NSString *)hmacStringUsingAlg:(CCHmacAlgorithm)alg withKey:(NSString *)key
{
size_t size;
switch (alg) {
case kCCHmacAlgMD5:
size = CC_MD5_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA1:
size = CC_SHA1_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA224:
size = CC_SHA224_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA256:
size = CC_SHA256_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA384:
size = CC_SHA384_DIGEST_LENGTH;
break;
case kCCHmacAlgSHA512:
size = CC_SHA512_DIGEST_LENGTH;
break;
default:
return nil;
}
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
NSData *messageData = [self dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *mutableData = [NSMutableData dataWithLength:size];
CCHmac(alg, keyData.bytes, keyData.length, messageData.bytes, messageData.length, mutableData.mutableBytes);
return [self stringFromBytes:(unsigned char *)mutableData.bytes length:(int)mutableData.length];
}
- (NSString *)stringFromBytes:(unsigned char *)bytes length:(int)length
{
NSMutableString *mutableString = @"".mutableCopy;
for (int i = 0; i < length; i++)
[mutableString appendFormat:@"%02x", bytes[i]];
return [NSString stringWithString:mutableString];
}
@end
測試
// HMAC 用一個(gè)密鑰加密娜遵,并且做了兩次散列阱持。
// 在實(shí)際的開發(fā)中,密鑰來自于服務(wù)器魔熏≈匝剩——對應(yīng)一個(gè)帳號(hào),一個(gè)KEY
NSString *pwd = @"123456";
pwd = [pwd hmacMD5StringWithKey:@"Key"];
NSLog(@"MD5 = %@",pwd);
// MD5 = a7cac7471d2c9eb7a944e07d44d305ca
將此MD5密碼放到該網(wǎng)站上查詢也是查不到的蒜绽。
項(xiàng)目實(shí)際使用流程:
- 服務(wù)器根據(jù)用戶帳號(hào)生成KEY镶骗,發(fā)送給客戶端;
- 客戶端獲得KEY并保存到本地躲雅,使用KEY對數(shù)據(jù)進(jìn)行HMAC加密鼎姊,將加密后的數(shù)據(jù)發(fā)送給服務(wù)器;
- 服務(wù)器對加密后對數(shù)據(jù)進(jìn)行驗(yàn)證相赁。
客戶端登錄時(shí)相寇,沒有KEY就先根據(jù)帳號(hào)從服務(wù)器獲取KEY保存到本地,再將獲得的KEY對密碼進(jìn)行加密钮科。
防止KEY泄露唤衫,對KEY進(jìn)行非對稱加密、定期更換KEY绵脯。
QQ設(shè)備鎖:
- 本地有KEY——為授權(quán)手機(jī)佳励。
- 本地沒有KEY,未授權(quán)設(shè)備蛆挫,需要允許服務(wù)器發(fā)送KEY赃承。允許一次登錄,本地不保存KEY悴侵,允許多次登錄瞧剖,保存KEY到本地。
- 短信驗(yàn)證碼登錄獲取KEY。
- 申訴獲取KEY抓于。
HMAC加密+時(shí)間戳(不加秒)
之前:
驗(yàn)證方式:HMAC密碼直接匹配是否正確做粤。
現(xiàn)在:
客戶端:(HMAC密碼+“201711010358”).MD5校驗(yàn)
服務(wù)器:
- (HMAC密碼+“201711010359”).MD5校驗(yàn)
- (HMAC密碼+“201711010358”).MD5校驗(yàn)
密碼驗(yàn)證有效期最長2分鐘,超過2分鐘毡咏,驗(yàn)證失敗驮宴。
有經(jīng)驗(yàn)的服務(wù)器人員,會(huì)在返回?cái)?shù)據(jù)時(shí)呕缭,返回時(shí)間戳堵泽。
登錄等待時(shí)間,不要超過6秒;肿堋S蕖!提示用戶:你的網(wǎng)絡(luò)不穩(wěn)定片仿,請稍后再試纹安!
終端測試命令:
md5 -s "string" #這是 Apple 用的 openssl 標(biāo)準(zhǔn)進(jìn)行的MD5加密
MD5使用場景,百度搜索引擎(拆詞搜索思路)運(yùn)用 以及百度云盤文件識(shí)別運(yùn)用
搜索引擎的拆詞搜索 && 詞庫
無論搜索 Apple Blue Sky
,還是搜索Sky Blue Apple
,得到的返回結(jié)果是一樣的。
原理
先計(jì)算各個(gè)單詞的MD5
- MD5 ("Apple") = 9f6290f4436e5a2351f12e03b6433c3c
- MD5 ("Blue") = 9594eec95be70e7b1710f730fdda33d9
- MD5 ("Sky") = 03462a41aec357b74c89eb8d272532f7
然后再對MD5值進(jìn)行按位相加砂豌,得到的結(jié)果是一樣的厢岂。
再去搜索匹配結(jié)果的數(shù)據(jù)。
散列碰撞:兩個(gè)不同的數(shù)據(jù)阳距,哈希之后塔粒,得到相同的哈希值!
從理論的角度出發(fā)筐摘,有無限個(gè)碰撞可能卒茬!
MD5 32為字符晴弃,它能表達(dá)的數(shù)據(jù)個(gè)數(shù)是有限的玉转,而被加密的數(shù)據(jù)是無限個(gè)削咆。
其他使用場景
通過數(shù)據(jù)的散列值绢彤,判斷數(shù)據(jù)是否相等,保存云盤數(shù)據(jù)(相同的數(shù)據(jù)在云上保存一份)去团。
正版軟件使用哈希進(jìn)行文件識(shí)別更振。
對下載后的軟件安裝版進(jìn)行 MD5 校驗(yàn)宙帝,判斷安裝包是否被污染咽斧。