iOS 對稱加密 DES,3DES,AES128,AES256

前言

最近開發(fā)的功能需要用對網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)進(jìn)行加密不傅,因此調(diào)研了常用了對稱加密DES3DES搁骑,AES128AES256又固。做了如下的整理仲器。

加解密的黑盒過程

現(xiàn)在我們就是需要把plainString變成cipherString

加解密

DES/3DES加解密過程

DES/3DES加解密過程
  1. DES加密過程有一步是把加密后的data數(shù)據(jù)先轉(zhuǎn)場Base64data數(shù)據(jù),然后進(jìn)行UTF8轉(zhuǎn)化
  2. cipherString直接通過Base64轉(zhuǎn)成cipherData

AES128/AES256加解密過程

AES128/AES256加解密過程
  1. AES的加密和解密過程是對稱的
  2. 在轉(zhuǎn)化成字符串的時候口予,需要選擇Base64還是Hex轉(zhuǎn)化

DES/3DES 實現(xiàn)代碼

KSAdEncryptionDES

- (NSString *)encrypt:(NSString *)plainString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString {
    [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"des encrypt"];
    if (plainString == nil) {
        return nil;
    }
    NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
    size_t bufferPtrSize = (plainData.length + kCCBlockSizeDES);
    unsigned char *buffer = (unsigned char *)malloc(bufferPtrSize);
    memset(buffer, 0, bufferPtrSize);
    size_t numBytesEncrypted = 0;
    const void *initializationVector = [self initializationVectorWithString:initializationVectorString];
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding, [key UTF8String], kCCKeySizeDES, initializationVector, plainData.bytes, plainData.length, buffer, bufferPtrSize, &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *cipherData = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)numBytesEncrypted];
        NSData *base64Data = [cipherData base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
        NSString *cipherString = [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
        return cipherString;
    }
    free(buffer);
    return nil;
}
- (NSString *)decrypt:(NSString *)cipherString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString {
    [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"des decrypt"];
    if (cipherString == nil) {
        return nil;
    }
    NSData *cipherData = [[NSData alloc] initWithBase64EncodedString:cipherString options:NSDataBase64DecodingIgnoreUnknownCharacters];
    size_t bufferPtrSize = (cipherData.length + kCCBlockSizeDES);
    unsigned char *buffer = (unsigned char *)malloc(bufferPtrSize);
    memset(buffer, 0, bufferPtrSize);
    size_t numBytesDecrypted = 0;
    const void *initializationVector = [self initializationVectorWithString:initializationVectorString];
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding, [key UTF8String], kCCKeySizeDES, initializationVector, cipherData.bytes, cipherData.length, buffer, bufferPtrSize, &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *plainData = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)numBytesDecrypted];
        NSString *plainText = [[NSString alloc] initWithData:plainData encoding:NSUTF8StringEncoding];
        return plainText;
    }
    free(buffer);
    return nil;
}

加密過程:

  1. plainString 通過UTF8變成plainData
  2. plainData 通過DES轉(zhuǎn)化為cipherData
  3. cipherData 通過Base64轉(zhuǎn)化為base64Data
  4. base64Data通過UTF8轉(zhuǎn)化為可讀的cipherString

解密過程

  1. cipherString 通過Base64變成cipherData
  2. cipherData 通過DES轉(zhuǎn)化為plainData
  3. plainData 通過UTF8轉(zhuǎn)化為plainString

注意:

  1. import <CommonCrypto/CommonCryptor.h>

  2. 如果是3DES娄周,那么把
    kCCBlockSizeDES->kCCBlockSize3DES
    kCCAlgorithmDES->kCCAlgorithm3DES
    kCCKeySize3DES->kCCKeySize3DES
  3. initializationVectorWithString:
- (const void *)initializationVectorWithString:(NSString *)string {
   if (string.length == 0) {
       return NULL;
   }
   NSData *initializationVectorData = [string dataUsingEncoding:NSUTF8StringEncoding];
   const void *initializationVector = initializationVectorData.bytes;
   return initializationVector;
}

