1.公司要求实现AES加密算法,对于java,js及PHP,网上有现成的demo。唯独没有iOS的。气的一笔。没办法只能自己慢慢摸索了。
附上java及JS的实现地址 https://github.com/mpetersen/aes-example (开源项目)
java部分源代码:
private static final int KEY_SIZE = 128; private static final int ITERATION_COUNT = 10000; private static final String IV = "F27D5C9927726BCEFE7510B1BDD3D137"; private static final String SALT = "3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55"; private static final String PLAIN_TEXT = "abc"; private static final String PASSPHRASE = "1234567890";
static void test1() throws Exception { AesUtil util = new AesUtil(KEY_SIZE,ITERATION_COUNT); String encrypt = util.encrypt(SALT, IV, PASSPHRASE, PLAIN_TEXT); System.out.println(encrypt); // 密文: izGCdsKok+u/x3UwTy9fDg== String decrypt = util.decrypt(SALT, IV, PASSPHRASE, encrypt); System.out.println(decrypt); } |
网上搜了一堆demo,但是都不太符合要求。因为网上的demo,都要求key和偏移量是16位字符串。而我们采用的是AES-128-CBC-kCCOptionPKCS5Padding -base64模式,key值的产生由密码和SALT产生。关键的地方是key的产生不是16位的字符串,这就蛋疼了.网上搜了很久,忽然发现openssl已经实现了PKCS5_PBKDF2_HMAC_SHA1加密算法。很开心。
安装openSSL,github上已经有大神已经封装过了(https://github.com/x2on/OpenSSL-for-iPhone)。只需要终端运行响应命令即可。
安装过程:
1.github上下载OpenSSL-for-iPhone。
2.运行 ./build-libssl.sh 此过程时间比较长,3-5分钟可以喝杯茶。加载的好像是1.0.2版本。如果要最新的版本加上版本号运行命令./build-libssl.sh --version=1.1.0f。完成后在相应文件夹下。即可看到文件。(如果你在安装的时候发现,相应的目录下面没有相应的文件或者用了相应的文件,不是你本地运行命令建立的文件报了一堆错,或者你安装了多了xcode的导致文件的路径不对,请换一台能用的电脑,创建openssl的文件,然后导入工程中),我当时就是在此处出现了很多问题,以为这个大神封装的库有问题呢,装逼装过头了。后来换了一台电脑,我擦,竟然好了。可能跟我安装了两个xcode有关。
使用步骤:
1.将OpenSSL-for-iPhone文件下include头文件夹copy 到项目中,
2.将lib下的libcrypto.a,libssl.a复制到工程中
3.修改Header Search Paths 设置“$(SRCROOT)/$(PROJECT_NAME)/openssl/include” 设置为recursive;
4.查看build Phases的link Binary with libraries库中是否有libcrypto.a,libssl.a。
5.加入Security.framework库
验证很简单了,commend+B运行一下,不报错,恭喜你openssl已经完成集成。
下面就是AES加密算法的封装了。
实现一个加密方法
+ (NSString *)encryptedDataForData:(NSString *)plainText
password:(NSString *)password
iv:(NSData *)iv
salt:(NSData *)salt
error:(NSError *)error;
一个解密方法
+ (NSString *)decryptedDataForData:(NSString *)plainText
password:(NSString *)password
iv:(NSData *)iv
salt:(NSData *)salt
error:(NSError *)error ;
//16进制转换为NSData
+ (NSData*)convertHexStrToData:(NSString*)str;
//NSData转换为16进制
+ (NSString*)convertDataToHexStr:(NSData*)data;
.m文件
定义算法参数
const CCAlgorithm kAlgorithm = kCCAlgorithmAES128;
const NSUInteger kAlgorithmKeySize = kCCKeySizeAES128;
const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
实现方法
+ (NSData *)AESKeyForPassword:(NSString *)password
salt:(NSData *)salt {
NSMutableData *
derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
int result = PKCS5_PBKDF2_HMAC_SHA1(password.UTF8String, (int)[password length],
salt.bytes, (int)[salt length], 10000,
(int)[derivedKey length], derivedKey.mutableBytes);
NSAssert(result == 1,
@"Unable to create AES key for password: %d", result);
return derivedKey;
}
+ (NSString *)encryptedDataForData:(NSString *)plainText
password:(NSString *)password
iv:(NSData *)iv
salt:(NSData *)salt
error:(NSError *)error {
const char *cstr = [plainText cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:plainText.length];
NSData *key = [self AESKeyForPassword:password salt:salt];
size_t outLength;
NSMutableData *
cipherData = [NSMutableData dataWithLength:data.length +
kAlgorithmBlockSize];
CCCryptorStatus
result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionPKCS7Padding, // options
key.bytes, // key
key.length, // keylength
(iv).bytes,// iv
data.bytes, // dataIn
data.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
if (error) {
error = [NSError errorWithDomain:@"error"
code:result
userInfo:nil];
}
return nil;
}
return [cipherData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}
+ (NSString *)decryptedDataForData:(NSString *)plainText
password:(NSString *)password
iv:(NSData *)iv
salt:(NSData *)salt
error:(NSError *)error {
NSData *data = [[NSData alloc] initWithBase64EncodedString:plainText options:NSDataBase64DecodingIgnoreUnknownCharacters];
// const char *cstr = [plainText cStringUsingEncoding:NSUTF8StringEncoding];
// NSData *data = [NSData dataWithBytes:cstr length:plainText.length];
//
NSData *key = [self AESKeyForPassword:password salt:salt];
size_t outLength;
NSMutableData *
cipherData = [NSMutableData dataWithLength:data.length +
kAlgorithmBlockSize];
CCCryptorStatus
result = CCCrypt(kCCDecrypt,
kAlgorithm,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
(iv).bytes ,
data.bytes,
data.length,
cipherData.mutableBytes,
cipherData.length,
&outLength);
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
if (error) {
error = [NSError errorWithDomain:@"error"
code:result
userInfo:nil];
}
return nil;
}
return [[NSString alloc] initWithData:cipherData encoding:NSUTF8StringEncoding];
}
//16进制转换为NSData
+ (NSData*)convertHexStrToData:(NSString*)str {
if (!str || [str length] ==0) {
return nil;
}
NSMutableData *hexData = [[NSMutableData alloc]initWithCapacity:[str length]*2];
NSRange range;
if ([str length] %2==0) {
range = NSMakeRange(0,2);
} else {
range = NSMakeRange(0,1);
}
for (NSInteger i = range.location; i < [str length]; i +=2) {
unsigned int anInt;
NSString *hexCharStr = [str substringWithRange:range];
NSScanner *scanner = [[NSScanner alloc]initWithString:hexCharStr];
[scanner scanHexInt:&anInt];
NSData *entity = [[NSData alloc]initWithBytes:&anInt length:1];
[hexData appendData:entity];
range.location+= range.length;
range.length=2;
}
// NSLog(@"hexdata: %@", hexData);
return hexData;
}
//NSData转换为16进制
+ (NSString*)convertDataToHexStr:(NSData*)data {
if (!data || [data length] ==0) {
return @"";
}
NSMutableString *string = [[NSMutableString alloc]initWithCapacity:[data length]/2];
[data enumerateByteRangesUsingBlock:^(const void*bytes,NSRange byteRange,BOOL*stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i =0; i < byteRange.length; i++) {
NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
if ([hexStr length] ==2) {
[string appendString:hexStr];
} else {
[string appendFormat:@"0%@", hexStr];
}
}
}];
return string;
}
创建测试工程viewCtroller中导入头文件。
测试验证
NSString *IV = @"F27D5C9927726BCEFE7510B1BDD3D137";
NSString *SALT = @"3FF2EC019C627B945225DEBAD71A01B6985FE84C95A70EB132882F88C0A59A55";
NSString *PLAIN_TEXT = @"abcd";
NSString *PASSPHRASE = @"1234567890";
NSData *HEX_IV = [AES convertHexStrToData:IV];
NSData *HEX_SALT = [AES convertHexStrToData:SALT];
NSString *str = [AES encryptedDataForData:PLAIN_TEXT password:PASSPHRASE iv:HEX_IV salt:HEX_SALT error:nil];
NSString *str2 = [AES decryptedDataForData:str password:PASSPHRASE iv:HEX_IV salt:HEX_SALT error:nil];
NSLog(@"%@===%@",str,str2);
完事。
文章里面有参照别人的代码和方法,为了方便,不做封装了,引用之处往见谅。