iOS中加密、解密

weixin_33890499發表於2017-11-09

(大家可以關注我的部落格,有的文章還沒來得及移過來的flyoceanfish部落格傳送門)

對稱加密

無狀態加密

#import <CommonCrypto/CommonCrypto.h>

分組密碼(塊加密)即是無狀態加密,加密之後除了密文其他資訊都會丟失

#import <CommonCrypto/CommonCrypto.h>

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>)

有狀態加密

#import <CommonCrypto/CommonCrypto.h>

流密碼主要用於大型或流式集合這些難以一次性加密的情況,操作速度快。流密碼稱為有狀態加密,因為他們
知道加密處理的位置

  • 建立CCCryptor、CCCryptorRef

    CCCryptorRef 貫穿於整個加密過程,所以有狀態其實也是主要因為這個引數

CCCryptorCreate(CCOperation op,
                CCAlgorithm alg,    
                CCOptions options,
                const void *key,
                size_t keyLength,
                const void *iv,
                CCCryptorRef *cryptorRef)
  • 獲取輸出資料的最大長度
size_t CCCryptorGetOutputLength(
    CCCryptorRef cryptorRef,
    size_t inputLength,
    bool final)
  • 加密處理update寫入快取區
CCCryptorUpdate(CCCryptorRef cryptorRef,
                const void *dataIn,
                size_t dataInLength,
                void *dataOut,
                size_t dataOutAvailable,
                size_t *dataOutMoved)

  • 重新整理所有資料,所有輸出被寫入
CCCryptorFinal(CCCryptorRef cryptorRef,
   void *dataOut,
    size_t dataOutAvailable,
     size_t *dataOutMoved)
  • 釋放
CCCryptorStatus CCCryptorRelease(
    CCCryptorRef cryptorRef)

主祕鑰加密

KDF(key derivation function) 祕鑰生成函式

目前常見的不可逆加密演算法有以下幾種:

  • 一次MD5(使用率很高)
  • 將密碼與一個隨機串進行一次MD5
  • 兩次MD5,使用一個隨機字串與密碼的md5值再進行一次md5,使用很廣泛
  • PBKDF2演算法
  • bcrypt

PBKDF2簡單而言就是將salted hash進行多次重複計算,這個次數是可選擇的。如果計算一次所需要的時間是1微秒,那麼計算1百萬次就需要1秒鐘。假如攻擊一個密碼所需的rainbow table有1千萬條,建立所對應的rainbow table所需要的時間就是115天。這個代價足以讓大部分的攻擊者忘而生畏。

#import <CommonCrypto/CommonKeyDerivation.h>

- (NSData*)generateSalt256 {
    unsigned char salt[32];
    for (int i=0; i<32; i++) {
        salt[i] = (unsigned char)arc4random();
    }
    return [NSData dataWithBytes:salt length:32];
}

...

// Make keys!
NSString* myPass = @"MyPassword1234";
NSData* myPassData = [myPass dataUsingEncoding:NSUTF8StringEncoding];
NSData* salt = [self generateSalt256];

// How many rounds to use so that it takes 0.1s ?
int rounds = CCCalibratePBKDF(kCCPBKDF2, myPassData.length, salt.length, kCCPRFHmacAlgSHA256, 32, 100);

// Open CommonKeyDerivation.h for help
unsigned char key[32];
CCKeyDerivationPBKDF(kCCPBKDF2, myPassData.bytes, myPassData.length, salt.bytes, salt.length, kCCPRFHmacAlgSHA256, rounds, key, 32);

地理位置加密

通過經緯度與PBKDF2結合,大大增加了安全性,降低了破解可能性

拆分伺服器祕鑰

一半口令儲存在使用者裝置上,另一半儲存到伺服器上,只有同時用這兩個祕鑰才能解密

記憶體安全

  • NSData記憶體清除

memset([myData bytes],0,[myData length])

  • NSString記憶體清除

由於NSString物件我們使用時都是資料的一個副本,所以用CFStringGetCStringPtr函式獲取資料指標,以此用來清除

unsigned char *text = (unsigned char *)CFStringGetCStringPtr((CFStringRef)myString,
CFStringGetSystemEncoding());
memset(text, 0, [myString length]);
NSLog(@"%s",[myString UTF8String]);

公鑰加密體系(非對稱加密)

Security.framework

只支援從標準證書檔案(cer, crt)中讀取公鑰

RSA

//生成公鑰和私鑰的方法
OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey,
SecKeyRef *privateKey) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);

//加密方法
OSStatus SecKeyEncrypt(
    SecKeyRef           key,
    SecPadding          padding,
    const uint8_t      *plainText,
    size_t              plainTextLen,
    uint8_t             *cipherText,
    size_t              *cipherTextLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);

//解密方法
OSStatus SecKeyDecrypt(
     SecKeyRef   key,    /* Private key */
     SecPadding  padding,   /*kSecPaddingNone,kSecPaddingPKCS1,kSecPaddingOAEP */
     const uint8_t  *cipherText,
     size_t  cipherTextLen,     /* length of cipherText */
     uint8_t *plainText,
     size_t  *plainTextLen)     /* IN/OUT */
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);

相關文章