NSData與NSString轉(zhuǎn)化

在先介紹AES128/AES256實現(xiàn)代碼之前沪停,先介紹兩種不常用的NSDataNSString轉(zhuǎn)化
直接上類和代碼:

typedef NS_ENUM(NSInteger, KSAdEncryptionDataStringEncoding) {
    KSAdEncryptionDataStringEncoding_Hex,
    KSAdEncryptionDataStringEncoding_Base64,
};

@interface KSAdEncryptionEncoding : NSObject


+ (instancetype)encryptionEncodingWithEncoding:(KSAdEncryptionDataStringEncoding)encoding;

- (NSString *)stringFromData:(NSData *)data;
- (NSData *)dataFromString:(NSString *)string;

@end

@implementation KSAdEncryptionEncoding

+ (instancetype)encryptionEncodingWithEncoding:(KSAdEncryptionDataStringEncoding)encoding {
    switch (encoding) {
        case KSAdEncryptionDataStringEncoding_Base64:
            return [KSAdEncryptionEncodingBase64 new];
        default:
            return [KSAdEncryptionEncodingHex new];
    }
}


- (NSString *)stringFromData:(NSData *)data {
    return nil;
}
- (NSData *)dataFromString:(NSString *)string {
    return nil;
}
@end

@implementation KSAdEncryptionEncodingBase64
- (NSString *)stringFromData:(NSData *)data {
    NSString *string = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return string;
}
- (NSData *)dataFromString:(NSString *)string {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters];
    return data;
}
@end
@implementation KSAdEncryptionEncodingHex
- (NSString *)stringFromData:(NSData *)data {
    Byte *bytes = (Byte *)[data bytes];
    NSString *string = @"";
    for (NSInteger i = 0; i<data.length; i++) {
        NSString *newHexStr = [NSString stringWithFormat:@"%x", bytes[i] & 0xff]; //16進(jìn)制數(shù)
        newHexStr = [newHexStr uppercaseString];
        if ([newHexStr length] == 1) {
            newHexStr = [NSString stringWithFormat:@"0%@",newHexStr];
        }
        string = [string stringByAppendingString:newHexStr];
    }
    return string;
}
- (NSData *)dataFromString:(NSString *)string {
    const char *ch = [[string lowercaseString] cStringUsingEncoding:NSUTF8StringEncoding];
    NSMutableData *data = [NSMutableData data];
    while (*ch) {
        if (*ch == ' ') {
            continue;
        }
        char byte = 0;
        if ('0' <= *ch && *ch <= '9') {
            byte = *ch - '0';
        } else if ('a' <= *ch && *ch <= 'f') {
            byte = *ch - 'a' + 10;
        } else if ('A' <= *ch && *ch <= 'F') {
            byte = *ch - 'A' + 10;
        }
        ch++;
        byte = byte << 4;
        if (*ch) {
            if ('0' <= *ch && *ch <= '9') {
                byte += *ch - '0';
            } else if ('a' <= *ch && *ch <= 'f') {
                byte += *ch - 'a' + 10;
            } else if('A' <= *ch && *ch <= 'F') {
                byte += *ch - 'A' + 10;
            }
            ch++;
        }
        [data appendBytes:&byte length:1];
    }
    return data;
}
@end

具體可以參考:iOS NSString與char *互相轉(zhuǎn)換

AES128/AES256 實現(xiàn)代碼

KSAdEncryptionAES128

