转:http://kvmisc./blog/2015/02/10/implement-aes-and-rsa-algorithm-in-ios/写在文前
本文的主要目的不是阐述 AES 和 RSA 算法的实现。笔者没时间去仔细研究这两种算法的具体细节,再针对明文进行一系列复杂的字节操作。造轮子的事情还是少做为好,而且笔者也没有信心能造好这个轮子。
AES 加密
iOS 系统自带的 CommonCrypto 库包含了 AES 加密的功能,所以 AES 加密的实现很简单,将 CommonCrypto 库里面的 C 函数进行封装就可以。
#import <CommonCrypto/CommonCrypto.h>
@implementation NSData (AES)
- (NSData *)AESCryptWithOperation:(CCOperation)operation key:(NSData *)key iv:(NSData *)iv
{
CCCryptorRef cryptorRef = NULL;
CCCryptorStatus status = CCCryptorCreate(operation,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
[key bytes],
[key length],
[iv bytes],
&cryptorRef);
if ( status==kCCSuccess ) {
NSUInteger bufferSize = CCCryptorGetOutputLength(cryptorRef, [self length], true);
NSMutableData *result = [[NSMutableData alloc] initWithLength:bufferSize];
void *buffer = [result mutableBytes];
NSUInteger totalLength = 0;
size_t writtenLength = 0;
status = CCCryptorUpdate(cryptorRef,
[self bytes],
[self length],
buffer,
bufferSize,
&writtenLength);
if ( status==kCCSuccess ) {
totalLength += writtenLength;
status = CCCryptorFinal(cryptorRef,
buffer+writtenLength,
bufferSize-writtenLength,
&writtenLength);
if ( status==kCCSuccess ) {
totalLength += writtenLength;
[result setLength:totalLength];
CCCryptorRelease(cryptorRef);
return result;
}
}
CCCryptorRelease(cryptorRef);
}
return nil;
}
@end
上面的代码将 AES 加密封装到 NSData 的类别中,工作模式采用 CBC,填充模式选择 PKCS7Padding。
RSA 加密
iOS 系统中没有直接提供用于 RSA 加密的函数。在不使用第三方库的情况下,可以使用 Security 框架里面针对 x509 证书的函数来实现 RSA 加密,这种方法要对公钥和私钥进行一系列的操作。密钥的准备工作如下:
# 生成 RSA 私钥
openssl genrsa -out private.pem 2048
# 从密钥中提取公钥
openssl rsa -pubout -in private.pem -out public.pem
# 用私钥生成证书签名请求
openssl req -new -key private.pem -out cert.csr
# 用私钥和证书签名请求生成自签名的证书
openssl x509 -req -days 3650 -in cert.csr -signkey private.pem -out cert.crt
# 将自签名的证书转换为 DER 格式(里面包含公钥)
openssl x509 -outform der -in cert.crt -out cert.der
# 将私钥和证书导出到 p12 文件中(要求输入密码)
openssl pkcs12 -export -inkey private.pem -in cert.crt -out cert.p12
经过这几个步骤以后,我们生成了 cert.der 和 cert.p12 两个文件,它们就是 Security 框架所能识别的格式。将这两文件导入到项目工程,最终的加密代码如下:
#define ReleaseObject(ref) {if(ref){CFRelease(ref);ref=NULL;}}
@implementation NSData (RSA)
- (NSData *)RSAEncryptedDataWithKey:(SecKeyRef)pubkey
{
NSMutableData *result = nil;
if ( ([self length]>0) && [self length]<=(SecKeyGetBlockSize(pubkey)-11) ) {
size_t size = SecKeyGetBlockSize(pubkey);
result = [NSMutableData dataWithLength:size];
SecKeyEncrypt(pubkey, kSecPaddingPKCS1, [self bytes], [self length], [result mutableBytes], &size);
[result setLength:size];
}
return result;
}
- (NSData *)RSADecryptedDataWithKey:(SecKeyRef)prikey
{
NSMutableData *result = nil;
if ( [self length]==SecKeyGetBlockSize(prikey) ) {
size_t size = [self length];
result = [NSMutableData dataWithLength:size];
SecKeyDecrypt(prikey, kSecPaddingPKCS1, [self bytes], [self length], [result mutableBytes], &size);
[result setLength:size];
}
return result;
}
+ (SecKeyRef)RSACreatePublicKey:(NSData *)data
{
SecKeyRef keyRef = NULL;
SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)data);
if ( certificateRef ) {
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
if ( policyRef ) {
SecTrustRef trustRef;
if ( SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef)==errSecSuccess ) {
SecTrustResultType trustResultType;
if ( SecTrustEvaluate(trustRef, &trustResultType)==errSecSuccess ) {
keyRef = SecTrustCopyPublicKey(trustRef);
}
}
ReleaseObject(trustRef);
}
ReleaseObject(policyRef);
}
ReleaseObject(certificateRef);
return keyRef;
}
+ (SecKeyRef)RSACreatePrivateKey:(NSData *)data password:(NSString *)password
{
SecKeyRef keyRef = NULL;
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { (__bridge CFStringRef)password };
CFDictionaryRef optionRef = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef itemRef = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus status = SecPKCS12Import((__bridge CFDataRef)data, optionRef, &itemRef);
if ( (status==errSecSuccess) && (CFArrayGetCount(itemRef)>0) ) {
CFDictionaryRef dictionaryRef = CFArrayGetValueAtIndex(itemRef, 0);
SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(dictionaryRef, kSecImportItemIdentity);
if ( SecIdentityCopyPrivateKey(identityRef, &keyRef)!=errSecSuccess ) {
keyRef = NULL;
}
}
ReleaseObject(itemRef);
ReleaseObject(optionRef);
return keyRef;
}
@end
使用 OpenSSL
上面介绍的 RSA 加密实现方法有点曲折,如果想要直接的实现方法,必须得使用第三方库,OpenSSL 就是一个不错的选择。那么,OpenSSL 有没有 iOS 版本呢?
OpenSSL 是一个使用 C 语言开发的软件包,里面包含应用程序、SSL 协议库和密码算法库。既然是使用 C 语言编写而成,那么,它就具有跨平台特性,移植到 iOS 系统也是理所当然的。幸运的是,已经有人作了此类研究,编写了编译脚本,这使得移植工作变得相当简单,具体细节可以参考 OpenSSL for iOS。
|