既然說到加密,必然和隱私相關(guān)京闰,那么就從網(wǎng)絡(luò)開發(fā)兩大原則說起:
1-網(wǎng)絡(luò)上不允許傳輸用戶的明文隱私數(shù)據(jù)锨亏。
2-本地不允許保存用戶的額明文隱私數(shù)據(jù)。
那么既然不能使用明文進行傳輸和保存忙干,我們同時又需要進行相關(guān)操作的話器予,就必須要使用下面說到的各種加密了。
首先捐迫,市面上常用的加密方式分為對稱加密
,非對稱加密
和哈希加密
乾翔。
1.對稱加密:
文件加密和解密使用相同的密鑰,即加密密鑰也可以用作解密密鑰。
常用加密算法有DES
,3DES
,AES
等.
DES 數(shù)據(jù)加密標準(用的比較少,因為強度不夠).
3DES 使用3個密鑰,對相同的數(shù)據(jù)執(zhí)行三次加密,強度增強.
AES 高級加密標準,目前美國國家安全局使用AES加密,蘋果的鑰匙串訪問就是使用AES加密反浓。
而對稱加密一般分為四種模式:ECB
,CBC
,CFB
和OFB
萌丈,最為常見的是前兩種。
ECB的特點:
加密文件會被分為若干個加密塊雷则,
每個塊都是獨立進行加密辆雾,互不影響。
所以月劈,如果變動數(shù)據(jù)中的某一個地方度迂,
加密之后其對應(yīng)得塊也會發(fā)生變化,
缺點是一旦被破解某個模塊猜揪,就可以進行推理惭墓,
進而有機會獲取到重要數(shù)據(jù)。
關(guān)于ECB的終端操作代碼:
加密: $ openssl enc -des-ecb -K 616263 -nosalt -in
msg.txt -out msgLock.bin
解密:$ openssl enc -des-ecb -K 616263 -nosalt -in
msgLock.bin -out msg.txt -d
查看加密之后的二進制文件:$ xxd msgLock.bin
CBC的特點:
使用一個密鑰和一個初始化向量 (IV)對數(shù)據(jù)執(zhí)
行加密轉(zhuǎn)換而姐。
加密文件同樣會被分為若干個加密塊腊凶,
每個塊都依賴于上一個加密塊進行加密,互相牽制拴念。
所以伞鲫,如果變動數(shù)據(jù)中的某一個地方磨澡,
加密之后整體數(shù)據(jù)都會發(fā)生變化城须。
可以有效地保證密文的完整性
關(guān)于CBC的終端操作代碼:
加密: $ openssl enc -des-cbc -K 616263 -iv
0000000000000000 -nosalt -in a.txt -out
msg1.bin
解密:$ openssl enc -des-cbc -K 616263 -iv
0000000000000000 -nosalt -in msg1.bin -out
msg4.txt -d
查看加密之后的二進制文件:$ xxd msg1.bin
2.非對稱加密
與對稱加密算法不同拐迁,非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。也就是公鑰加密缔俄,私鑰解密或者私鑰加密弛秋,公鑰解密。常見的非對稱加密算法有RSA
(加密俐载,證書生成),DSA
(數(shù)字簽名)等,非對稱加密算法的保密性比較好蟹略,但加密和解密花費時間長、速度慢遏佣,它不適合于對文件加密而只適用于對少量數(shù)據(jù)進行加密挖炬。
使用openssl生成密鑰加密的步驟:
生成強度是 512 的 RSA 私鑰:$ openssl genrsa -out private.pem 512
以明文輸出私鑰內(nèi)容:$ openssl rsa -in private.pem -text -out
private.txt
校驗私鑰文件:$ openssl rsa -in private.pem -check
從私鑰中提取公鑰:$ openssl rsa -in private.pem -out public.pem
-outform PEM -pubout
以明文輸出公鑰內(nèi)容:$ openssl rsa -in public.pem -out public.txt
-pubin -pubout -text
使用公鑰加密小文件:$ openssl rsautl -encrypt -pubin -inkey
public.pem -in msg.txt -out msg.bin
使用私鑰解密小文件:$ openssl rsautl -decrypt -inkey private.pem
-in msg.bin -out a.txt
將私鑰轉(zhuǎn)換成 DER 格式:$ openssl rsa -in private.pem -out private.der
-outform der
將公鑰轉(zhuǎn)換成 DER 格式:$ openssl rsa -in public.pem -out public.der
-pubin -outform der
程序開發(fā)數(shù)字證書的生成:
生成私鑰:openssl genrsa -out ca.key 1024
創(chuàng)建證書請求:openssl req -new -key ca.key -out rsacert.csr
生成證書并簽名,有效期10年:openssl x509 -req -days 3650 -in rsacert.csr
-signkey ca.key -out rsacert.crt
轉(zhuǎn)換格式(將 openssl默認生成的PEM 格式文件轉(zhuǎn)換成iOS支持的DER 格式):openssl x509 -outform der -in rsacert.crt -out
rsacert.der
導(dǎo)入P12文件:openssl pkcs12 -export -out p.p12 -inkey
ca.key -in rsacert.crt
iOS開發(fā)中相關(guān)的函數(shù):
使用公鑰對數(shù)據(jù)加密:SecKeyEncrypt
使用私鑰對數(shù)據(jù)解密:SecKeyDecrypt
使用公鑰對數(shù)字簽名進行驗證:SecKeyRawVerify
使用私鑰生成數(shù)字簽名:SecKeyRawSign
3.HASH加密
Hash算法特別的地方在于它是一種單向算法状婶,用戶可以通過Hash算法對目標信息生成一段特定長度(32個字符)的唯一的Hash值意敛,卻不能通過這個Hash值重新獲得目標信息。對用相同數(shù)據(jù)膛虫,加密之后的密文相同草姻。
常見的Hash算法有MD5
和SHA
。
由于加密結(jié)果固定稍刀,所以基本上原始的哈希加密已經(jīng)不再安全撩独,于是衍生出了加鹽的方式敞曹。
加鹽:先對原始數(shù)據(jù)拼接固定的字符串再進行加密。
HMAC:也叫隨機鹽综膀,給定一個密鑰澳迫,對明文進行拼接,
并且做兩次散列剧劝。其中密鑰由服務(wù)器在用戶注冊時候返回給客戶端橄登。
iOS對稱加密代碼:
//AES - ECB 加密
NSString * key = @"hk";
//加密
NSLog(@"加密: %@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil]);
//解密
NSLog(@"解密: %@",[[EncryptionTools sharedEncryptionTools] decryptString:@"cKRPM1ALLG+0q5qCjADoaQ==" keyString:key iv:nil]);
//AES - CBC 加密
uint8_t iv[8] = {2,3,4,5,6,7,0,0}; //直接影響加密結(jié)果!
NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];
NSLog(@"CBC加密: %@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:ivData]);
NSLog(@"CBC解密: %@", [[EncryptionTools sharedEncryptionTools] decryptString:@"+dv/u4juE0WE3S9XSFyibA==" keyString:key iv:ivData]);
//DES - ECB 加密
[EncryptionTools sharedEncryptionTools].algorithm = kCCAlgorithmDES;
NSLog(@"DES 加密%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil]);
NSLog(@"DES 解密: %@", [[EncryptionTools sharedEncryptionTools] decryptString:@"vTuv8E5AlWQ=" keyString:key iv:nil]);
其中EncryptionTools
文件如下:
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>
/**
* 終端測試指令
*
* DES(ECB)加密
* $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
*
* DES(CBC)加密
* $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
* AES(ECB)加密
* $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
*
* AES(CBC)加密
* $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
*
* DES(ECB)解密
* $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
*
* DES(CBC)解密
* $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
* AES(ECB)解密
* $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
*
* AES(CBC)解密
* $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
*
* 提示:
* 1> 加密過程是先加密,再base64編碼
* 2> 解密過程是先base64解碼讥此,再解密
*/
@interface EncryptionTools : NSObject
+ (instancetype)sharedEncryptionTools;
/**
@constant kCCAlgorithmAES 高級加密標準拢锹,128位(默認)
@constant kCCAlgorithmDES 數(shù)據(jù)加密標準
*/
@property (nonatomic, assign) uint32_t algorithm;
/**
* 加密字符串并返回base64編碼字符串
*
* @param string 要加密的字符串
* @param keyString 加密密鑰
* @param iv 初始化向量(8個字節(jié))
*
* @return 返回加密后的base64編碼字符串
*/
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
/**
* 解密字符串
*
* @param string 加密并base64編碼后的字符串
* @param keyString 解密密鑰
* @param iv 初始化向量(8個字節(jié))
*
* @return 返回解密后的字符串
*/
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv;
@end
#import "EncryptionTools.h"
@interface EncryptionTools()
@property (nonatomic, assign) int keySize;
@property (nonatomic, assign) int blockSize;
@end
@implementation EncryptionTools
+ (instancetype)sharedEncryptionTools {
static EncryptionTools *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
instance.algorithm = kCCAlgorithmAES;
});
return instance;
}
- (void)setAlgorithm:(uint32_t)algorithm {
_algorithm = algorithm;
switch (algorithm) {
case kCCAlgorithmAES:
self.keySize = kCCKeySizeAES128;
self.blockSize = kCCBlockSizeAES128;
break;
case kCCAlgorithmDES:
self.keySize = kCCKeySizeDES;
self.blockSize = kCCBlockSizeDES;
break;
default:
break;
}
}
- (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設(shè)置秘鑰
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設(shè)置iv
/*
kCCOptionPKCS7Padding CBC 的加密方式
kCCOptionPKCS7Padding | kCCOptionECBMode ECB 的加密方式
*/
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
[iv getBytes:cIv length:self.blockSize];
option = kCCOptionPKCS7Padding;
} else {
option = kCCOptionPKCS7Padding | kCCOptionECBMode;
}
// 設(shè)置輸出緩沖區(qū)
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開始加密
size_t encryptedSize = 0;
/***
CCCrypt 對稱加密算法的核心函數(shù)(加密/解密)
參數(shù):
1.kCCEncrypt 加密/kCCDecrypt 解密
2.加密算法,默認使用的是 AES/DES
3.加密選項 ECB/CBC
kCCOptionPKCS7Padding CBC 的加密方式
kCCOptionPKCS7Padding | kCCOptionECBMode ECB 的加密方式
4.加密密鑰
5.密鑰長度
6.iv 初始化向量,ECB 不需要指定
7.加密的數(shù)據(jù)
8.加密的數(shù)據(jù)的長度
9.密文的內(nèi)存地址
10.密文緩沖區(qū)的大小
11.加密結(jié)果大小
*/
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
} else {
free(buffer);
NSLog(@"[錯誤] 加密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [result base64EncodedStringWithOptions:0];
}
- (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
// 設(shè)置秘鑰
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t cKey[self.keySize];
bzero(cKey, sizeof(cKey));
[keyData getBytes:cKey length:self.keySize];
// 設(shè)置iv
uint8_t cIv[self.blockSize];
bzero(cIv, self.blockSize);
int option = 0;
if (iv) {
[iv getBytes:cIv length:self.blockSize];
option = kCCOptionPKCS7Padding;
} else {
option = kCCOptionPKCS7Padding | kCCOptionECBMode;
}
// 設(shè)置輸出緩沖區(qū)
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
size_t bufferSize = [data length] + self.blockSize;
void *buffer = malloc(bufferSize);
// 開始解密
size_t decryptedSize = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&decryptedSize);
NSData *result = nil;
if (cryptStatus == kCCSuccess) {
result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
} else {
free(buffer);
NSLog(@"[錯誤] 解密失敗|狀態(tài)編碼: %d", cryptStatus);
}
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
@end
iOS RSA加密代碼:
- (void)viewDidLoad {
[super viewDidLoad];
//1.加載公鑰
[[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
//2. 加載私鑰 - P12的文件 password : 生成P12 的時候設(shè)置的密碼
[[RSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSData * reault = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
//base64 編碼
NSString * base64 = [reault base64EncodedStringWithOptions:0];
NSLog(@"加密的信息: %@",base64);
//解密
NSData * jiemi = [[RSACryptor sharedRSACryptor] decryptData:reault];
NSLog(@"%@",[[NSString alloc]initWithData:jiemi encoding:NSUTF8StringEncoding]);
}
RSACryptor
文件如下:
#import <Foundation/Foundation.h>
@interface RSACryptor : NSObject
+ (instancetype)sharedRSACryptor;
/**
* 生成密鑰對
*
* @param keySize 密鑰尺寸暂论,可選數(shù)值(512/1024/2048)
*/
- (void)generateKeyPair:(NSUInteger)keySize;
/**
* 加載公鑰
*
* @param publicKeyPath 公鑰路徑
*
@code
# 生成證書
$ openssl genrsa -out ca.key 1024
# 創(chuàng)建證書請求
$ openssl req -new -key ca.key -out rsacert.csr
# 生成證書并簽名
$ openssl x509 -req -days 3650 -in rsacert.csr -signkey ca.key -out rsacert.crt
# 轉(zhuǎn)換格式
$ openssl x509 -outform der -in rsacert.crt -out rsacert.der
@endcode
*/
- (void)loadPublicKey:(NSString *)publicKeyPath;
/**
* 加載私鑰
*
* @param privateKeyPath p12文件路徑
* @param password p12文件密碼
*
@code
openssl pkcs12 -export -out p.p12 -inkey ca.key -in rsacert.crt
@endcode
*/
- (void)loadPrivateKey:(NSString *)privateKeyPath password:(NSString *)password;
/**
* 加密數(shù)據(jù)
*
* @param plainData 明文數(shù)據(jù)
*
* @return 密文數(shù)據(jù)
*/
- (NSData *)encryptData:(NSData *)plainData;
/**
* 解密數(shù)據(jù)
*
* @param cipherData 密文數(shù)據(jù)
*
* @return 明文數(shù)據(jù)
*/
- (NSData *)decryptData:(NSData *)cipherData;
@end
#import "RSACryptor.h"
// 填充模式
// kSecPaddingNone 每次加密結(jié)果是固定的 kSecPaddingPKCS1 是隨機的
#define kTypeOfWrapPadding kSecPaddingPKCS1
// 公鑰/私鑰標簽
#define kPublicKeyTag "com.itheima.sample.publickey"
#define kPrivateKeyTag "com.itheima.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 - 加密 & 解密數(shù)據(jù)
- (NSData *)encryptData:(NSData *)plainData {
OSStatus sanityCheck = noErr;
size_t cipherBufferSize = 0;
size_t keyBufferSize = 0;
NSAssert(plainData != nil, @"明文數(shù)據(jù)為空");
NSAssert(publicKeyRef != nil, @"公鑰為空");
NSData *cipher = nil;
uint8_t *cipherBuffer = NULL;
// 計算緩沖區(qū)大小
cipherBufferSize = SecKeyGetBlockSize(publicKeyRef);
keyBufferSize = [plainData length];
if (kTypeOfWrapPadding == kSecPaddingNone) {
NSAssert(keyBufferSize <= cipherBufferSize, @"加密內(nèi)容太大");
} else {
NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密內(nèi)容太大");
}
// 分配緩沖區(qū)
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", sanityCheck);
// 生成密文數(shù)據(jù)
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, @"私鑰不存在");
// 計算緩沖區(qū)大小
cipherBufferSize = SecKeyGetBlockSize(privateKey);
keyBufferSize = [cipherData length];
NSAssert(keyBufferSize <= cipherBufferSize, @"解密內(nèi)容太大");
// 分配緩沖區(qū)
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);
// 生成明文數(shù)據(jù)
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];
// 設(shè)置密鑰對的頂級字典
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
// 設(shè)置私鑰字典
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:_privateTag forKey:(__bridge id)kSecAttrApplicationTag];
// 設(shè)置公鑰字典
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:_publicTag forKey:(__bridge id)kSecAttrApplicationTag];
// 設(shè)置頂級字典屬性
[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 表示的證書創(chuàng)建一個證書對象
NSData *certificateData = [NSData dataWithContentsOfFile:publicKeyPath];
SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certificateData);
NSAssert(certificateRef != NULL, @"公鑰文件錯誤");
// 返回一個默認 X509 策略的公鑰對象取胎,使用之后需要調(diào)用 CFRelease 釋放
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
// 包含信任管理信息的結(jié)構(gòu)體
SecTrustRef trustRef;
// 基于證書和策略創(chuàng)建一個信任管理對象
OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
NSAssert(status == errSecSuccess, @"創(chuàng)建信任管理對象失敗");
// 信任結(jié)果
SecTrustResultType trustResult;
// 評估指定證書和策略的信任管理是否有效
status = SecTrustEvaluate(trustRef, &trustResult);
NSAssert(status == errSecSuccess, @"信任評估失敗");
// 評估之后返回公鑰子證書
publicKeyRef = SecTrustCopyPublicKey(trustRef);
NSAssert(publicKeyRef != NULL, @"公鑰創(chuàng)建失敗");
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 格式數(shù)據(jù)中的標示和證書
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, @"私鑰創(chuàng)建失敗");
}
/**
* 刪除非對稱密鑰
*/
- (void)deleteAsymmetricKeys {
OSStatus sanityCheck = noErr;
NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
// 設(shè)置公鑰查詢字典
[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];
// 設(shè)置私鑰查詢字典
[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];
// 設(shè)置私鑰查詢字典
[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