- (NSString *)encrypt:(NSString *)plainString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString {
    [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"aes128 encrypt"];
    if (plainString == nil) {
        return nil;
    }
    NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
    size_t bufferSize = plainData.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesEncrypted = 0;
    const void *initializationVector = [self initializationVectorWithString:initializationVectorString];
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, [key UTF8String], kCCKeySizeAES128, initializationVector, plainData.bytes, plainData.length, buffer, bufferSize, &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *cipherData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        NSString *cipherText = [self.encryptionEncoding stringFromData:cipherData];
        return cipherText;
    }
    free(buffer);
    return nil;
}
- (NSString *)decrypt:(NSString *)cipherString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString {
    [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"aes128 decrypt"];
    if (cipherString == nil) {
        return nil;
    }
    NSData *cipherData = [self.encryptionEncoding dataFromString:cipherString];
    size_t bufferSize = cipherData.length + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    const void *initializationVector = [self initializationVectorWithString:initializationVectorString];
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, [key UTF8String], kCCKeySizeAES128, initializationVector, cipherData.bytes, cipherData.length, buffer, bufferSize, &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *plainData = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        NSString *plainText = [[NSString alloc] initWithData:plainData encoding:NSUTF8StringEncoding];
        return plainText;
    }
    free(buffer);
    return nil;
}

加密過程:

  1. plainString 通過UTF8變成plainData
  2. plainData 通過AES轉(zhuǎn)化為cipherData
  3. cipherData 通過Base64/Hex轉(zhuǎn)化為cipherString

解密過程

  1. cipherString 通過Base64/Hex變成cipherData
  2. cipherData 通過AES轉(zhuǎn)化為plainData
  3. plainData 通過UTF8轉(zhuǎn)化為plainString

注意:

如果是AES256煤辨,那么把
kCCBlockSizeAES128->kCCBlockSizeAES256
kCCAlgorithmAES128->kCCAlgorithmAES256
kCCKeySizeAES128->kCCKeySizeAES256

至此整個加解密就完成了木张。

補充众辨,使用工廠模式來創(chuàng)建加解密功能對象:

typedef NS_ENUM(NSInteger, KSAdEncryptionType) {
    KSAdEncryptionType_DES,
    KSAdEncryptionType_3DES,
    KSAdEncryptionType_AES128,
    KSAdEncryptionType_AES256,
};

@interface KSAdEncryption : NSObject
@property (nonatomic, readonly, strong) KSAdEncryptionEncoding *encryptionEncoding;
+ (instancetype)encryptionWithType:(KSAdEncryptionType)type encoding:(KSAdEncryptionDataStringEncoding)encoding;
- (NSString *)encrypt:(NSString *)plainString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString;
- (NSString *)decrypt:(NSString *)cipherString key:(NSString *)key initializationVectorString:(NSString *)initializationVectorString;
- (const void *)initializationVectorWithString:(NSString *)string;
@end

+ (instancetype)encryptionWithType:(KSAdEncryptionType)type encoding:(KSAdEncryptionDataStringEncoding)encoding {
    Class class = nil;
    switch (type) {
        case KSAdEncryptionType_DES:
            class = [KSAdEncryptionDES class];
            break;
        case KSAdEncryptionType_3DES:
            class = [KSAdEncryption3DES class];
            break;
        case KSAdEncryptionType_AES128:
            class = [KSAdEncryptionAES128 class];
            break;
        case KSAdEncryptionType_AES256:
        default:
            class = [KSAdEncryptionAES256 class];
            break;
    }
    KSAdEncryption *encryption = [class new];
    encryption.encryptionEncoding = [KSAdEncryptionEncoding encryptionEncodingWithEncoding:encoding];
    return encryption;
}

最后的測試代碼:

    NSString *plainString = @"abc我們123";
    NSString *key = @"123key我們";
