| 三大類加密算法 | 算法特點(diǎn) | 代表的算法 |
|---|---|---|
| 哈希(散列函數(shù))算法 | 1. 算法公開 2. 對(duì)不同數(shù)據(jù)加密結(jié)果是定長(zhǎng)的32位字符 3. 加密之后的數(shù)據(jù)是不可逆的 |
MD5 SHA256/512 HMAC |
| 對(duì)稱加密算法 | 1. 加密后可逆 2. 加密和解密使用同一個(gè)“密鑰”(密鑰的保密工作非常重要,密鑰一般會(huì)定期換,密鑰管理非常麻煩) 3. 加密效率高 |
DES 3DES AES |
| 非對(duì)稱加密算法 | 1. 加密后可逆 2. 公鑰和私鑰(使用公鑰加密,私鑰解密;使用私鑰加密,公鑰解密) 3. 純數(shù)學(xué)運(yùn)算,加密效率非常低 |
RSA |
| 對(duì)稱加密算法的兩種加密方式 | 描述 |
|---|---|
| ECB | 電子代碼本,就是說(shuō)每一個(gè)數(shù)據(jù)塊都是獨(dú)立加密的 |
| CBC | 密碼塊鏈,使用一個(gè)密鑰和一個(gè)“初始化向量(IV)”對(duì)數(shù)據(jù)執(zhí)行加密轉(zhuǎn)換,每一個(gè)數(shù)據(jù)塊的加密都與上一個(gè)數(shù)據(jù)塊有關(guān)聯(lián) 如果在傳輸數(shù)據(jù)的過程中,一個(gè)數(shù)據(jù)塊被破壞了,那么整個(gè)數(shù)據(jù)都沒法解密了 |
| 加密算法 | 應(yīng)用場(chǎng)景 |
|---|---|
| MD5 | 1. 一般用來(lái)做密碼加密 2. 版權(quán)問題(對(duì)比文件MD5值 ) 3. 搜索引擎(搜索iOS 密碼學(xué) 與 密碼學(xué) iOS結(jié)果是一樣的,原因:取MD5值,按位相加) 4. 百度云&360云盤秒傳(對(duì)比文件MD5值) |
| DES | 數(shù)據(jù)加密標(biāo)準(zhǔn)(用的少,因?yàn)閺?qiáng)度不夠) |
| 3DES | 使用3個(gè)密鑰,對(duì)相同的數(shù)據(jù)執(zhí)行3次加密,強(qiáng)度增強(qiáng)(更加用的少) |
| AES | 高級(jí)加密標(biāo)準(zhǔn),目前美國(guó)國(guó)家安全局使用的就是AES(用的少,因?yàn)閺?qiáng)度不夠) |
一、數(shù)據(jù)加密方法
以前對(duì)于用戶密碼一般使用MD5進(jìn)行加密,但是現(xiàn)在單獨(dú)使用MD5對(duì)用戶密碼加密已經(jīng)不安全了!
現(xiàn)在的解決方案:
1. 加鹽處理(可以保證MD5不被輕易的破解) — 早期的使用!
( 密碼 + 鹽 ) . md5
鹽:靜態(tài)字符串。一定要足夠復(fù)雜,足夠長(zhǎng)!如:
static NSString *salt = @“SOFILKSFK92832349472JLF;p]qi3323hoos+_)(*^%’’//?adsofu8 {}SKDFJ@#%*(((&OKDKkdjfdjkdj”;
其實(shí)這種方法也不是足夠安全,它有一個(gè)最大的弊端。鹽:是固定寫死的。寫死在程序里面的。一旦鹽泄漏,就不安全了!
2. HMAC 用一個(gè)密鑰加密,然后做兩次散列!-- 安全的做法!
pwd = [pwd hmacMD5StringWithKey:@“從服務(wù)器獲取的key”]; //每一個(gè)賬號(hào)對(duì)應(yīng)著不同的key!
這個(gè)key是密鑰!這個(gè)密鑰是從服務(wù)器獲取的!
HMAC加密關(guān)鍵點(diǎn)在于key(密鑰)。它是怎么產(chǎn)生的,又是什么時(shí)候產(chǎn)生的呢?
注:第一次的第一個(gè)密鑰來(lái)自于用戶注冊(cè)!
- 1)首先,客戶端給服務(wù)器發(fā)送一個(gè)賬號(hào)。
- 2)服務(wù)器拿到賬號(hào)后會(huì)保存該賬號(hào),并對(duì)應(yīng)著賬號(hào)生成一個(gè)Key(密鑰),緊接著服務(wù)器會(huì)把這個(gè)密鑰返回給客戶端。
- 3)客戶端得到Key(密鑰)后,會(huì)立刻將密鑰保存在本地。接著使用 HMAC & Key 對(duì)密碼進(jìn)行加密,將加密后的32位字符串再發(fā)送給服務(wù)器。
((密碼+key)).HMAC - 4)服務(wù)器將HMAC之后的密碼進(jìn)行保存。
以后的每一次登錄都需要走第3步對(duì)密碼(HMAC & Key)加密后發(fā)送服務(wù)器,服務(wù)器對(duì)密碼進(jìn)行驗(yàn)證。可以看出來(lái)保存在本地的 Key 很關(guān)鍵!如果沒有這個(gè) Key 用戶是不可能登錄成功的!所以可以把 Key 放入鑰匙串中,避免應(yīng)用刪除后,本地密鑰也被刪除!

