前言
最近开发的功能需要用对网络传输的数据进行加密,因此调研了常用了对称加密DES
,3DES
,AES128
,AES256
。做了如下的整理。
加解密的黑盒过程
现在我们就是需要把plainString
变成cipherString
DES/3DES加解密过程
DES
加密过程有一步是把加密后的data
数据先转场Base64
的data
数据,然后进行UTF8
转化cipherString
直接通过Base64
转成cipherData
AES128/AES256加解密过程
AES
的加密和解密过程是对称的- 在转化成字符串的时候,需要选择
Base64
还是Hex
转化
DES/3DES 实现代码
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;
}
加密过程:
plainString
通过UTF8
变成plainData
plainData
通过DES
转化为cipherData
cipherData
通过Base64
转化为base64Data
base64Data
通过UTF8
转化为可读的cipherString
解密过程
cipherString
通过Base64
变成cipherData
cipherData
通过DES
转化为plainData
plainData
通过UTF8
转化为plainString
注意:
import
- 如果是
3DES
,那么把
kCCBlockSizeDES
->kCCBlockSize3DES
kCCAlgorithmDES
->kCCAlgorithm3DES
kCCKeySize3DES
->kCCKeySize3DES
。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转化
在先介绍AES128/AES256
实现代码之前,先介绍两种不常用的NSData
与NSString
转化
直接上类和代码:
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
具体可以参考:iOS NSString与char *互相转换
AES128/AES256 实现代码
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;
}
加密过程:
plainString
通过UTF8
变成plainData
plainData
通过AES
转化为cipherData
cipherData
通过Base64/Hex
转化为cipherString
解密过程
cipherString
通过Base64/Hex
变成cipherData
cipherData
通过AES
转化为plainData
plainData
通过UTF8
转化为plainString
注意:
如果是
AES256
,那么把
kCCBlockSizeAES128
->kCCBlockSizeAES256
kCCAlgorithmAES128
->kCCAlgorithmAES256
kCCKeySizeAES128
->kCCKeySizeAES256
。
至此整个加解密就完成了。
补充,使用工厂模式来创建加解密功能对象:
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 = @"我们看看快手了关键时刻了来快手见鬼了是就离开过乐扣乐扣结束观看了";
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];
}