iOS逆向--加密算法
一、加密算法分類
1、Hash
算法是公開(kāi)的
對(duì)相同數(shù)據(jù)運(yùn)算,得到的結(jié)果是一樣的
對(duì)不同數(shù)據(jù)運(yùn)算,如MD5得到的結(jié)果默認(rèn)是128位,也就是32個(gè)字符(16進(jìn)制標(biāo)識(shí))
無(wú)法逆運(yùn)算
主要作為信息摘要,信息指紋,用來(lái)做數(shù)據(jù)識(shí)別的
用戶密碼的加密:因?yàn)闊o(wú)法還原,所以加密性很好,哪怕泄露了,也午飯逆向出用戶的真實(shí)密碼
搜索引擎
版權(quán)
數(shù)字簽名
直接使用MD5
MD5加鹽
HMAC加密方案
添點(diǎn)東西
網(wǎng)絡(luò)上不允許明文傳遞用戶的隱私信息
本地不允許明文保存用戶隱私信息
- (NSString *)md5String {
const char *str = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
//將字符串指針、字符串的長(zhǎng)度、以及密文存儲(chǔ)的空間傳進(jìn)去,空間一般是16位,加密后會(huì)把密文以16進(jìn)制形式放在待存儲(chǔ)的空間中,
CC_MD5(str, (CC_LONG)strlen(str), buffer);
//拿到密文后,我們將密文拼接起來(lái)就得到一個(gè)密文字符串
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
- (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
NSMutableString *strM = [NSMutableString string];
for (int i = 0; i < length; i++) {
[strM appendFormat:@"%02x", bytes[i]];
}
return [strM copy];
}
我們對(duì)123456進(jìn)行加密:就得到這樣一個(gè)十六進(jìn)制的字符串
e10adc3949ba59abbe56e057f20f883e
HMAC:
使用一個(gè)密鑰加密,并且做兩次散列
實(shí)際開(kāi)發(fā)中,密鑰來(lái)自于服務(wù)器,動(dòng)態(tài)的
一個(gè)賬號(hào)對(duì)應(yīng)一個(gè)key,而且還可以更新 我們?cè)谧?cè)或者換設(shè)備時(shí)候?qū)ey下發(fā)給客戶端,然后在本地緩存起來(lái),然后以后每次登陸時(shí)候從本地取出來(lái)對(duì)密碼進(jìn)行加密,這樣我們就可以加上一個(gè)設(shè)備鎖,當(dāng)換設(shè)備時(shí)候需要原來(lái)設(shè)備同意才能在新設(shè)備上登陸
#pragma mark - HMAC 散列函數(shù)
- (NSString *)hmacMD5StringWithKey:(NSString *)key {
const char *keyData = key.UTF8String;
const char *strData = self.UTF8String;
uint8_t buffer[CC_MD5_DIGEST_LENGTH];
CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);
return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
}
1、登錄之前先從服務(wù)器請(qǐng)求到服務(wù)器的時(shí)間戳time
2、然后在客戶端通過(guò)HMAC和key對(duì)密碼進(jìn)行加密得到密文1
3、將密文1拼接上時(shí)間戳再進(jìn)行一次HMAC和key的加密得到密文2
4、將密文2傳給服務(wù)器進(jìn)行校驗(yàn),服務(wù)器從本地取出用戶的密碼密文也就是密文1拼接上當(dāng)前時(shí)間戳后再進(jìn)行HMAC和key的加密跟客戶端傳過(guò)來(lái)的進(jìn)行匹配,相同則校驗(yàn)通過(guò)
如果不同,則將密文1和服務(wù)器時(shí)間戳的前一分鐘的時(shí)間戳拼接后在進(jìn)行匹配,相同則通過(guò),不同則返回密碼不正確
搜索引擎:
版權(quán):
數(shù)字簽名:
可以對(duì)支付的信息轉(zhuǎn)成MD5
在對(duì)MD5密文進(jìn)行RSA加密得到一個(gè)密文,這個(gè)就是數(shù)字簽名
傳遞給服務(wù)器后,服務(wù)器對(duì)密文進(jìn)行RSA解密得到MD5密文1,再對(duì)支付信息轉(zhuǎn)成MD5得到密文2,然后密文1和密文2進(jìn)行匹配,如果一樣,說(shuō)明支付信息沒(méi)有被修改
2、對(duì)稱加密:
DES:數(shù)據(jù)加密標(biāo)準(zhǔn)(用得少,因?yàn)閺?qiáng)度不夠)
3DES:用三個(gè)密鑰對(duì)相同數(shù)據(jù)執(zhí)行3次加密,強(qiáng)度增強(qiáng),但是有3個(gè)密鑰比較麻煩,所有用的比較少
AES:高級(jí)密碼標(biāo)準(zhǔn),鑰匙串訪問(wèn)就是使用這個(gè),F(xiàn)BI加密用的也是這個(gè)
ECB:電子密碼本模式,每一塊數(shù)據(jù)獨(dú)立加密。最基本的加密模式,也就是通常理解的加密,相同的明文將永遠(yuǎn)加密成相同的密文,無(wú)初始向量,因?yàn)槊恳粔K數(shù)據(jù)都是單獨(dú)的,所以容易受到密碼本重放攻擊,一般情況很少用
CBC:密碼分組鏈接模式,使用一個(gè)密鑰和一個(gè)初始化向量(IV)對(duì)數(shù)據(jù)執(zhí)行加密,明文被加密前要與前面的密文進(jìn)行異或或運(yùn)算后再加密,因此只要選擇不同的初始向量,相同的密碼加密后會(huì)形成不同的密文,這是目前應(yīng)用最廣泛的模式。CBC加密后的密文是上下文相關(guān)的,但明文的錯(cuò)誤不會(huì)傳遞到后續(xù)分組,但是如果一個(gè)分組丟失,后面的分組將全部作廢,也就是數(shù)據(jù)都是相關(guān)聯(lián)的,后面一塊數(shù)據(jù)的加解密依賴于前一塊數(shù)據(jù),如果其中一塊數(shù)據(jù)遭到破壞,那么整個(gè)數(shù)據(jù)都無(wú)法解析
CBC可以有效的保證密文的完整性,如果一個(gè)數(shù)據(jù)塊在傳遞時(shí)丟失或者改變了,后面的數(shù)據(jù)將無(wú)法正常解密
/**
* 終端測(cè)試指令
*
* 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)加密
* $ 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)解密
* $ 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
*
* 提示:
* 1> 加密過(guò)程是先加密,再base64編碼
* 2> 解密過(guò)程是先base64解碼,再解密
*/
加密代碼:
/** AES - ECB */
NSString * key = @"abc";
NSString * encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];
NSLog(@"加密的結(jié)果是:%@",encStr);
NSLog(@"解密的結(jié)果是:%@",[[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:nil]);
/** AES - CBC 加密 */
uint8_t iv[8] = {1,2,3,4,5,6,7,8};
NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSLog(@"CBC加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:@"abc" iv:ivData]);
NSLog(@"解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:key iv:ivData]);
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設(shè)置秘鑰
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設(shè)置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;
}
// 設(shè)置輸出緩沖區(qū)
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開(kāi)始加密
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(@"[錯(cuò)誤] 加密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [result base64EncodedStringWithOptions:0];
}
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設(shè)置秘鑰
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設(shè)置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加密!
}
// 設(shè)置輸出緩沖區(qū)
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開(kāi)始解密
size_t decryptedSize = 0;
/**CCCrypt 對(duì)稱加密算法的核心函數(shù)(加密/解密)
參數(shù):
1、kCCEncrypt 加密/kCCDecrypt 解密
2、加密算法、默認(rèn)的 AES/DES
3、加密方式的選項(xiàng)
kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密!
kCCOptionPKCS7Padding;//CBC 加密!
4、加密密鑰
5、密鑰長(zhǎng)度
6、iv 初始化向量,ECB 不需要指定
7、加密的數(shù)據(jù)
8、加密的數(shù)據(jù)長(zhǎng)度
9、緩沖區(qū)(地址),存放密文的
10、緩沖區(qū)的大小
11、加密結(jié)果大小
*/
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(@"[錯(cuò)誤] 解密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
3、加密算法存在的問(wèn)題
作者 | iOS_大書 鏈接 | 點(diǎn)擊左下方的 ‘’閱讀原文’’ 可進(jìn)入作者主頁(yè)
-End-
最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

面試題】即可獲取
