http://blog.csdn.net/jerryvon/article/details/16843065
一.基本知識
1.方法
SecItemAdd 增
SecItemUpdate 改
SecItemDelete 刪
SecItemCopyMatching 查
2.權限
文檔上說iOS的keyChain是一個相對獨立的空間准夷,當程序替換,刪除時并不會刪除keyChain的內(nèi)容,這個要比Library/Cache好拂苹。刷機,恢復出廠應該就沒有了。關于備份,只會備份數(shù)據(jù)旧找,到那時不會備份設備的密鑰,換句話說麦牺,即使拿到數(shù)據(jù)钮蛛,也沒有辦法解密里面的內(nèi)容鞭缭。有人說似乎破解的手機就能破解keyChain,本人并不清楚,希望有大神能指教魏颓。但個人認為岭辣,keyChain只是沙盒的升級版,可以存放一些非私密的信息甸饱,即使破解也不影響其它用戶沦童,只影響那個破解了的設備。(比如針對該設備的一個密鑰)柜候。
可訪問性一般來說搞动,自己的程序只能訪問自己的keychain,相同bundle的程序通過設置group可以互相共享同組的keychain躏精,從而實現(xiàn)程序間可以共同訪問一些數(shù)據(jù)渣刷。詳細后面介紹一些我測試下來的經(jīng)驗。
3.如何查詢keyChain
[objc] view plain copy
print?
genericPasswordQuery = [[NSMutableDictionary alloc] init];
[genericPasswordQuery setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];//1
[genericPasswordQuery setObject:identifier forKey:(id)kSecAttrGeneric];//2
******if** (accessGroup !=** nil){
[genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];//3
}
[genericPasswordQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];//4
[genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];//5
******NSDictionary tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];
******NSMutableDictionary* outDictionary =* nil;
******if (SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef )&outDictionary) == noErr){//6
//found and outDicitionary is not nil
}else*{
//not found
}
1.設置Class值矗烛,每個Class對應的都有不同的參數(shù)類型
2.用戶確定的參數(shù)辅柴,一般是程序中使用的類別,比如說是"Password"或"Account Info"瞭吃,作為search的主力條件
3.設置Group,如果不同程序都擁有這個組碌嘀,那么不同程序間可以共享這個組的數(shù)據(jù)
4.只返回第一個匹配數(shù)據(jù),查詢方法使用歪架,還有值kSecMatchLimitAll
5.返回數(shù)據(jù)為CFDicitionaryRef股冗,查詢方法使用
6.執(zhí)行查詢方法,判斷返回值
eg:這個是none-ARC的代碼哦和蚪!ARC情況下會有bridge提示止状。
4.類型轉換
介紹增刪改方法調用前,先介紹轉換方法攒霹,如何將NSDictionary轉換成KeyChain方法可以設置的Dicitionary怯疤,一般在寫程序過程中,應該盡量避免直接訪問KeyChain催束,一般會創(chuàng)建一個NSDictionary來同步對應的數(shù)據(jù)集峦,所以兩者需要做轉換。
[objc] view plain copy
print?
//data to secItem
-
(NSMutableDictionary )dictionaryToSecItemFormat:(NSDictionary* *)dictionaryToConvert
{
// Create a dictionary to return populated with the attributes and data.
NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];//設置kSecClass
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
//將Dictionary里的kSecValueData(一般就是這個keyChain里主要內(nèi)容抠刺,比如說是password),NSString轉換成NSData
NSString passwordString = [dictionaryToConvert objectForKey:(id)kSecValueData];
[returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id*)kSecValueData];
return returnDictionary;
}
//secItem to data -
(NSMutableDictionary )secItemFormatToDictionary:(NSDictionary* *)dictionaryToConvert
{
NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];// Add the proper search key and class attribute.
[returnDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];// Acquire the password data from the attributes.
NSData passwordData = NULL;
if (SecItemCopyMatching((CFDictionaryRef)returnDictionary, (CFTypeRef* )&passwordData) == noErr)
{
// 刪除多余的kSecReturnData數(shù)據(jù)
[returnDictionary removeObjectForKey:(id*)kSecReturnData];// 對應前面的步驟塔淤,將數(shù)據(jù)從NSData轉成NSString **NSString** *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length] encoding:NSUTF8StringEncoding] autorelease]; [returnDictionary setObject:password forKey:(**id**)kSecValueData];
}
else
{
NSAssert(NO, @"Serious error, no matching item found in the keychain.\n");
}
[passwordData release];
return returnDictionary;
}
5.增刪改
用代碼來說明
[objc] view plain copy
print?
- (void)writeToKeychain
{
NSDictionary attributes = NULL;
NSMutableDictionary updateItem = NULL;
OSStatus result;
//判斷是增還是改
if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef** )&attributes) == noErr)
{
// First we need the attributes from the Keychain.
updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];
// Second we need to add the appropriate search key/values.
[updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];
// Lastly, we need to set up the updated attribute list being careful to remove the class.
NSMutableDictionary tempCheck = [self** dictionaryToSecItemFormat:keychainItemData];
//刪除kSecClass update不能update該字段,否則會報錯
[tempCheck removeObjectForKey:(id)kSecClass];
//參數(shù)1表示search的速妖,參數(shù)2表示需要更新后的值
result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
}else{
//增加
result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
}
}
刪除很簡單凯沪,就不寫注釋了
[objc] view plain copy
print?
-
(void)resetKeychainItem
{
OSStatus junk = noErr;
if (!keychainItemData)
{
self.keychainItemData = [[NSMutableDictionary alloc] init];
}
else if (keychainItemData)
{
NSMutableDictionary tempDictionary = [self* dictionaryToSecItemFormat:keychainItemData];
junk = SecItemDelete((CFDictionaryRef)tempDictionary);
NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." );
}// Default attributes for keychain item.
[keychainItemData setObject:@"" forKey:(id)kSecAttrAccount];
[keychainItemData setObject:@"" forKey:(id)kSecAttrLabel];
[keychainItemData setObject:@"" forKey:(id)kSecAttrDescription];// Default data for keychain item.
[keychainItemData setObject:@"" forKey:(id)kSecValueData];
}
二.Group的配置
配置Target的Code Signing Entitlements.
配置該文件
可以配置一個Array列表,表示該程序可以支持多個group
這樣就可以在創(chuàng)建secItem時候添加kSecAttrAccessGroup了买优。
經(jīng)過測試有以下經(jīng)驗同大家分享:
1.相同bundle下生成的程序都可以共享相同group的keyChain.
相同bundle解釋下就是:比如:2個程序分別使用的provision對應bundle是com.jv.key1和com.jv.key2妨马,那你配置文件肯定是{Identifer}.com.jv.{name},其中identifer是蘋果生成的隨機串號挺举,可以在申請證書時看到,復制過來即可烘跺,name可以自己取湘纵,程序中指定屬于哪個Group即可。
2.如果你在 addkey時滤淳,沒有指定group,則會默認添加你keychain-access-groups里第一個group梧喷,如果你沒有設置Entitlements,則默認使用對應的程序的bundle name,比如com.jv.key1,表示只能給自己程序使用。
3.如果你程序添加的group并不存在你的配置文件中脖咐,程序會奔潰铺敌,表示無法添加。因此你只能添加你配置文件中支持的keychain屁擅。
參考資料:
蘋果文檔:
Keychain Services Reference
Certificate, Key, and Trust Services Programming Guide
Keychain Services Programming Guide