前言:
在我們開發(fā)中免不了和服務器做一些數(shù)據(jù)交互,在交互過程中走得都是http請求骑歹,這類請求不像https那樣的安全所以就會在交互過程中做一些數(shù)據(jù)加密解密的事情预烙,現(xiàn)在主流的加密是AES對稱加密和RSA非對稱加密下面給大家講解下AES加密,非對稱加密會過幾天跟新道媚。
AES加密介紹:
- AES加密是一種對稱加密方式扁掸,他有基本的五種加密模式組成分別是:
1.電碼本模式(Electronic Codebook Book (ECB));
2.密碼分組鏈接模式(Cipher Block Chaining (CBC))最域;
3.計算器模式(Counter (CTR))谴分;
4.密碼反饋模式(Cipher FeedBack (CFB));
5.輸出反饋模式(Output FeedBack (OFB))
- 以上所說的這五種加密模式我們講最常用的CBC模式镀脂,下面我說一下實現(xiàn)AES對稱加密(CBC)的基本步驟;
1.要加密的密文轉(zhuǎn)為NSData類型
2.使用AES對稱加密(CBC)加密NSData
3.之后對加密過后的NSData進行編碼(編碼在下面我會說到)
AES加密代碼實現(xiàn):
新建SecurityUtil繼承NSObject
SecurityUtil.h實現(xiàn):
#pragma mark - AES加密
//將string轉(zhuǎn)成帶密碼的data
+ (NSString*)encryptAESData:(NSString*)string Withkey:(NSString * )key ivkey:(NSString * )ivkey;
//將帶密碼的data轉(zhuǎn)成string
+(NSString*)decryptAESData:(NSString*)data Withkey:(NSString *)key ivkey:(NSString * )ivkey;
SecurityUtil.m實現(xiàn)(加密部分):
#pragma mark - AES加密
//將string轉(zhuǎn)成帶密碼的data
+(NSString*)encryptAESData:(NSString*)string Withkey:(NSString *)key ivkey:(NSString *)ivkey
{
//將nsstring轉(zhuǎn)化為nsdata
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
//使用密碼對nsdata進行加密
NSData *encryptedData = [data AES128EncryptWithKey:key ivKey:ivkey];
//加密之后編碼
return [self dataTohexString:encryptedData];;
}
#pragma mark - AES解密
//將帶密碼的data轉(zhuǎn)成string
+(NSString*)decryptAESData:(NSString*)string Withkey:(NSString *)key ivkey:(NSString *)ivkey
{
//對數(shù)據(jù)進行解密
NSData* result = [[self hexStringToData:string] AES128DecryptWithKey:key ivkey:ivkey];
if (result && result.length > 0) {
//加密之后進行編碼
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
return nil;
}
SecurityUtil.m實現(xiàn)(編碼部分):
#pragma mark - 16位編碼 -加密
+ (NSString *)dataTohexString:(NSData*)data
{
Byte *bytes = (Byte *)[data bytes];
NSString *hexStr=@"";
for(int i=0;i<[data length];i++)
{
NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];//16進制數(shù)
if([newHexStr length]==1)
hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
else
hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
}
return hexStr;
}
#pragma mark - 16位編碼 -解密
+ (NSData*)hexStringToData:(NSString*)hexString
{
int j=0;
Byte bytes[hexString.length]; ///3ds key的Byte 數(shù)組牺蹄, 128位
for(int i=0;i<[hexString length];i++)
{
int int_ch; /// 兩位16進制數(shù)轉(zhuǎn)化后的10進制數(shù)
unichar hex_char1 = [hexString characterAtIndex:i]; ////兩位16進制數(shù)中的第一位(高位*16)
int int_ch1;
if(hex_char1 >= '0' && hex_char1 <='9')
int_ch1 = (hex_char1-48)*16; //// 0 的Ascll - 48
else if(hex_char1 >= 'A' && hex_char1 <='F')
int_ch1 = (hex_char1-55)*16; //// A 的Ascll - 65
else
int_ch1 = (hex_char1-87)*16; //// a 的Ascll - 97
i++;
unichar hex_char2 = [hexString characterAtIndex:i]; ///兩位16進制數(shù)中的第二位(低位)
int int_ch2;
if(hex_char2 >= '0' && hex_char2 <='9')
int_ch2 = (hex_char2-48); //// 0 的Ascll - 48
else if(hex_char1 >= 'A' && hex_char1 <='F')
int_ch2 = hex_char2-55; //// A 的Ascll - 65
else
int_ch2 = hex_char2-87; //// a 的Ascll - 97
int_ch = int_ch1+int_ch2;
//NSLog(@"int_ch=%x",int_ch);
bytes[j] = int_ch; ///將轉(zhuǎn)化后的數(shù)放入Byte數(shù)組里
j++;
}
// NSData *newData = [[NSData alloc] initWithBytes:bytes length:j];
NSData *newData = [[NSData alloc] initWithBytes:bytes length:j];
//NSLog(@"newData=%@",newData);
return newData;
}
新建一個NSData的擴展咋們把他命名為AES
NSData+AES.h實現(xiàn):
@class NSString;
@interface NSData (Encryption)
- (NSData *)AES128EncryptWithKey:(NSString *) key ivKey:(NSString *)ivkey;//加密
- (NSData *)AES128DecryptWithKey:(NSString *) key ivkey:(NSString * )ivkey;//解密
NSData+AES.m實現(xiàn):
//(key和iv向量這里是16位的) 這里是CBC加密模式,安全性更高
//加密
- (NSData *)AES128EncryptWithKey:(NSString *) key ivKey:(NSString *)ivkey{
char keyPtr[kCCKeySizeAES256+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,
kCCOptionPKCS7Padding ,
keyPtr, kCCBlockSizeAES128,
[ivkey UTF8String],
[self bytes], dataLength,
buffer, bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
//解密
- (NSData *)AES128DecryptWithKey:(NSString *) key ivkey:(NSString *)ivkey {
char keyPtr[kCCKeySizeAES256+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
kCCOptionPKCS7Padding ,
keyPtr, kCCBlockSizeAES128,
[ivkey UTF8String],
[self bytes], dataLength,
buffer, bufferSize,
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer);
return nil;
}
- 試驗調(diào)用一下:
NSString *originalString = @"加密這個字符串";
NSString * secretStr = @"秘鑰是這個";
//CBC加密字符串
NSString * encryptCBC = [SecurityUtil encryptAESData: originalString Withkey:uuid ivkey: secretStr];
//CBC解密字符串
NSString * decryptCBC = [SecurityUtil decryptAESData: encryptCBC Withkey:uuid ivkey: secretStr];
- AES加密(CBC)全部實現(xiàn)我們已經(jīng)做好了下面我講一下編碼;
編碼有很多種在我的項目中我們采用了16位編碼薄翅,為什么說我要采用16位編碼這又要講到Base64編碼沙兰,首先我先給大家看下這倆種編碼后的密文是什么樣子的氓奈。。
Base64編碼:
BsDhzys9BkPbfuMUK4SDpSqh47FMMNltY6huj/lMwI77ibB61Wk9eBMMzQRmNgVvmnbTpWKNUdS2XXKgfwuEyGjJC7uUSkoTuV/TFN+BEFv3vlL0UKeY1Jt8plcJzrDKyDxK0oQOiM9THr5ZTFOsdDGfM3cmGWf7KRTQFwYE=
16位編碼:
06C0E1CF2B3D0643DB7EE3142B8483A52AA1E3B14C33FA21365B58EA1BA3FE533023BEE26C1EB55A4F5E04C33341198D815BE69DB4E958A354752D975CA81FC2E1321A3242EEE5129284EE57F4C537E04416FDEF94BD1429E63526DF2995C273AC32B20F12B4A103A233D4C7AF965314EB1D0C67CCDDC98659FECA453405C181
大家也看到了倆種編碼之后的密文明顯的不同之處鼎天,Base64的唯一缺點就是其中有很多的特殊符號這種特殊符號在http傳送過程中會發(fā)生改變導致密文解碼解不了舀奶,所以我就采用了16位編碼避免這種事情的發(fā)生。