之前介紹了非對稱加密算法,這篇文章介紹一下在非對稱加密算法出現(xiàn)之前的對稱加密算法浪漠,常見的對稱加密算法、終端演示OpenSSL和iOS代碼運用以及CCCrypt的安全隱患等址愿。
對稱加密算法:明文通過密鑰加密得到密文,密文再通過這個密鑰解密得到明文响谓。所以在業(yè)務邏輯上相對沒有非對稱加密RSA的安全性高。
常見的對稱加密算法
- DES
數(shù)據(jù)加密標準娘纷,但由于強度不高,暴力破解難度不是很高赖晶,所以用的很少。 - 3DES
使用3個密鑰,對數(shù)據(jù)進行三次加密棉圈,強度增強。雖然強度相對DES有所提高分瘾,但是對稱加密算法密鑰的保存就很難吁系,3DES的3個密鑰更麻煩,所以3DES也沒有被廣泛使用汽纤。 - AES
高級密碼標準福荸,加密強度非常高,被廣泛使用敬锐,美國安全局和蘋果鑰匙串訪問都是用了AES加密算法。
常用的兩種加密模式
- ECB(Electronic Code Book):電子密碼本模式(每一塊數(shù)據(jù)獨立加密)
最基本的加密模式台夺,也就是通常理解的加密,相同的明文將永遠加密成相同的密文颤介,無初始向量,容易受到密碼本重放攻擊滚朵,一般情況下很少用。 - CBC(Cipher Block Chaining):密碼分組鏈接模式(使用一個密鑰和一個初始化向量[IV]對數(shù)據(jù)執(zhí)行加密始绍。每一塊數(shù)據(jù)加密都依賴上一塊數(shù)據(jù),有效的保證數(shù)據(jù)的完整性)
明文被加密前要與前面的密文進行異或運算后再加密学赛,因此只要選擇不同的初始向量,相同的密文加密后會形成不同的密文盏浇,這是目前應用最廣泛的模式。CBC加密后的密文是上下文相關的绢掰,但明文的錯誤不會傳遞到后續(xù)分組童擎,但如果一個分組丟失,后面的分組將全部作廢(同步錯誤)顾复。CBC可以有效的保證密文的完整性,如果一個數(shù)據(jù)塊在傳遞時丟失或改變芯砸,后面的數(shù)據(jù)將無法正常解密给梅。
當然了双揪,除了對稱加密和非對稱加密外,我們肯定還聽說過Hash
Hash概述
Hash:一般翻譯做“散列”渔期,也有直接音譯為“哈希”的擎场,就是把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值迅办。這種轉換是一種壓縮映射,也就是站欺,散列值的空間通常遠小于輸入的空間,不同的輸入可能會散列成相同的輸出矾策,所以不可能從散列值來確定唯一的輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數(shù)
之前介紹了RSA加密算法逃糟,在RSA算法之后也衍生出很多加密算法米诉,典型的算法就有HASH函數(shù)(也稱之為散列函數(shù)尖阔,嚴格意義上不算是加密算法,只不過是和加密一起用)互纯,還有在RSA出現(xiàn)之前的對稱加密算法檐蚜,這些算法都是公開的玩敏。
Hash特點
算法是公開的
相同的數(shù)據(jù)加密結果不變
不同的數(shù)據(jù)加密結果定長(MD5得到的結果默認是128位二進制,一般用16進制的32個字符來標識)
不可逆
信息摘要旺聚,信息“指紋”眶蕉,用來做數(shù)據(jù)識別的
HASH用途
密碼加密:服務器不需要知道用戶真實密碼,只需要匹配HASH值
搜索引擎
版權
數(shù)字簽名
OpenSSL演示ECB和CBC的區(qū)別
- OpenSSL演示ECB模式加密
// 先創(chuàng)建一個待加密的message.txt文件妻坝,編輯內容
$ vi message.txt
$ cat message.txt
Hello vincent!!!
// enc -des-ecb是對稱加密算法DES的ECB模式,-K是密鑰刽宪,616263就是ASCII碼“abc”,-nosalt不加鹽(OpenSSL默認會加鹽)圣拄,輸出msg.bin
$ openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg.bin
這時在文件夾內會多出一個加密過后的二進制文件msg.bin,修改message.txt文件的內容岳掐,再次進行加密
// 先修改message.txt的內容,vincent->Vincent
$ vi message.txt
$ cat message.txt
Hello Vincent!!!
// 再次對message.txt進行同樣的方式加密串述,輸出msg1.bin
$ openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg1.bin
// 查看下msg.bin和msg1.bin有什么不同
$ xxd msg.bin
00000000: 6d87 4097 d383 0bda a5bc d168 de16 688d m.@........h..h.
00000010: b8db 0794 f9ed eca9
$ xxd msg1.bin
00000000: 20e2 8361 50a7 16a0 a5bc d168 de16 688d ..aP......h..h.
00000010: b8db 0794 f9ed eca9
我們會發(fā)現(xiàn)寞肖,修改message.txt內容后ECB模式加密的結果只是修改部分不同,前后加密結果不變
- OpenSSL演示CBC模式加密
// 先編輯message.txt的內容
$ vi message.txt
$ cat message.txt
Hello vincent!!!
// 再次對message.txt進行CBC方式加密新蟆,相對ECB模式除了修改-des-cbc,還會多一個iv參數(shù)吮螺,iv是初始化向量,輸出msg2.bin
$ openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg2.bin
// 再次編輯message.txt的內容鸠补,vincent->Vincent
$ vi message.txt
$ cat message.txt
Hello Vincent!!!
// 對修改后的文件加密熊咽,輸出msg3.bin
$ openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg3.bin
// 查看下msg2.bin和msg3.bin有什么不同
$ xxd msg2.bin
00000000: d647 a33b 0389 dea5 3c81 02c9 ec05 44dd .G.;....<.....D.
00000010: 467c a581 ab1a 415a
$ xxd msg3.bin
00000000: 9882 c1b6 3186 b465 b3be d08a 5ad5 2fd1 ....1..e....Z./.
00000010: 6032 add7 bdb2 07da `2......
經多次測試發(fā)現(xiàn),修改message.txt內容后CBC模式加密的結果是修改部分不同以及后面的加密結果也會變化
- 終端測試指令
加密過程:先加密横殴,再base64編碼
解密過程:先base64解碼,再解密
// DES(ECB)加密
$ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
// DES(CBC)加密
$ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
// AES(ECB)加密 128位
$ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
// AES(CBC)加密
$ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
// DES(ECB)解密 base64 -D進行解碼成二進制 -d解密
$ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
// DES(CBC)解密
$ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
// AES(ECB)解密
$ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
// AES(CBC)解密
$ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
對稱加密算法代碼演示
// AES加密梨与、ECB模式對“hello vincent!!!”進行加密
NSString *ECBEncryptStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello vincent!!!" keyString:@"abc" iv:nil];
NSLog(@"%@", ECBEncryptStr);
// 解密
NSString *ECBDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:ECBEncryptStr keyString:@"abc" iv:nil];
NSLog(@"%@", ECBDecrypt);
// 一個數(shù)組文狱,和前面一樣有8個數(shù)據(jù)
uint8_t iv[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// 把數(shù)組包裝才二進制NSdata 把數(shù)組的指針和長度傳進去
NSData *ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
// AES加密、CBC模式
NSString *CBCEncryptStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello vincent!!!" keyString:@"abc" iv:ivData];
NSLog(@"%@", CBCEncryptStr);
// 解密
NSString *CBCDecrypt = [[EncryptionTools sharedEncryptionTools] decryptString:CBCEncryptStr keyString:@"abc" iv:ivData];
NSLog(@"%@", CBCDecrypt);
打印結果:
LzWe4b6VMKHECZTg5GEoDvOJyUo3lvcCucS987KliFw=
hello vincent!!!
Vo04z90TAfQX07onyrvCie1SnRpsbHKMkYnaNhcEPP0=
hello vincent!!!
雖然將加密和解密封裝成了兩個方法呻粹,但是蘋果內部加密和解密都是用的一個函數(shù)壕曼。先看下其中封裝的一個方法內部實現(xiàn)
// 加密字符串并返回base64編碼字符串
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設置秘鑰 將keyString轉成二進制
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設置iv
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
[iv getBytes:cIv length:self.blockSize];
option = kCCOptionPKCS7Padding; // CBC加密
} else {
option = kCCOptionPKCS7Padding | kCCOptionECBMode; // ECB加密
}
// 設置輸出緩沖區(qū) 將原始數(shù)據(jù)轉成二進制等浊,并根據(jù)所使用的加密方式設置緩沖區(qū)
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開始加密
size_t encryptedSize = 0;
//加密解密都是它 -- CCCrypt
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
} else {
free(buffer);
NSLog(@"[錯誤] 加密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [result base64EncodedStringWithOptions:0];
}
// 解密字符串
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設置秘鑰
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設置iv
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
[iv getBytes:cIv length:self.blockSize];
option = kCCOptionPKCS7Padding;
} else {
option = kCCOptionPKCS7Padding | kCCOptionECBMode;
}
// 設置輸出緩沖區(qū)
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開始解密
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&decryptedSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
free(buffer);
NSLog(@"[錯誤] 解密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
代碼已加入相應的注釋筹燕,就不解釋代碼了。我們會發(fā)現(xiàn)蘋果內部加密和解密都是用CCCryptorStatus 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)
撒踪,這個函數(shù)是對稱加密算法的核心函數(shù)。
WTF!!!11個參數(shù)掸绞,這么多,這都是干嘛的集漾?
參數(shù)意義
op:kCCEncrypt(加密)/ kCCDecrypt(解密)
alg:加密算法 kCCAlgorithmAES、kCCAlgorithmDES具篇、kCCAlgorithmBlowfish等等
options:加密方式 kCCOptionPKCS7Padding(CBC方式)/kCCOptionECBMode(ECB方式)
key:加密密鑰
keyLength:密鑰長度
iv:初始化向量 ECB不需要指定(CBC多了這個參數(shù)就相當于加鹽凌埂,加密強度更高了)
dataIn:加密的數(shù)據(jù)
dataInLength:加密數(shù)據(jù)的長度
dataOut:緩沖區(qū)(地址),存放密文
dataOutAvailable:緩沖區(qū)的大小
dataOutMoved:加密結果的大小
搞清楚每個參數(shù)的意義也就明白了瞳抓,蘋果這樣設計還是挺人性化的。對稱加密和解密所用的參數(shù)密鑰都是一樣的孩哑,所以加密和解密都是用同一個函數(shù)。蘋果的加密算法也都在CommonCrypto.h這個庫里面横蜒,這個庫并不在macho中,是在系統(tǒng)中丛晌,所以我們大多數(shù)會認為這個加密會很安全,但是事實上并不是這樣澎蛛。
CCCrypt函數(shù)安全隱患
現(xiàn)在我們已經使用CCCrypt對數(shù)據(jù)進行加密和解密了,接下來看下我們用CCCrypt加密的數(shù)據(jù)是否真的安全。下面的內容涉及到逆向開發(fā)桐经,可能有點跑偏浙滤,如果感興趣的小伙伴也可以進一步研究一下。
我們加密數(shù)據(jù)就是為了防止中間人攻擊瓷叫,假設如果別人拿到我們的APP送巡,別人肯定不會知道我們的源碼,也不知道在數(shù)據(jù)核心加密的地方是不是用的CCCrypt骗爆,這時別人會進行符號斷點,當然這個只要是沒有去符號摘投,或者系統(tǒng)的都是可以攔截到的。
前方高能P宜骸!外臂!
下了斷點后,我們繼續(xù)運行剛才的demo宋光,程序果斷進入斷點,接下來要讀寄存器了9渎!酌毡!
剛剛說過,CCCrypt第7個參數(shù)是我們加密的數(shù)據(jù)阔馋,所以在寄存器中X6(從X0開始)就是我們的加密數(shù)據(jù),我們在lldb中讀取X6的地址值呕寝,也就是指針,拿到X6的地址值是0x00000001c403ee00下梢,再p (char *)0x00000001c403ee00查看X6的值,回車D踅!岗屏!我們剛剛加密的數(shù)據(jù)顯示出來了,我們原以為很安全的手段就這樣被別人拿到了这刷!所以我們有很多核心的加密算法不能直接用。
那怎么防御呢暇屋?先想到去符號,前面也說了咐刨,這個庫是系統(tǒng)的,所以沒辦法去符號定鸟,當然自己實現(xiàn)或者三方庫,比如支付寶就是直接用的OpenSSL联予,可以去符號來避免被直接破解。最好的方式是加密之前不能直接使用關鍵數(shù)據(jù)躯泰,我們可以自己對關鍵數(shù)據(jù)處理一下比如異或,方法肯定不止一個麦向,如果各位有什么好的解決辦法歡迎交流。
后面可能會介紹下怎么隱藏函數(shù)調用诵竭,怎樣保護核心數(shù)據(jù),當然逆向大神還是很多的卵慰,這也僅僅是讓逆向變的更難而已。該文章為記錄本人的學習路程裳朋,希望能夠幫助大家,也歡迎大家點贊留言交流!0筝骸惕耕!http://www.reibang.com/p/a6fca79eb89c