123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- //
- // RSACryptor.m
- //
- #import "RSACryptor.h"
- // 填充模式 kSecPaddingNone 每次加密结果是固定的,kSecPaddingPKCS1是随机变化的
- #define kTypeOfWrapPadding kSecPaddingNone
- // 公钥/私钥标签
- #define kPublicKeyTag "com.wendingding.sample.publickey"
- #define kPrivateKeyTag "com.wendingding.sample.privatekey"
- static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
- static const uint8_t privateKeyIdentifier[] = kPrivateKeyTag;
- @interface RSACryptor() {
- SecKeyRef publicKeyRef; // 公钥引用
- SecKeyRef privateKeyRef; // 私钥引用
- }
- @property (nonatomic, retain) NSData *publicTag; // 公钥标签
- @property (nonatomic, retain) NSData *privateTag; // 私钥标签
- @end
- @implementation RSACryptor
- + (instancetype)sharedRSACryptor {
- static id instance;
-
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- instance = [[self alloc] init];
- });
- return instance;
- }
- - (instancetype)init {
- self = [super init];
- if (self) {
- // 查询密钥的标签
- _privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
- _publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
- }
- return self;
- }
- #pragma mark - 加密 & 解密数据
- - (NSData *)encryptData:(NSData *)plainData {
- OSStatus sanityCheck = noErr;
- size_t cipherBufferSize = 0;
- size_t keyBufferSize = 0;
-
- NSAssert(plainData != nil, @"明文数据为空");
- NSAssert(publicKeyRef != nil, @"公钥为空");
-
- NSData *cipher = nil;
- uint8_t *cipherBuffer = NULL;
-
- // 计算缓冲区大小
- cipherBufferSize = SecKeyGetBlockSize(publicKeyRef);
- keyBufferSize = [plainData length];
-
- if (kTypeOfWrapPadding == kSecPaddingNone) {
- NSAssert(keyBufferSize <= cipherBufferSize, @"加密内容太大");
- } else {
- NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密内容太大");
- }
-
- // 分配缓冲区
- cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
- memset((void *)cipherBuffer, 0x0, cipherBufferSize);
-
- // 使用公钥加密
- sanityCheck = SecKeyEncrypt(publicKeyRef,
- kTypeOfWrapPadding,
- (const uint8_t *)[plainData bytes],
- keyBufferSize,
- cipherBuffer,
- &cipherBufferSize
- );
-
- NSAssert(sanityCheck == noErr, @"加密错误,OSStatus == %d", (int)sanityCheck);
-
- // 生成密文数据
- cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
-
- if (cipherBuffer) free(cipherBuffer);
-
- return cipher;
- }
- - (NSData *)decryptData:(NSData *)cipherData {
- OSStatus sanityCheck = noErr;
- size_t cipherBufferSize = 0;
- size_t keyBufferSize = 0;
-
- NSData *key = nil;
- uint8_t *keyBuffer = NULL;
-
- SecKeyRef privateKey = NULL;
-
- privateKey = [self getPrivateKeyRef];
- NSAssert(privateKey != NULL, @"私钥不存在");
-
- // 计算缓冲区大小
- cipherBufferSize = SecKeyGetBlockSize(privateKey);
- keyBufferSize = [cipherData length];
-
- NSAssert(keyBufferSize <= cipherBufferSize, @"解密内容太大");
-
- // 分配缓冲区
- keyBuffer = malloc(keyBufferSize * sizeof(uint8_t));
- memset((void *)keyBuffer, 0x0, keyBufferSize);
-
- // 使用私钥解密
- sanityCheck = SecKeyDecrypt(privateKey,
- kTypeOfWrapPadding,
- (const uint8_t *)[cipherData bytes],
- cipherBufferSize,
- keyBuffer,
- &keyBufferSize
- );
-
- NSAssert1(sanityCheck == noErr, @"解密错误,OSStatus == %d", sanityCheck);
-
- // 生成明文数据
- key = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize];
-
- if (keyBuffer) free(keyBuffer);
-
- return key;
- }
- #pragma mark - 密钥处理
- /**
- * 生成密钥对
- */
- - (void)generateKeyPair:(NSUInteger)keySize {
- OSStatus sanityCheck = noErr;
- publicKeyRef = NULL;
- privateKeyRef = NULL;
-
- NSAssert1((keySize == 512 || keySize == 1024 || keySize == 2048), @"密钥尺寸无效 %tu", keySize);
-
- // 删除当前密钥对
- [self deleteAsymmetricKeys];
-
- // 容器字典
- NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
-
- // 设置密钥对的顶级字典
- [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
- [keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
-
- // 设置私钥字典
- [privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
- [privateKeyAttr setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
-
- // 设置公钥字典
- [publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
- [publicKeyAttr setObject:_publicTag forKey:(__bridge id)kSecAttrApplicationTag];
-
- // 设置顶级字典属性
- [keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
- [keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
-
- // SecKeyGeneratePair 返回密钥对引用
- sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKeyRef, &privateKeyRef);
- NSAssert((sanityCheck == noErr && publicKeyRef != NULL && privateKeyRef != NULL), @"生成密钥对失败");
- }
- /**
- * 加载公钥
- */
- - (void)loadPublicKey:(NSString *)publicKeyPath {
-
- NSAssert(publicKeyPath.length != 0, @"公钥路径为空");
-
- // 删除当前公钥
- if (publicKeyRef) CFRelease(publicKeyRef);
-
- // 从一个 DER 表示的证书创建一个证书对象
- NSData *certificateData = [NSData dataWithContentsOfFile:publicKeyPath];
- SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
- NSAssert(certificateRef != NULL, @"公钥文件错误");
-
- // 返回一个默认 X509 策略的公钥对象,使用之后需要调用 CFRelease 释放
- SecPolicyRef policyRef = SecPolicyCreateBasicX509();
- // 包含信任管理信息的结构体
- SecTrustRef trustRef;
-
- // 基于证书和策略创建一个信任管理对象
- OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
- NSAssert(status == errSecSuccess, @"创建信任管理对象失败");
-
- // 信任结果
- SecTrustResultType trustResult;
- // 评估指定证书和策略的信任管理是否有效
- status = SecTrustEvaluate(trustRef, &trustResult);
- NSAssert(status == errSecSuccess, @"信任评估失败");
-
- // 评估之后返回公钥子证书
- publicKeyRef = SecTrustCopyPublicKey(trustRef);
- NSAssert(publicKeyRef != NULL, @"公钥创建失败");
-
- if (certificateRef) CFRelease(certificateRef);
- if (policyRef) CFRelease(policyRef);
- if (trustRef) CFRelease(trustRef);
- }
- /**
- * 加载私钥
- */
- - (void)loadPrivateKey:(NSString *)privateKeyPath password:(NSString *)password {
-
- NSAssert(privateKeyPath.length != 0, @"私钥路径为空");
-
- // 删除当前私钥
- if (privateKeyRef) CFRelease(privateKeyRef);
-
- NSData *PKCS12Data = [NSData dataWithContentsOfFile:privateKeyPath];
- CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
- CFStringRef passwordRef = (__bridge CFStringRef)password;
-
- // 从 PKCS #12 证书中提取标示和证书
- SecIdentityRef myIdentity;
- SecTrustRef myTrust;
- const void *keys[] = {kSecImportExportPassphrase};
- const void *values[] = {passwordRef};
- CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
- CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
-
- // 返回 PKCS #12 格式数据中的标示和证书
- OSStatus status = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
-
- if (status == noErr) {
- CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
- myIdentity = (SecIdentityRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
- myTrust = (SecTrustRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
- }
-
- if (optionsDictionary) CFRelease(optionsDictionary);
-
- NSAssert(status == noErr, @"提取身份和信任失败");
-
- SecTrustResultType trustResult;
- // 评估指定证书和策略的信任管理是否有效
- status = SecTrustEvaluate(myTrust, &trustResult);
- NSAssert(status == errSecSuccess, @"信任评估失败");
-
- // 提取私钥
- status = SecIdentityCopyPrivateKey(myIdentity, &privateKeyRef);
- NSAssert(status == errSecSuccess, @"私钥创建失败");
- }
- /**
- * 删除非对称密钥
- */
- - (void)deleteAsymmetricKeys {
- OSStatus sanityCheck = noErr;
- NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
-
- // 设置公钥查询字典
- [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
- [queryPublicKey setObject:_publicTag forKey:(__bridge id)kSecAttrApplicationTag];
- [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
-
- // 设置私钥查询字典
- [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
- [queryPrivateKey setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
- [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
-
- // 删除私钥
- sanityCheck = SecItemDelete((__bridge CFDictionaryRef)queryPrivateKey);
- NSAssert1((sanityCheck == noErr || sanityCheck == errSecItemNotFound), @"删除私钥错误,OSStatus == %d", sanityCheck);
-
- // 删除公钥
- sanityCheck = SecItemDelete((__bridge CFDictionaryRef)queryPublicKey);
- NSAssert1((sanityCheck == noErr || sanityCheck == errSecItemNotFound), @"删除公钥错误,OSStatus == %d", sanityCheck);
-
- if (publicKeyRef) CFRelease(publicKeyRef);
- if (privateKeyRef) CFRelease(privateKeyRef);
- }
- /**
- * 获得私钥引用
- */
- - (SecKeyRef)getPrivateKeyRef {
- OSStatus sanityCheck = noErr;
- SecKeyRef privateKeyReference = NULL;
-
- if (privateKeyRef == NULL) {
- NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
-
- // 设置私钥查询字典
- [queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
- [queryPrivateKey setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
- [queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
- [queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
-
- // 获得密钥
- sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
-
- if (sanityCheck != noErr) {
- privateKeyReference = NULL;
- }
- } else {
- privateKeyReference = privateKeyRef;
- }
-
- return privateKeyReference;
- }
- @end
|