KeychainItemWrapper ---- 官方封裝文件

KeychainItemWrapper.H

/*? ? File: KeychainItemWrapper.h Abstract:? Objective-C wrapper for accessing a single keychain item.? Version: 1.2? Disclaimer: IMPORTANT:? This Apple software is supplied to you by Apple Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms.? If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software.? In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple.? Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated.? The Apple Software is provided by Apple on an "AS IS" basis.? APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.? IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.? Copyright (C) 2010 Apple Inc. All Rights Reserved.?

*/

#import<UIKit/UIKit.h>

/*

The KeychainItemWrapper class is an abstraction layer for the iPhone Keychain communication. It is merely a

simple wrapper to provide a distinct barrier between all the idiosyncracies involved with the Keychain

CF/NS container objects.

*/

@interface KeychainItemWrapper : NSObject

{

NSMutableDictionary *keychainItemData; // The actual keychain item data backing store.

NSMutableDictionary *genericPasswordQuery; // A placeholder for the generic keychain item query used to locate the item.

}

@property (nonatomic, retain) NSMutableDictionary *keychainItemData;

@property (nonatomic, retain) NSMutableDictionary *genericPasswordQuery;

// Designated initializer.

- (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;

- (void)setObject:(id)inObject forKey:(id)key;

- (id)objectForKey:(id)key;

// Initializes and resets the default generic keychain item data.

- (void)resetKeychainItem;

@end



keychainItemWrapper.m


/*? ? File: KeychainItemWrapper.m? Abstract:? Objective-C wrapper for accessing a single keychain item.? ? Version: 1.2? ? Disclaimer: IMPORTANT:? This Apple software is supplied to you by Apple? Inc. ("Apple") in consideration of your agreement to the following? terms, and your use, installation, modification or redistribution of? this Apple software constitutes acceptance of these terms.? If you do? not agree with these terms, please do not use, install, modify or? redistribute this Apple software.? ? In consideration of your agreement to abide by the following terms, and? subject to these terms, Apple grants you a personal, non-exclusive? license, under Apple's copyrights in this original Apple software (the? "Apple Software"), to use, reproduce, modify and redistribute the Apple? Software, with or without modifications, in source and/or binary forms;? provided that if you redistribute the Apple Software in its entirety and? without modifications, you must retain this notice and the following? text and disclaimers in all such redistributions of the Apple Software.? Neither the name, trademarks, service marks or logos of Apple Inc. may? be used to endorse or promote products derived from the Apple Software? without specific prior written permission from Apple.? Except as? expressly stated in this notice, no other rights or licenses, express or? implied, are granted by Apple herein, including but not limited to any? patent rights that may be infringed by your derivative works or by other? works in which the Apple Software may be incorporated.? ? The Apple Software is provided by Apple on an "AS IS" basis.? APPLE? MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION? THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS? FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND? OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.? ? IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL? OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF? SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS? INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,? MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED? AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),? STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE? POSSIBILITY OF SUCH DAMAGE.? ? Copyright (C) 2010 Apple Inc. All Rights Reserved.? */

?#import "KeychainItemWrapper.h"

#import<Security/Security.h>

/*

These are the default constants and their respective types,

available for the kSecClassGenericPassword Keychain Item class:

kSecAttrAccessGroup - CFStringRef

kSecAttrCreationDate - CFDateRef

kSecAttrModificationDate? ? - CFDateRef

kSecAttrDescription - CFStringRef

kSecAttrComment - CFStringRef

kSecAttrCreator - CFNumberRef

kSecAttrType? ? ? ? ? ? ? ? - CFNumberRef

kSecAttrLabel - CFStringRef

kSecAttrIsInvisible - CFBooleanRef

kSecAttrIsNegative - CFBooleanRef

kSecAttrAccount - CFStringRef

kSecAttrService - CFStringRef

kSecAttrGeneric - CFDataRef

See the header file Security/SecItem.h for more details.

*/

@interface KeychainItemWrapper (PrivateMethods)

/*

The decision behind the following two methods (secItemFormatToDictionary and dictionaryToSecItemFormat) was

to encapsulate the transition between what the detail view controller was expecting (NSString *) and what the

Keychain API expects as a validly constructed container class.

*/

- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert;

- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert;

// Updates the item in the keychain, or adds it if it doesn't exist.

- (void)writeToKeychain;

@end

@implementation KeychainItemWrapper

@synthesize keychainItemData, genericPasswordQuery;

- (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;

{

if (self = [super init])

{

// Begin Keychain search setup. The genericPasswordQuery leverages the special user

// defined attribute kSecAttrGeneric to distinguish itself between other generic Keychain

// items which may be included by the same application.

genericPasswordQuery = [[NSMutableDictionary alloc] init];

[genericPasswordQuery setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];

[genericPasswordQuery setObject:identifier forKey:(id)kSecAttrGeneric];

// The keychain access group attribute determines if this item can be shared

// amongst multiple apps whose code signing entitlements contain the same keychain access group.

if (accessGroup != nil)

{

#if TARGET_IPHONE_SIMULATOR

// Ignore the access group if running on the iPhone simulator.

//

// Apps that are built for the simulator aren't signed, so there's no keychain access group

// for the simulator to check. This means that all apps can see all keychain items when run

// on the simulator.

//

// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the

// simulator will return -25243 (errSecNoAccessForItem).

#else

[genericPasswordQuery setObject:accessGroup forKey:(id)kSecAttrAccessGroup];

#endif

}

// Use the proper search constants, return only the attributes of the first match.

[genericPasswordQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];

[genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];

NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery];

NSMutableDictionary *outDictionary = nil;

if (! SecItemCopyMatching((CFDictionaryRef)tempQuery, (CFTypeRef *)&outDictionary) == noErr)

{

// Stick these default values into keychain item if nothing found.

[self resetKeychainItem];

// Add the generic attribute and the keychain access group.

[keychainItemData setObject:identifier forKey:(id)kSecAttrGeneric];

if (accessGroup != nil)

{

#if TARGET_IPHONE_SIMULATOR

// Ignore the access group if running on the iPhone simulator.

//

// Apps that are built for the simulator aren't signed, so there's no keychain access group

// for the simulator to check. This means that all apps can see all keychain items when run

// on the simulator.

//

// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the

// simulator will return -25243 (errSecNoAccessForItem).

#else

[keychainItemData setObject:accessGroup forKey:(id)kSecAttrAccessGroup];

#endif

}

}

else

{

// load the saved data from Keychain.

self.keychainItemData = [self secItemFormatToDictionary:outDictionary];

}

[outDictionary release];

}

return self;

}

- (void)dealloc

{

[keychainItemData release];

[genericPasswordQuery release];

[super dealloc];

}

- (void)setObject:(id)inObject forKey:(id)key

{

if (inObject == nil) return;

id currentObject = [keychainItemData objectForKey:key];

if (![currentObject isEqual:inObject])

{

[keychainItemData setObject:inObject forKey:key];

[self writeToKeychain];

}

}

- (id)objectForKey:(id)key

{

return [keychainItemData objectForKey:key];

}

- (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];

}