那如果用戶換了新手機(jī)該怎么辦呢?
解決方案:
- 重新根據(jù)你的賬號(hào)發(fā)送給服務(wù)器,找服務(wù)器獲取一次Key。
- 客戶端拿到Key(密鑰)后,將密鑰保存在本地。接著使用 HMAC & Key 對(duì)密碼進(jìn)行加密,將加密后的32位字符串再發(fā)送給服務(wù)器。
- 服務(wù)器對(duì)密碼進(jìn)行驗(yàn)證。
這種加密方式有什么好處呢?
我們都知道QQ有一個(gè)設(shè)備鎖的功能。它的實(shí)現(xiàn)原理就是 HMAC 的實(shí)現(xiàn)原理!如果你在之前設(shè)置過設(shè)備鎖,那么服務(wù)器不會(huì)立刻把 Key(密鑰)給你,而是告訴你等待上一個(gè)設(shè)備進(jìn)行驗(yàn)證。如果你的上一個(gè)設(shè)備不允許,那么這個(gè) Key 是永遠(yuǎn)不會(huì)拿到的。
如果黑客攔截了你的請(qǐng)求,拿到了你的 HMAC 字符串,這樣就可以模仿你給服務(wù)器發(fā)送請(qǐng)求,從而獲取你的登錄權(quán)限。那我們?cè)撊绾伪WC用戶的安全呢?
最常用以及最有效的解決方案:
- 改第3步??蛻舳藢MAC加密后的密碼+年月日時(shí)分,然后整體md5加密。再發(fā)送給服務(wù)器。
(((密碼+key)).HMAC + “201805071622”).md5 - 服務(wù)器也通過此方法,比如
(((密碼+key)).HMAC + “201805071623”).md5后,得到的字符串與客戶端發(fā)送的進(jìn)行對(duì)比。如果對(duì)不上,服務(wù)器會(huì)立即換成上一分鐘的時(shí)間再次進(jìn)行對(duì)比。(((密碼+key)).HMAC + “201805071622”).md5這就是服務(wù)器的處理邏輯。
image.png
這樣可以保證,如果你發(fā)送網(wǎng)絡(luò)請(qǐng)求,中間的延時(shí)能夠有最少61秒的時(shí)間,這樣保證了正常的網(wǎng)絡(luò)請(qǐng)求發(fā)送。這樣的好處是如果一個(gè)黑客攔截了你的網(wǎng)絡(luò)請(qǐng)求,他必須務(wù)必在120秒之內(nèi)對(duì)其服務(wù)器進(jìn)行訪問。如果沒訪問,獲取的網(wǎng)絡(luò)請(qǐng)求的字符串就失效了。
這種方式的特點(diǎn):
- 只有分鐘沒有秒
- 做到每次加密的結(jié)果是不一樣的,加密的結(jié)果受時(shí)間的影響很大
很多公司都愿意把時(shí)間作為加密算法中的一個(gè)參數(shù),這樣保證了每一次加密結(jié)果都是不一樣的。而且保證了可以和服務(wù)器做一個(gè)合適的驗(yàn)證。
二、數(shù)字簽名原理
我們發(fā)送數(shù)據(jù)的時(shí)候,要保證數(shù)據(jù)在發(fā)送的過程中不能被篡改。所以就要求我們?cè)诎l(fā)送數(shù)據(jù)的時(shí)候,對(duì)數(shù)據(jù)數(shù)字簽名。

