这几天项目要求做一个加密功能,采用的是 AES 加密,要求是 CBC 方式NoPadding。项目需求只有加密功能,所以这里没有对应的解密方法。不过照着加密的方法推导一下,结合网上的文章看一看,差不多也能写出来。
项目并没有用GTMBase64做转码,大致的流程是:
加密内容----转成 NSData ---- AES 加密并得到结果 ---- 把结果转成16进制传给后台 ---- 完事儿
首先需要的参数:
- key:移动端和后端约定的秘钥。
- ivValue:可选的初始化向量,我这方法里就没用到这个值。
- content:就是你需要加密的内容。
接下来是加密部分:
导入头文件#import <CommonCrypto/CommonCrypto.h>
代码
+ (NSString *)AES128Encrypt:(NSData *)plainText keyString:(NSString *)keyStr
{
// 这里的 plainText 是由需要加密的内容 string 转成 NSData 的,下面会详细说.
NSUInteger dataLength = [plainText length];
unsigned long diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
unsigned long newSize = 0;
if(diff > 0)
{
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [plainText bytes], [plainText length]);
for(int i = 0; i < diff; i++)
{
// 0x0000 代表 no padding
dataPtr[i + dataLength] = 0x0000;
}
size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
memset(buffer, 0, bufferSize);
size_t numBytesCrypted = 0;
// 这里的 byte 表示初始化向量,下面会详细说.
// Byte byte[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000, // 0x00 表示 no padding,其他的根据情况来选
[keyStr UTF8String], // keyPtr
kCCKeySizeAES128,
NULL, // 原本是初始化向量值,不过是可选的,所以用 NULL
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesCrypted);
if (cryptStatus == kCCSuccess) {
NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
// 将加密好的数据转成16进制的字符
return [self hexStringFromData:resultData];
}
free(buffer);
return nil;
}
+ (NSString *)hexStringFromData:(NSData *)data {
Byte *bytes = (Byte *)[data bytes];
// 下面是Byte 转换为16进制。
NSString *hexStr = @"";
for(int i=0; i<[data length]; i++) {
NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i] & 0xff]; //16进制数
newHexStr = [newHexStr uppercaseString];
if([newHexStr length] == 1) {
newHexStr = [NSString stringWithFormat:@"0%@",newHexStr];
}
hexStr = [hexStr stringByAppendingString:newHexStr];
}
return hexStr;
}
说明
- 这里说说上面代码里提到的 plainText。
项目里要求先把 content 转成 data,如果 data 的长度不足64位需要在末尾补0。所以原本是 string 类型的 plainText 在这儿就是 data 类型了,可以根据自己的需要改一下子就行。把代码放在下面,有需要的就用,没需要的就略过吧。 - 还有一个初始化向量,刚开始后台给了这个值,就是代码里那16个0x00的 byte 数组。但是后来发现这个向量值用不上,所以本文一开头儿也说了这玩意儿可选,看具体情况来吧。
- 最后把加密完的内容转成16进制也是项目需求,具体转不转不强求,只要后台能解密出来就行。
NSString *contStr = @"这是一个天大的秘密内容";
// 把内容转成 data
NSData *contData = [contStr dataUsingEncoding:NSUTF8StringEncoding];
// 创建一个64位的 byte 数组
//Byte *byteData = (Byte*)malloc(64); // 这样创建的数组在位数不够时好像并不会补0
Byte byteData[64] = {0};
// 得到转化成 data 的内容的 byte 数组
char *byteObj = (char *)[contData bytes];
// 把内容的 byte 遍历到新的 byte 数组里去
for (int i=0; i<contData.length; i++) {
byteData[i] = byteObj[i];
}
// 得到新的 data
// 这个 '48' 也是个不解的地方,为啥不是 64 呢?
NSData *encryptData = [[NSData alloc]initWithBytes:byteData length:48];
// 把新的 data 进行 AES 加密,并得到加密后的 string
NSString *aesStr = [AESEncrypt AES128Encrypt:encryptData keyString:gkey];
NSLog(@"加密:%@",aesStr);
最后
不明白的地方,如果哪位明白人儿能搞懂,麻烦你给翻译翻译,谢谢了!
当然了,自己也得找找帖子琢磨琢磨,以下是参考过的帖子。
iOS AES128 CBC No Padding加密解密
AES加密 - iOS与Java的同步实现
[拿走直接用] iOS加密:AES+Base64
网友评论