//    key = @"12345678";
    key = @"我們看看快手了關(guān)鍵時刻了來快手見鬼了是就離開過樂扣樂扣結(jié)束觀看了";
    NSString *initializationVectorString = @"123456789";
    
    [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"plainString:%@ key:%@ initializationVectorString:%@", plainString, key, initializationVectorString];
    
    // des
    KSAdEncryption *desEncryption = [KSAdEncryption encryptionWithType:KSAdEncryptionType_DES encoding:KSAdEncryptionDataStringEncoding_Base64];
    
    NSString *cipherString = [desEncryption encrypt:plainString key:key initializationVectorString:initializationVectorString];
    NSString *plainFromCipherString = [desEncryption decrypt:cipherString key:key initializationVectorString:initializationVectorString];
    
    if ([plainFromCipherString isEqualToString:plainString]) {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption DES succeed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    } else {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption DES failed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    }
    // 3des
    KSAdEncryption *des3Encryption = [KSAdEncryption encryptionWithType:KSAdEncryptionType_3DES encoding:KSAdEncryptionDataStringEncoding_Base64];
    
    cipherString = [des3Encryption encrypt:plainString key:key initializationVectorString:initializationVectorString];
    plainFromCipherString = [des3Encryption decrypt:cipherString key:key initializationVectorString:initializationVectorString];
    
    if ([plainFromCipherString isEqualToString:plainString]) {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption 3DES succeed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    } else {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption 3DES failed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    }
    
    // aes128
    KSAdEncryption *aes128Encryption = [KSAdEncryption encryptionWithType:KSAdEncryptionType_AES128 encoding:KSAdEncryptionDataStringEncoding_Base64];
    
    cipherString = [aes128Encryption encrypt:plainString key:key initializationVectorString:initializationVectorString];
    plainFromCipherString = [aes128Encryption decrypt:cipherString key:key initializationVectorString:initializationVectorString];
    
    if ([plainFromCipherString isEqualToString:plainString]) {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption AES128 succeed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    } else {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption AES128 failed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    }
    
    // aes256
    KSAdEncryption *aes256Encryption = [KSAdEncryption encryptionWithType:KSAdEncryptionType_AES256 encoding:KSAdEncryptionDataStringEncoding_Base64];
    cipherString = [aes256Encryption encrypt:plainString key:key initializationVectorString:initializationVectorString];
    plainFromCipherString = [aes256Encryption decrypt:cipherString key:key initializationVectorString:initializationVectorString];
    if ([plainFromCipherString isEqualToString:plainString]) {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption AES256 succeed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    } else {
        [KSAdLogManager debugLogWithModule:KSAdLogModuleEncryption format:@"KSAdEncryption AES256 failed cipherString:%@ plainFromCipherString:%@", cipherString, plainFromCipherString];
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市舷礼,隨后出現(xiàn)的幾起案子鹃彻,更是在濱河造成了極大的恐慌,老刑警劉巖妻献,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛛株,死亡現(xiàn)場離奇詭異,居然都是意外死亡育拨,警方通過查閱死者的電腦和手機谨履,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熬丧,“玉大人笋粟,你說我怎么就攤上這事。” “怎么了害捕?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵绿淋,是天一觀的道長。 經(jīng)常有香客問我尝盼,道長吞滞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任东涡,我火速辦了婚禮冯吓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疮跑。我一直安慰自己组贺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布祖娘。 她就那樣靜靜地躺著失尖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渐苏。 梳的紋絲不亂的頭發(fā)上掀潮,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天,我揣著相機與錄音琼富,去河邊找鬼仪吧。 笑死,一個胖子當(dāng)著我的面吹牛鞠眉,可吹牛的內(nèi)容都是我干的薯鼠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼械蹋,長吁一口氣:“原來是場噩夢啊……” “哼出皇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哗戈,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤郊艘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后唯咬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纱注,經(jīng)...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年胆胰,在試婚紗的時候發(fā)現(xiàn)自己被綠了奈附。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡煮剧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情勉盅,我是刑警寧澤佑颇,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站草娜,受9級特大地震影響挑胸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宰闰,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一茬贵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧移袍,春花似錦解藻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至觅够,卻和暖如春胶背,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喘先。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工钳吟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人窘拯。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓红且,卻偏偏與公主長得像,于是被迫代替她去往敵國和親树枫。 傳聞我的和親對象是個殘疾皇子直焙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內(nèi)容