分享

iOS 系统中 AES 和 RSA 算法的实现

 望穿墙 2016-06-22

转: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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多