- (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert

{

// The assumption is that this method will be called with a properly populated dictionary

// containing all the right key/value pairs for a SecItem.

// Create a dictionary to return populated with the attributes and data.

NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert];

// Add the Generic Password keychain item class attribute.

[returnDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];

// Convert the NSString to NSData to meet the requirements for the value type kSecValueData.

// This is where to store sensitive data that should be encrypted.

NSString *passwordString = [dictionaryToConvert objectForKey:(id)kSecValueData];

[returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];

return returnDictionary;

}

- (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert

{

// The assumption is that this method will be called with a properly populated dictionary

// containing all the right key/value pairs for the UI element.

// Create a dictionary to return populated with the attributes and data.

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)

{

// Remove the search, class, and identifier key/value, we don't need them anymore.

[returnDictionary removeObjectForKey:(id)kSecReturnData];

// Add the password to the dictionary, converting from NSData to NSString.

NSString *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length]

encoding:NSUTF8StringEncoding] autorelease];

[returnDictionary setObject:password forKey:(id)kSecValueData];

}

else

{

// Don't do anything if nothing is found.

NSAssert(NO, @"Serious error, no matching item found in the keychain.\n");

}

[passwordData release];

return returnDictionary;

}

- (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];

[tempCheck removeObjectForKey:(id)kSecClass];

#if TARGET_IPHONE_SIMULATOR

// Remove the access group if running on the iPhone simulator.

//

// Apps that are built for the simulator aren't signed, so there's no keychain access group

// for the simulator to check. This means that all apps can see all keychain items when run

// on the simulator.

//

// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the

// simulator will return -25243 (errSecNoAccessForItem).

//

// The access group attribute will be included in items returned by SecItemCopyMatching,

// which is why we need to remove it before updating the item.

[tempCheck removeObjectForKey:(id)kSecAttrAccessGroup];

#endif

// An implicit assumption is that you can only update a single item at a time.

result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);

NSAssert( result == noErr, @"Couldn't update the Keychain Item." );

}

else

{

// No previous item found; add the new one.

result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);

NSAssert( result == noErr, @"Couldn't add the Keychain Item." );

}

}

@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子移国,更是在濱河造成了極大的恐慌召庞,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異构蹬,居然都是意外死亡惋鹅,警方通過查閱死者的電腦和手機则酝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闰集,“玉大人沽讹,你說我怎么就攤上這事般卑。” “怎么了爽雄?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵蝠检,是天一觀的道長。 經(jīng)常有香客問我挚瘟,道長叹谁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任乘盖,我火速辦了婚禮傻工,結(jié)果婚禮上山析,老公的妹妹穿的比我還像新娘购裙。我一直安慰自己蛀醉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布布蔗。 她就那樣靜靜地躺著藤违,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纵揍。 梳的紋絲不亂的頭發(fā)上顿乒,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音泽谨,去河邊找鬼璧榄。 笑死,一個胖子當(dāng)著我的面吹牛吧雹,可吹牛的內(nèi)容都是我干的骨杂。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼雄卷,長吁一口氣:“原來是場噩夢啊……” “哼搓蚪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起丁鹉,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤妒潭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后揣钦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雳灾,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年冯凹,在試婚紗的時候發(fā)現(xiàn)自己被綠了谎亩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖匈庭,靈堂內(nèi)的尸體忽然破棺而出夫凸,到底是詐尸還是另有隱情,我是刑警寧澤嚎花,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站呀洲,受9級特大地震影響紊选,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜道逗,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一兵罢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滓窍,春花似錦卖词、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至噪生,卻和暖如春裆赵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跺嗽。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工战授, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桨嫁。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓植兰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親璃吧。 傳聞我的和親對象是個殘疾皇子楣导,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容