三、破解對(duì)稱加密算法的思路
iOS系統(tǒng)庫(kù)中定義了軟件開發(fā)中常用的加解密算法,接口為C語(yǔ)言形式。具體包括了以下幾個(gè)大類:
#include <CommonCrypto/CommonCryptor.h> //常用加解密算法
#include <CommonCrypto/CommonDigest.h> //摘要算法
#include <CommonCrypto/CommonHMAC.h>
#include <CommonCrypto/CommonKeyDerivation.h>
#include <CommonCrypto/CommonSymmetricKeywrap.h>
其中第一類常用加解密算法包含了AES、DES和已經(jīng)廢棄的RC4。第二類摘要算法包括如MD5、SHA等。
CCCrypt(<#CCOperation op#>, <#CCAlgorithm alg#>, <#CCOptions options#>, <#const void *key#>, <#size_t keyLength#>, <#const void *iv#>, <#const void *dataIn#>, <#size_t dataInLength#>, <#void *dataOut#>, <#size_t dataOutAvailable#>, <#size_t *dataOutMoved#>);
CC_MD5(<#const void *data#>, <#CC_LONG len#>, <#unsigned char *md#>);
CC_SHA256(<#const void *data#>, <#CC_LONG len#>, <#unsigned char *md#>):
像上面這些公開加密算法的函數(shù),都是系統(tǒng)的函數(shù)。既然是系統(tǒng)的函數(shù),那么 fishhook 就能夠 HOOK 住。
調(diào)用系統(tǒng)加密函數(shù)
1. 以前的做法
一般像 RSA 公鑰,這種非常重要核心的數(shù)據(jù),你一般會(huì)采取什么方式保存在本地呢?很多人可能會(huì)使用鑰匙串訪問,因?yàn)殍€匙串訪問在本地,所以會(huì)感覺很安全。
但是,鑰匙串訪問也是調(diào)用的方法,一樣傳遞的參數(shù)。與對(duì)稱加密算法 CCCrypt 一樣,鑰匙串訪問也是調(diào)用的系統(tǒng)函數(shù),所以我們一樣可以 HOOK。
假如:我們有一個(gè) RSA 公鑰,一個(gè)明文A。當(dāng)我們調(diào)用 CCCrypt() 函數(shù)的時(shí)候,我們會(huì)把明文A參數(shù)傳進(jìn)去,然后進(jìn)行加密,生成一個(gè)密文B。對(duì)于一個(gè)黑客來(lái)說(shuō),他沒必要對(duì)密文B進(jìn)行破解。他只需要 HOOK CCCrypt() 函數(shù),拿到明文A。所以,我們要注意,在調(diào)用系統(tǒng)加密函數(shù)的時(shí)候,不要直接把核心數(shù)據(jù)丟進(jìn)去。
2. 今后的做法
采取封裝的形式!
- 自定義一個(gè)函數(shù),把明文A異或鹽(從服務(wù)器請(qǐng)求或本地存儲(chǔ)的都行,一個(gè)賬號(hào)一個(gè)鹽),得到密文B
- 把密文B丟給系統(tǒng)的加密算法,等到密文C
- 把密文C傳給服務(wù)器
注:第1步中可以函數(shù)中再調(diào)函數(shù),一層層加密。這樣就加大了黑客解密的難度。
解密過程
解密:
- 密文C調(diào)用系統(tǒng)的解密算法,得到密文B
- 密文B同樣異或鹽,得到明文A
黑客也很難得到你的明文
作為黑客,由于他不知道你的邏輯,所以他想得到你的明文A是比較困難的。
- 首先,他會(huì)去 HOOK 系統(tǒng)的加密算法的函數(shù),一個(gè)函數(shù)一個(gè)函數(shù)去 HOOK。
- 當(dāng)他 HOOK 到之后,發(fā)現(xiàn)你調(diào)用了加密算法的函數(shù),他會(huì)去看函數(shù)的返回值,對(duì)比這個(gè)函數(shù)的返回值(密文C)是不是你發(fā)給服務(wù)器的核心數(shù)據(jù)。
- 當(dāng)他發(fā)現(xiàn)兩者一樣的時(shí)候,他就會(huì)去解密(密文C)。當(dāng)他解密成功以為會(huì)拿到明文A,其實(shí)只是拿到了密文B,接下來(lái)他還需要把密文B解密。而這個(gè)過程,對(duì)我來(lái)說(shuō),我知道邏輯很好做,但是對(duì)于黑客來(lái)說(shuō),他只能去猜。是不是 HOOK 出了問題?是不是 HOOK 的方法出了問題?他就會(huì)這樣一直懷疑,這樣他想真正通過分析找到封裝的函數(shù)的機(jī)率就非常低了。
