本章描述并演示了如何使用證書、密鑰和信任服務(wù)去導(dǎo)入一個身份(identity),評估證書是否可信,判斷信任失敗的原因,以及信任失敗后的恢復(fù)。
本章按如下順序分別演示了:
- 導(dǎo)入一個 identity.
- 從導(dǎo)入的數(shù)據(jù)中獲得證書.
- 獲得用于證書評估的策略.
- 校驗(yàn)證書,根據(jù)指定策略評估證書是否可信.
- 測試證書中的可恢復(fù)錯誤.
- 判斷證書是否過期.
- 改變評估條件,忽略過期證書.
- 重新評估證書.
Certificate, Key, and Trust Services Concepts提供了證書,密鑰,信任服務(wù)的概念和術(shù)語。證書,密鑰,信任服務(wù)函數(shù)的詳細(xì)信息參見Certificate, Key, and Trust Services Reference.
文章中的代碼片段假設(shè)你已經(jīng)引入了以下頭文件。
#import <UIKit/UIKit.h>
#import <Security/Security.h>
#import <CoreFoundation/CoreFoundation.h>
1. 從一個.p12文件中提取、評估身份
如果你需要在iOS設(shè)備上使用加密過的identity(一個密鑰及其關(guān)聯(lián)的證書)進(jìn)行客戶端認(rèn)證,例如:你可以把PKCS#12數(shù)據(jù)以受密碼保護(hù)的文件的方式安全地傳輸?shù)竭@個設(shè)備上。本節(jié)顯示如何從PKCS#12數(shù)據(jù)中提取identity和trust objects(可信任對象),并評估其可信度。
列表2-1 顯示了用SecPKCS12Import函數(shù)從.p12文件中提取identity和可信任對象,以及評估其可信度。
列表 2-2 顯示如何從identity中獲取證書并顯示證書信息。每個列表后都對代碼進(jìn)行了解釋。
在編譯這段代碼時,請確認(rèn)在Xcode工程中加入了Security.framework。
Listing 2-1 Extractingidentity and trust objects from PKCS #12 Data
從PKCS#12數(shù)據(jù)中提取identity和trust對象
OSStatus extractIdentityAndTrust(CFDataRef inPKCS12Data,
SecIdentityRef *outIdentity,
SecTrustRef *outTrust,
CFStringRef keyPassword)
{
OSStatus securityError = errSecSuccess;
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { keyPassword };
CFDictionaryRef optionsDictionary = NULL;
/* Create a dictionary containing the passphrase if one
was specified. Otherwise, create an empty dictionary. */
optionsDictionary = CFDictionaryCreate(
NULL, keys,
values, (keyPassword ? 1 : 0),
NULL, NULL); // 1 創(chuàng)建要傳給 SecPKCS12Import的包含密碼的字典
CFArrayRef items = NULL;
securityError = SecPKCS12Import(inPKCS12Data,
optionsDictionary,
&items); // 2 從PKCS #12數(shù)據(jù)中導(dǎo)出證書、密鑰、信任,放到數(shù)組中。
//
if (securityError == 0) {
// 3 從數(shù)組中取出第一個字典,并從這個字典中取出身份和信任。
// SecPKCS12Import方法為PKCS #12數(shù)據(jù)中的每一個條目(身份或證書)返回一個字典。
// 在這個例子中被導(dǎo)出的身份是數(shù)組中的第一個(item #0)。
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust,
kSecImportItemIdentity);
CFRetain(tempIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
CFRetain(tempTrust);
*outTrust = (SecTrustRef)tempTrust;
}
if (optionsDictionary) // 4 釋放這些不用的字典和數(shù)組
CFRelease(optionsDictionary);
if (items)
CFRelease(items);
return securityError;
}
這段代碼假設(shè):
- 你已經(jīng)加載PKCS#12文件為NSData或CFDataRef對象。
- 已經(jīng)得到了密鑰的密碼。
這里是這段代碼做的內(nèi)容:
- 創(chuàng)建要傳給 SecPKCS12Import的包含密碼的字典
- 從PKCS #12數(shù)據(jù)中導(dǎo)出證書、密鑰、信任,放到數(shù)組中。
- 從數(shù)組中取出第一個字典,并從這個字典中取出身份和信任。SecPKCS12Import方法為PKCS #12數(shù)據(jù)中的每一個條目(身份或證書)返回一個字典。在這個例子中被導(dǎo)出的身份是數(shù)組中的第一個(item #0)。
- 釋放這些不用的字典和數(shù)組
完成這些步驟,你應(yīng)該:
- 釋放包含新數(shù)據(jù)的CFDataRef對象
- 返回的信任對象通過調(diào)用SecTrustEvaluate 或 SecTrustEvaluateAsync評估信任。
- 處理信任結(jié)果。
- 如果信任結(jié)果是kSecTrustResultInvalid, kSecTrustResultDeny, kSecTrustResultFatalTrustFailure,你不能繼續(xù),以失敗結(jié)束。
如果信任結(jié)果是kSecTrustResultRecoverableTrustFailure,你應(yīng)該從信任失敗中恢復(fù)。
下面的代碼清單顯示了如何從身份中獲取證書,如何展示證書的信息。在編譯這段代碼時,請確認(rèn)在Xcode工程中加入了Security.framework。
Listing 2-2 Displaying information from the certificate
顯示證書信息
NSString *copySummaryString(SecIdentityRef identity)
{
// Get the certificate from the identity.
SecCertificateRef myReturnedCertificate = NULL;
OSStatus status = SecIdentityCopyCertificate (identity,
&myReturnedCertificate); // 1 從證書中提取身份
if (status) {
NSLog(@"SecIdentityCopyCertificate failed.\n");
return NULL;
}
CFStringRef certSummary = SecCertificateCopySubjectSummary
(myReturnedCertificate); // 2 從證書中獲取概要信息。
NSString* summaryString = [[NSString alloc]
initWithString:(__bridge NSString *)certSummary]; // 3轉(zhuǎn)換string為NSString對象
CFRelease(certSummary); //4 釋放NSString對象
return summaryString;
}
2. 獲取和使用持久化的鑰匙串
當(dāng)你在鑰匙串中添加或查找一個條目時,你需要有一個持久化的引用。因?yàn)槌志没媚鼙WC在程序從啟動到能寫入磁盤這段時間內(nèi),始終可用。當(dāng)需要反復(fù)在鑰匙串中查找條目時,使用持久化引用更加容易。以下代碼演示如何獲取一個identity 的持久化引用。
Listing 2-3 Gettinga persistent reference for an identity
CFDataRef persistentRefForIdentity(SecIdentityRef identity)
{
OSStatus status = errSecSuccess;
CFTypeRef persistent_ref = NULL;
const void *keys[] = { kSecReturnPersistentRef, kSecValueRef };
const void *values[] = { kCFBooleanTrue, identity };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
2, NULL, NULL);
status = SecItemAdd(dict, &persistent_ref);
if (dict)
CFRelease(dict);
return (CFDataRef)persistent_ref;
}
下面的示例展示了如何從持久化引用的鑰匙串中檢索身份對象。
Listing 2-4 Gettingan identity using a persistent reference
SecIdentityRef identityForPersistentRef(CFDataRef persistent_ref)
{
CFTypeRef identity_ref = NULL;
const void *keys[] = { kSecClass, kSecReturnRef, kSecValuePersistentRef };
const void *values[] = { kSecClassIdentity, kCFBooleanTrue, persistent_ref };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
3, NULL, NULL);
SecItemCopyMatching(dict, &identity_ref);
if (dict)
CFRelease(dict);
return (SecIdentityRef)identity_ref;
}
3. 從鑰匙串中查找證書
以下代碼演示如何在要是串中查找使用名稱識別的證書。在鑰匙串中找到一個持久化引用的條目,參考列表2-4。要用一個id字串查找一個條目,參考“數(shù)據(jù)加密和解密”。
Listing 2-5 Findinga certificate In the Keychain
void certificateInKeychain(){
OSStatus status = errSecSuccess;
CFTypeRef certificateRef = NULL; // 1
const char *certLabelString = "Romeo Montague";
CFStringRef certLabel = CFStringCreateWithCString(
NULL, certLabelString,
kCFStringEncodingUTF8); // 2
const void *keys[] = { kSecClass, kSecAttrLabel, kSecReturnRef };
const void *values[] = { kSecClassCertificate, certLabel, kCFBooleanTrue };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys,
values, 3,
NULL, NULL); // 3
status = SecItemCopyMatching(dict, &certificateRef); // 4
if (status == errSecSuccess) {
CFRelease(certificateRef);
certificateRef = NULL;
}
/* Do something with certificateRef here */
if (dict)
CFRelease(dict);
}
4. 獲取策略對象并評估可信度
評估證書可信度之前,必需獲取到一個證書對象的引用。你可以從一個identity中提取一個證書對象(列表 2-2),也可以從DER證書數(shù)據(jù)中創(chuàng)建證書對象(使用SecCertificateCreateWithData函數(shù),見列表2-6),或者從鑰匙串中查找證書(列表 2-5)。
評估信任度的標(biāo)準(zhǔn)由信任策略(trust policy)指定。列表3-2 顯示如何獲得用于評估的策略對象。在iOS中有兩種策略可用:Basic X509和SSL(參考AppleX509TP信任策略)。可以用SecPolicyCreateBasicX509或者SecPolicyCreateSSL函數(shù)獲取策略對象。
下列代碼顯示了獲取策略對象并用于評估證書是否可信。
Listing 2-6 Obtaining a policy reference object and evaluating trust
NSString *thePath = [[NSBundle mainBundle]
pathForResource:@"Romeo Montague" ofType:@"cer"];
NSData *certData = [[NSData alloc]
initWithContentsOfFile:thePath];
CFDataRef myCertData = (__bridge CFDataRef)certData; // 1
SecCertificateRef myCert;
myCert = SecCertificateCreateWithData(NULL, myCertData); // 2
SecPolicyRef myPolicy = SecPolicyCreateBasicX509(); // 3
SecCertificateRef certArray[1] = { myCert };
CFArrayRef myCerts = CFArrayCreate(
NULL, (void *)certArray,
1, NULL);
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(
myCerts,
myPolicy,
&myTrust); // 4
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult); // 5
}
//... // 6
if (trustResult == kSecTrustResultRecoverableTrustFailure) {
// ...;
}
// ...
if (myPolicy)
CFRelease(myPolicy);
在這段代碼中:
- 查找證書文件并獲取數(shù)據(jù)。本例中,該文件位于應(yīng)用程序束。但你也可以從網(wǎng)絡(luò)獲取證書。如果證書存在于鑰匙串中,參考“在鑰匙串中查找證書”。
- 從證書數(shù)據(jù)中創(chuàng)建certificate引用。
- 創(chuàng)建用于評估證書的策略。
- 用證書和策略創(chuàng)建信任對象(trust)。如果存在中間證書或者錨證書,應(yīng)把這些證書都包含在certificate數(shù)組中并傳遞給SecTrustCreateWithCertificates函數(shù)。這樣會加快評估的速度。
- 評估一個信任對象。
- 處理信任結(jié)果(trust result)。如果信任結(jié)果是kSecTrustResultInvalid,kSecTrustResultDeny,kSecTrustResultFatalTrustFailure,你無法進(jìn)行處理。如果信任結(jié)果是kSecTrustResultRecoverableTrustFailure,你可以恢復(fù)這個錯誤。參考“從信任失敗中恢復(fù)”。
- 釋放策略對象。
5. 從信任失敗中恢復(fù)
信任評估的結(jié)果有多個,這取決于:是否證書鏈中的所有證書都能找到并全都有效,以及用戶對這些證書的信任設(shè)置是什么。信任結(jié)果怎么處理則由你的程序來決定。例如,如果信任結(jié)果是kSecTrustResultConfirm,你可以顯示一個對話框,詢問用戶是否允許繼續(xù)。
信任結(jié)果kSecTrustResultRecoverableTrustFailure的意思是:信任被否決,但可以通過改變設(shè)置獲得不同結(jié)果。例如,如果證書簽發(fā)過期,你可以改變評估日期以判斷是否證書是有效的同時文檔是已簽名的。列表2-7 演示如何改變評估日期。注意 CFDateCreate函數(shù)使用絕對時間(從2001年1月1日以來的秒數(shù))。你可以用CFGregorianDateGetAbsoluteTime函數(shù)把日歷時間轉(zhuǎn)換為絕對時間。
void recoverFromTrustFailure(SecTrustRef myTrust)
{
SecTrustResultType trustResult;
OSStatus status = SecTrustEvaluate(myTrust, &trustResult); // 1
//Get time used to verify trust
CFAbsoluteTime trustTime,currentTime,timeIncrement,newTime;
CFDateRef newDate;
if (trustResult == kSecTrustResultRecoverableTrustFailure) {// 2
trustTime = SecTrustGetVerifyTime(myTrust); // 3
timeIncrement = 31536000; // 4
currentTime = CFAbsoluteTimeGetCurrent(); // 5
newTime = currentTime - timeIncrement; // 6
if (trustTime - newTime){ // 7
newDate = CFDateCreate(NULL, newTime); // 8
SecTrustSetVerifyDate(myTrust, newDate); // 9
status = SecTrustEvaluate(myTrust, &trustResult); // 10
}
}
if (trustResult != kSecTrustResultProceed) { // 11
//...
}
}
在這段代碼中:
評估證書可信度。參考“獲取策略對象并評估可信度”。
檢查信任評估結(jié)果是否是可恢復(fù)的失敗( kSecTrustResultRecoverableTrustFailure)。
取得證書的評估時間(絕對時間)。如果證書在評估時已經(jīng)過期了,則被認(rèn)為無效。
設(shè)置時間的遞增量為1年(以秒計算)。
取得當(dāng)前時間的絕對時間。
設(shè)置新時間(第2次評估的時間)為當(dāng)前時間減一年。
檢查評估時間是否大于1年前(最近一次評估是否1年前進(jìn)行的)。如果是,使用新時間(1年前的時間)進(jìn)行評估,看證書是否在1年前就已經(jīng)過期。
把新時間轉(zhuǎn)換為CFDateRef。也可以用NSDate,二者是完全互通的,方法中的NSDate*參數(shù),可以用CFDateRef進(jìn)行傳遞;反之亦可。
設(shè)置信任評估時間為新時間(1年前)。
再次進(jìn)行信任評估。如果證書是因?yàn)檫^期(到期時間在1年內(nèi))導(dǎo)致前次評估失敗,那么這次評估應(yīng)該成功。
再次檢查評估結(jié)果。如果仍不成功,則需要做更進(jìn)一步的操作,比如提示用戶安裝中間證書,或則友好地告知用戶證書校驗(yàn)失敗。
6.加密和解密數(shù)據(jù)(Encrypting and Decrypting Data)
證書,密鑰和信任API包含了生產(chǎn)不對稱密鑰對并用于數(shù)據(jù)加密和解密的函數(shù)。例如,您可能想要使用此功能來對你不想在備份數(shù)據(jù)中訪問的數(shù)據(jù)進(jìn)行加密?;蛘撸憧赡芟胧褂霉€/私鑰在你的iOS應(yīng)用和桌面應(yīng)用間通過網(wǎng)絡(luò)發(fā)送加密數(shù)據(jù)。列表2-8 顯示如何生成可用于手機(jī)的公/私鑰對。列表2-9 顯示如何用公鑰加密數(shù)據(jù),列表2-10 顯示如何用私鑰解密數(shù)據(jù)。注意,這幾個示例都使用了cocoa對象(如NSMutableDictionary),而不是像本章其他示例那樣使用了core foundation對象(如CFMutableDictionaryRef),Cocoa對象和對應(yīng)的Core Foundation完全相同,免費(fèi)橋接。例如:在方法中有個NSMutableDictionary *參數(shù),你可以轉(zhuǎn)化為CFMutableDictionaryRef,方法中的CFMutableDictionaryRef參數(shù),你可以轉(zhuǎn)換為NSMutableDictionary實(shí)例。
Listing 2-8 Generatinga key pair
生成密鑰對
//1 定義獨(dú)特的字符串作為屬性添加到私鑰和公鑰密鑰鏈項(xiàng),來讓他們以后更容易找到。
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";
- (void)generateKeyPairPlease
{
OSStatus status = noErr;
NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
// 2 為SecKeyGeneratePair方法中的屬性分配字典
NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
length:strlen((const char *)publicKeyIdentifier)];
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
length:strlen((const char *)privateKeyIdentifier)];
// 3 創(chuàng)建包含步驟1中定義的標(biāo)識符字符串的NSData對象
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL; // 4 為公鑰和私鑰創(chuàng)建SecKeyRef對象
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
forKey:(__bridge id)kSecAttrKeyType]; // 5 設(shè)置密鑰對類型屬性為RSA
[keyPairAttr setObject:[NSNumber numberWithInt:1024]
forKey:(__bridge id)kSecAttrKeySizeInBits]; // 6 設(shè)置密鑰對長度為1024字節(jié)
[privateKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent]; // 7 設(shè)置私鑰的持久化屬性(即是否存入鑰匙串)為YES
[privateKeyAttr setObject:privateTag
forKey:(__bridge id)kSecAttrApplicationTag]; // 8 把1-3步中的identifier放到私鑰的dictionary中
[publicKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent]; // 9 設(shè)置公鑰的持久化屬性(即是否存入鑰匙串)為YES
[publicKeyAttr setObject:publicTag
forKey:(__bridge id)kSecAttrApplicationTag]; // 10 把1-3步中的identifier放到公鑰的dictionary中
[keyPairAttr setObject:privateKeyAttr
forKey:(__bridge id)kSecPrivateKeyAttrs]; // 11 把私鑰的屬性集(dictionary)加到密鑰對的屬性集(dictionary)中
[keyPairAttr setObject:publicKeyAttr
forKey:(__bridge id)kSecPublicKeyAttrs]; // 12 把公鑰的屬性集(dictionary)加到密鑰對的屬性集(dictionary)中
status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
&publicKey, &privateKey); // 13 產(chǎn)生密鑰對
// error handling...
if(publicKey) CFRelease(publicKey);
if(privateKey) CFRelease(privateKey); // 14 釋放不用的對象內(nèi)存
}
你可以將您的公鑰發(fā)送給任何人,誰可以使用它來加密數(shù)據(jù)。如果你保持你的私鑰安全,那么只有你能夠解密數(shù)據(jù)。以下代碼示例展示了如何使用公鑰加密數(shù)據(jù)。這可以在設(shè)備上生成一個公鑰(參見前面的代碼示例)或者從發(fā)送給你或鑰匙鏈中的證書中提取公鑰。您可以使用SecTrustCopyPublicKey函數(shù)來從證書中提取公鑰。在下面的代碼示例中,假定密鑰已經(jīng)在設(shè)備上生成并放置在鑰匙串中。
Listing 2-9 Encryptingdata with a public key
用公鑰加密數(shù)據(jù)
- (NSData *)encryptWithPublicKey
{
OSStatus status = noErr;
size_t cipherBufferSize;
uint8_t *cipherBuffer; // 1 為加密文本分配緩沖區(qū)
// [cipherBufferSize]
const uint8_t dataToEncrypt[] = "the quick brown fox jumps "
"over the lazy dog\0"; // 2 指定要加密的文本
size_t dataLength = sizeof(dataToEncrypt)/sizeof(dataToEncrypt[0]);
SecKeyRef publicKey = NULL; // 3 定義SecKeyRef,用于公鑰。
NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
length:strlen((const char *)publicKeyIdentifier)]; // 4 定義NSData對象,存儲公鑰的identifier(見列表 2-8 的第1、3、8步),該id在鑰匙串中唯一。
NSMutableDictionary *queryPublicKey =
[[NSMutableDictionary alloc] init]; // 5 定義dictionary,用于從鑰匙串中查找公鑰。
[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];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// 6 設(shè)置dictionary的鍵-值屬性。屬性中指定,鑰匙串條目類型為“密鑰”,條目identifier為第4步中指定的字符串,密鑰類型為RSA,函數(shù)調(diào)用結(jié)束返回查找到的條目引用。
status = SecItemCopyMatching
((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7 調(diào)用SecItemCopyMatching函數(shù)進(jìn)行查找。
// Allocate a buffer
cipherBufferSize = SecKeyGetBlockSize(publicKey);
cipherBuffer = malloc(cipherBufferSize);
// Error handling
if (cipherBufferSize < sizeof(dataToEncrypt)) {
// Ordinarily, you would split the data up into blocks
// equal to cipherBufferSize, with the last block being
// shorter. For simplicity, this example assumes that
// the data is short enough to fit.
printf("Could not decrypt. Packet too large.\n");
return NULL;
}
// Encrypt using the public.
status = SecKeyEncrypt( publicKey,
kSecPaddingPKCS1,
dataToEncrypt,
(size_t) dataLength,
cipherBuffer,
&cipherBufferSize
); // 8 加密數(shù)據(jù), 返回結(jié)果用PKCS1格式對齊。
// Error handling
// Store or transmit the encrypted text
if (publicKey) CFRelease(publicKey);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];
free(cipherBuffer);
return encryptedData;
}
下面的代碼示例顯示了如何解密數(shù)據(jù)。這個示例使用用來加密數(shù)據(jù)的公鑰對應(yīng)的私鑰,并假設(shè)您已經(jīng)在前面的示例中創(chuàng)建的密文。從鑰匙串中獲取私鑰的技術(shù)跟前面的示例中獲取公鑰的技術(shù)相同。
Listing 2-10 Decryptingwith a private key
私鑰解密
- (void)decryptWithPrivateKey: (NSData *)dataToDecrypt
{
OSStatus status = noErr;
size_t cipherBufferSize = [dataToDecrypt length];
uint8_t *cipherBuffer = (uint8_t *)[dataToDecrypt bytes];
size_t plainBufferSize;
uint8_t *plainBuffer;
SecKeyRef privateKey = NULL;
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
length:strlen((const char *)privateKeyIdentifier)];
NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
// 1 設(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];
status = SecItemCopyMatching
((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2 從鑰匙串中找到私鑰
// Allocate the buffer
plainBufferSize = SecKeyGetBlockSize(privateKey);
plainBuffer = malloc(plainBufferSize);
if (plainBufferSize < cipherBufferSize) {
// Ordinarily, you would split the data up into blocks
// equal to plainBufferSize, with the last block being
// shorter. For simplicity, this example assumes that
// the data is short enough to fit.
printf("Could not decrypt. Packet too large.\n");
return;
}
// Error handling
status = SecKeyDecrypt( privateKey,
kSecPaddingPKCS1,
cipherBuffer,
cipherBufferSize,
plainBuffer,
&plainBufferSize
); // 3 解密數(shù)據(jù)
// Error handling
// Store or display the decrypted text
if(privateKey) CFRelease(privateKey); // 4 釋放內(nèi)存
}