密碼學概論
原則:
- 在網絡上不允許明文傳輸用戶隱私信息;
- 在本地不允許明文保存用戶隱私信息;
base64 編碼
base64 編碼:將二進制數據編碼成只有65個字符的文本文件(字符)!
base64 編碼包括的字符:0 ~9, a~z, A~Z, +/=
編碼后文件數據會比原有文件大1/3左右。
原理
base64 編碼:8位的二進制ASCII編碼 —> 6位的base64編碼
base64編碼表:
0~63,64個字符,還有 = 表示空格,總共65個字符。
示例:
Man 轉換為 base64 編碼:TWFu
M 的 ASCII編碼 十進制為 77 ,二進制為 01001101:
前6位二進制 010011 (十進制為19)在上面的base64編碼表中為 T 。
因此 M ? T 。
空格情況
因為是把8個字節轉換為6個字節進行編碼,勢必會產生位數不對應的問題。因此會使用 0 來補齊,用=表示全0的情況。(注意到base64 總會編碼補齊為4個字符一組)
因此,單獨的 M 用base64編碼 ? TQ==
Objective-C 代碼
// base64編碼
- (NSString *)base64Encode:(NSString *)string {
// 1.將字符串轉換為二進制
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
// 2.二進制數據進行編碼
return [data base64EncodedStringWithOptions:0];
}
// base64解碼
- (NSString *)base64Decode:(NSString *)string {
// 1.字符串轉換為二進制
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
// 2.解碼
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
哈希、對稱加密、非對稱加密
上世紀70年代開始 RSA — 非對稱加密算法
RSA — 非對稱加密算法
- 公鑰加密,私鑰解密;
- 私鑰加密,公鑰解密;
哈希(散列)函數
- MD5
- SHA1\SHA256\SHA512
- HMAC
對稱加密算法
- DES
- 3DES
- RC2、RC4
- AES(高級密碼標準,美國國家安全局使用、Apple 鑰匙串訪問使用、Lastpass 使用了256位的AES密鑰),以目前現階段計算機的運行效率,要暴力破解AES加密算法,需要上千萬年。
散列函數
算法都是公開的。
- 對相同的數據加密,得到的結果是一樣的。
- 對不同的數據加密,得到的結果是定長的。(比如MD5對不同的數據加密,得到32個字符)
- 加密之后的數據是沒法解密的。(不可逆運算)
MD5 哈希算法
GitHub源碼:jerilimov/NSHash——NSData、NSString 的分類,添加了MD5、SHA1、SHA256、SHA512 加密算法
NSString *pwd = @"123456";
pwd = [pwd MD5];
NSLog(@"MD5 = %@",pwd);
// MD5 = e10adc3949ba59abbe56e057f20f883e
像 MD5 這樣的加密算法是無法反向解密的,但是對相同的數據加密,得到的結果是一樣的。
于是 CMD5 利用散列函數的這種特性,將加密前的數據和加密后的數據進行映射保存,可以實現反向查詢。
將剛才 123456 加密后的 MD5 輸入,可以反向查詢出原始數據:
MD5加鹽:對數據先加鹽,再進行MD5加密,可以增加結果的復雜度
/* 鹽,足夠長,足夠復雜,足夠咸*/
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密碼放到該網站上進行查詢:
沒有查到,結果顯示,被反向查詢出來的難度就會加大。
缺點:鹽是固定的,如果鹽被泄露,數據就會不安全。
注:哈希算法&加密算法的區分
- MD5、HMAC、SHA 等所有的哈希算法嚴格上來說并不能稱之為加密算法,它只能說是密碼學中的哈希算法。
- 加密算法加密之后是可以解密的,而哈希算法無法反向解出原始數據。
- 哈希算法通常用于校驗數據的完整性,例如:校驗下載后的安裝包文件是否被篡改、刪減或植入惡意代碼。
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 用一個密鑰加密,并且做了兩次散列。
// 在實際的開發中,密鑰來自于服務器。——對應一個帳號,一個KEY
NSString *pwd = @"123456";
pwd = [pwd hmacMD5StringWithKey:@"Key"];
NSLog(@"MD5 = %@",pwd);
// MD5 = a7cac7471d2c9eb7a944e07d44d305ca
將此MD5密碼放到該網站上查詢也是查不到的。
項目實際使用流程:
- 服務器根據用戶帳號生成KEY,發送給客戶端;
- 客戶端獲得KEY并保存到本地,使用KEY對數據進行HMAC加密,將加密后的數據發送給服務器;
- 服務器對加密后對數據進行驗證。
客戶端登錄時,沒有KEY就先根據帳號從服務器獲取KEY保存到本地,再將獲得的KEY對密碼進行加密。
防止KEY泄露,對KEY進行非對稱加密、定期更換KEY。
QQ設備鎖:
- 本地有KEY——為授權手機。
- 本地沒有KEY,未授權設備,需要允許服務器發送KEY。允許一次登錄,本地不保存KEY,允許多次登錄,保存KEY到本地。
- 短信驗證碼登錄獲取KEY。
- 申訴獲取KEY。
HMAC加密+時間戳(不加秒)
之前:
驗證方式:HMAC密碼直接匹配是否正確。
現在:
客戶端:(HMAC密碼+“201711010358”).MD5校驗
服務器:
- (HMAC密碼+“201711010359”).MD5校驗
- (HMAC密碼+“201711010358”).MD5校驗
密碼驗證有效期最長2分鐘,超過2分鐘,驗證失敗。
有經驗的服務器人員,會在返回數據時,返回時間戳。
登錄等待時間,不要超過6秒!!!提示用戶:你的網絡不穩定,請稍后再試!
終端測試命令:
md5 -s "string" #這是 Apple 用的 openssl 標準進行的MD5加密
MD5使用場景,百度搜索引擎(拆詞搜索思路)運用 以及百度云盤文件識別運用
搜索引擎的拆詞搜索 && 詞庫
無論搜索 Apple Blue Sky
,還是搜索Sky Blue Apple
,得到的返回結果是一樣的。
原理
先計算各個單詞的MD5
- MD5 ("Apple") = 9f6290f4436e5a2351f12e03b6433c3c
- MD5 ("Blue") = 9594eec95be70e7b1710f730fdda33d9
- MD5 ("Sky") = 03462a41aec357b74c89eb8d272532f7
然后再對MD5值進行按位相加,得到的結果是一樣的。
再去搜索匹配結果的數據。
散列碰撞:兩個不同的數據,哈希之后,得到相同的哈希值!
從理論的角度出發,有無限個碰撞可能!
MD5 32為字符,它能表達的數據個數是有限的,而被加密的數據是無限個。
其他使用場景
通過數據的散列值,判斷數據是否相等,保存云盤數據(相同的數據在云上保存一份)。
正版軟件使用哈希進行文件識別。
對下載后的軟件安裝版進行 MD5 校驗,判斷安裝包是否被污染。