iOS學習——數據加密
在加密使用中,一種是散列函數(HASH),它最著名的特點就是不可逆性,我們無法通過加密出來的結果反向解密出內容,其最突出的代表就是MD5加密。MD5加密會無視內容大小,加密成一串32位字符串。面對其不可逆和無視內容大小特性,我們可以用它來做很多事情。
1.使用MD5做傳統的登陸密碼加密,服務器保留的並不是用戶的密碼明文,而是一串MD5加密過後的數據,僅僅用來做登陸驗證。當然,由於MD5加密後類似指紋的特性,即不同的數據加密結果不一樣,但是相同數據加密結果一直是相同的。一些網站可以通過保存加密後的數據與對應明文,來對照獲取到與加密數據相對應的明文輸入。面對這種情況,加密需要做一些改變,首先一種是,每個用戶註冊的時候為其生成相對應的鹽,這樣采用MD5+鹽的方式加密或者其它方式MD5(MD5)+鹽等其它方式,其內容就極其難以破解,並且也不會因為使用統一加鹽的方式導致人為泄漏。另外,針對抓包工具的橫行,防止被抓包後,黑客采用直接使用加密後的數據登陸,MD5加密後的數據可以加上時間再次加密上傳,一般可以采用分鐘作為單位,這樣服務器采用相同的加時間,當前時間和前後一分鐘進行驗證,這樣讓登陸賬號密文時效性足以驗證登陸而抓包者又難以使用。ps:再多的加密仍舊難以100%阻止登陸信息泄漏,因此在登陸就誕生了qq登陸這種驗證方式。當用戶設定好一臺手機作為本機,服務器會記錄對應的id,當在別處登陸的時候,首先會上傳賬號名,服務器根據賬號找到對應本機,並發出詢問信息,是否允許登陸,如果拒絕,登陸將無法執行,同意後,服務器才向登陸者發送允許登陸,然後再執行登陸操作。
2.使用MD5可以進行搜索功能,例如百度搜索引擎等,上面的數據無以計數,如何準確搜索到想要的數據,就可以將數據加密,利用這種類似指紋的特性,快速找到用戶想要的內容並展示。
3.MD5可以做的另外一個特性就是版權。譬如視頻,當作者發布在網上後,別人下載了,然後改掉信息重新發布,我們如何識別到誰是真正的發布者,就可以通過MD5來識別。作者上傳到網上後,原版並不會被發不出來,所有放出來給用戶下載觀看的都是網站處理過後的視頻,MD5的特性保證,任何一點不同都會加密出不同的MD5字符串,因此,別人下載再次上傳,對比下加密過後的MD5可以很明顯識別版權所有。
有不可逆加密,肯定也是有可逆加密的使用。對稱加密——傳統加密方式,都是采用明文——密鑰——密文,密文——密鑰——明文方式進行數據加解密。這種加密方式對密鑰的要求很高,而且要保證不會泄漏,一旦泄漏就會被破解加密,而且需要定期更換,密鑰使用得越舊越不安全。其最常用的加密算法是:DES、3DES、AES等,當然還有其它的方式,但就不一一贅述了。DES和3DES算法都是類似的,只不過DES加密強度太低,所以出現了使用三個密鑰進行三次DES算法這種方式,泄漏一個兩個密鑰毫無影響。而AES則是蘋果這邊最常見的加密方式,例如鑰匙串就是使用的AES進行加密。對稱加密算法有兩種加密方式:ECB和CBC,一個視頻數據可能非常大,一次加密不太現實,因此會將數據拆分開來,一塊一塊的單獨加密,這就是ECB的加密形式。而CBC,則是在ECB的基礎上加上一個向量,進行鏈式加密,只有加密完了第一個數據才加密第二個數據,並且,第一個數據的加密結果會成為第二個數據的加密密鑰,及時部分數據泄漏或被破解,仍然破解所有數據,因為不知道其處於鏈條的哪一部分。
- (NSString *)encryptString:(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; } // 設置輸出緩沖區 NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; size_t bufferSize = [data length] + self.blockSize; void *buffer = malloc(bufferSize); // 開始加密 size_t encryptedSize = 0; //CCCrypt 蘋果對稱加密核心算法 /**參數說明 1.加密或者解密 kCCEncrypt kCCDecrypt 2.加密方式:AES,DES,blowfish等等所有的對稱加密方式 3.ECB 或者CBC ECB:kCCOptionPKCS7Padding | kCCOptionECBMode CBC:kCCOptionPKCS7Padding 4.加密的密鑰 5.密鑰長度 6.向量 7.加密的數據 8.數據大小 9.密文內存地址 10.密文內存緩沖區大小 11.加密結果大小 */ 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(@"[錯誤] 加密失敗|狀態編碼: %d", cryptStatus); } return [result base64EncodedStringWithOptions:0]; }
ECB加密終端測試命令,加密:$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.txt -out msg1.bin;解密:$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.bin -out msg1.txt -d。CBC終端測試命令,加密:$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in a.txt -out msg1.bin 解密:$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in msg1.bin -out msg4.txt -d,文件查看命令$ xxd msg1.bin
對稱加密的對應面肯定就是非對稱加密(RSA)。這種加密方式采用了兩種密鑰,公鑰/私鑰。用公鑰加密,私鑰解密或者是私鑰加密,公鑰解密。其優點是非常之安全,就是采用大量的乘法運算得到一個加密結果,沒有密鑰用現在的手段基本無法解密。然後同樣因為其安全的加密方式帶來的後果是,加密非常緩慢,基本大數據不用想使用RSA加密。其加密原理就是:1.找到兩個“很大”的質數,P&Q,然後N = P*Q,M=(P-1)*(N-1),公鑰就是找到一個整數E與M互質,即除了1以外,沒有其他公約數,這個數可以很簡單,因為一般是對外公開使用。私鑰:找到一個整數D,使得E*D除以M余1;然後就是進行加密:(明文 ^E)%N等到密文,解密:(密文^D)%N 得到明文。一般數字簽名就可以用RSA,例如支付就需要使用RSA,其原理就是,將“支付金額”使用HASH得到“hash密文”,然後將“hash密文”使用RSA公鑰加密得到“數字簽名”,最後將數字簽名和“支付金額”發送給服務器。服務器將“支付金額”加密得到“hash密文”,並同時使用私鑰解密“數字簽名”得到“hash密文”,將兩個“hash密文”進行對比,正確就確認支付,這樣可以防止金額被篡改。
#pragma mark - 加密 & 解密數據 - (NSData *)encryptData:(NSData *)plainData { OSStatus sanityCheck = noErr; size_t cipherBufferSize = 0; size_t keyBufferSize = 0; NSAssert(plainData != nil, @"明文數據為空"); NSAssert(publicKeyRef != nil, @"公鑰為空"); NSData *cipher = nil; uint8_t *cipherBuffer = NULL; // 計算緩沖區大小 cipherBufferSize = SecKeyGetBlockSize(publicKeyRef); keyBufferSize = [plainData length]; if (kTypeOfWrapPadding == kSecPaddingNone) { NSAssert(keyBufferSize <= cipherBufferSize, @"加密內容太大"); } else { NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密內容太大"); } // 分配緩沖區 cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t)); memset((void *)cipherBuffer, 0x0, cipherBufferSize); // 使用公鑰加密 sanityCheck = SecKeyEncrypt(publicKeyRef, kTypeOfWrapPadding, (const uint8_t *)[plainData bytes], keyBufferSize, cipherBuffer, &cipherBufferSize ); NSAssert(sanityCheck == noErr, @"加密錯誤,OSStatus == %d", sanityCheck); // 生成密文數據 cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize]; if (cipherBuffer) free(cipherBuffer); return cipher; }
iOS學習——數據加密