• (转)iOS keychain API及其封装


    一. Keychain API

    KeyChain中item的结构为:

    1.增加keychain Item

    OSStatus SecItemAdd (CFDictionaryRef attributes,CFTypeRef *result);
    attributes字典中包括增加items的类型键值对和对应类型的属性键值对。item类型键常量为kSecClass,可能的取值为通用密码(kSecClassGenericPassword),网络密码(kSecClassInternetPassword),证书(kSecClassCertificate),密匙(kSecClassKey),ID(带有密匙的证书kSecClassIdentity)。每种类型的item具有不同的可选属性,具体可见Keychain Item Class Keys and Values

    若增加item成功,result则为新增加item的引用,其具体类型由attributes中的特定键指定。

    • 若kSecReturnData设置为kCFBooleanTrue,则result类型为CFDataRef;
    • 若kSecReturnAttributes设置为kCFBooleanTrue,则result类型为CFDictionaryRef;
    • 若kSecReturnRef设置为kCFBooleanTrue,则result类型为SecKeychainItemRef, SecKeyRef,SecCertificateRef, 或SecIdentityRef,当返回类型没有显式设置时,则默认为此设置。
    • 若kSecReturnPersistentRef设置为kCFBooleanTrue,则result类型为持久存储的CFDataRef,持久存储的CFDataRef可存储在磁盘或在进程之间传递。
    • 若以上多个返回类型被设置,则返回CFDictionaryRef类型。

    2.查询keychain item

    OSStatus SecItemCopyMatching (CFDictionaryRef query,CFTypeRef *result);
    根据query指定的属性查找item,并将结果存储在result中。

    3.删除item

    OSStatus SecItemDelete (CFDictionaryRef query);
    删除query指定的item.

    4.更新item

    OSStatus SecItemUpdate (CFDictionaryRef query,CFDictionaryRef attributesToUpdate);
    将query指定的item中的属性按照attributesToUpdate中的数据更新。

    参考:
    iOS 的keyChain
    Keychain Services Reference

    二.封装方式一:KeychainWrapper

    1. +(NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier;

    所有以下操作的基础,设置在增加、查找、更新、删除items时的通用属性字典。
    设置内容伪码如下:
    kSecClass = kSecClassGenericPassword;
    kSecAttrService = APP_NAME(应用标示符);
    kSecAttrGeneric = [identifier dataUsingEncoding:NSUTF8StringEncoding];
    kSecAttrAccount = [identifier dataUsingEncoding:NSUTF8StringEncoding];

    2. +(NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier;

    调用SecItemCopyMatching获取与identifier匹配的item内容,返回类型为kSecReturnData。
    使用的查找属性:
    kSecMatchLimit = kSecMatchLimitOne;
    kSecReturnData = kCFBooleanTrue;

    3. +(NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier;

    将searchKeychainCopyMatchingIdentifier:identifier获取的NSData结果转换为字符串。
    [[NSString alloc] initWithData:valueData encoding:NSUTF8StringEncoding];

    4. +(BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;

    调用SecItemAdd增加新的item.
    kSecValueData = (NSData*)value;
    kSecAttrAccessible = kSecAttrAccessibleWhenUnlocked;
    或identifier匹配的item已存在,则使用updateKeychainValue:forIdentifier更新item的data。

    5. +(BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier;

    调用SecItemUpdate将identifier匹配的items的kSecValueData内容修改为(NSData*)value。

    6. +(void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier;

    调用SecItemDelete删除identifier匹配的item。

    SourceCode:
    KeychainWrapper.h
    KeychainWrapper.m

    参考:
    Basic Security in iOS 5 Tutorial Part 1
    Basic Security in iOS 5 Tutorial Part 2

    三.封装方式二:SFHFKeychainUtils

    1.+(NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

    获取serviceName和username匹配的item数据.
    查找属性字典:
    kSecClass = kSecClassGenericPassword;
    kSecAttrAccount = username;
    kSecAttrService = serviceName;
    首先使用kSecReturnAttributes = kCFBooleanTrue;查找属性值是否存在。
    若属性存在,则使用kSecReturnData = kCFBooleanTrue;获取data即密码字段,并转换称NSString返回。
    属性存在,而密码不存在时返回特殊的错误码。

    2.+(BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error;

    设置serviceName和username的密码为password。
    已存在则update(SecItemUpdate),不存在则add(SecItemAdd)。
    kSecClass = kSecClassGenericPassword;
    kSecAttrService = serviceName;
    kSecAttrLabel = serviceName;
    kSecAttrAccount = username;
    kSecValueData = [password dataUsingEncoding: NSUTF8StringEncoding];

    3.+(BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

    删除serviceName,username对应的item。

    使用方式:

    存储用户名/密码对,通过用户名获取到对应的密码

        #import “SFHFKeychainUtils.h”
    
        //Store new Password in keychain
        NSError *error = nil;
        NSString *username = usernameFiled.text;
        NSString *password = passwordField.text;
        [SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:@"myApp",updateExisting:TRUE error:&err];
    
        //Get password from keychain
        NSError *error = nil;
        NSString *username = @"xuguoxing";
        password = [SFHFKeychainUtils getPasswordForUsername:username andServiceName:@"myApp",error:&err];

    SourceCode:
    https://github.com/ldandersen/scifihifi-iphone/tree/master/security/
    SFHFKeychainUtils.h
    SFHFKeychainUtils.m

    参考:
    Simple iPhone Tutorial: Password Management using the keychain by using SFHFKeychainUtils

    三.封装方式三:苹果提供的KeychainItemWrapper

    - (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup;
    - (void)setObject:(id)inObject forKey:(id)key;
    - (id)objectForKey:(id)key;
    - (void)resetKeychainItem;

    使用方式:

    每个keychain用Identifier标示,根据keychain的各种key设置value,同时可以根据key获取到value。

    KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"KeychainTest" accessGroup:nil];
    [keychain setObject:kSecAttrAccessibleWhenUnlocked forKey:kSecAttrAccessible];
    
    NSLog(@"%@, %@", [keychain objectForKey:kSecAttrAccount], [keychain objectForKey:kSecValueData]);
    
    [keychain setObject:@"example@email.com" forKey:kSecAttrAccount];
    [keychain setObject:@"MySuperSecretPassword" forKey:kSecValueData];
    
    [keychain release]; 

    SourceCode:
    KeychainItemWrapper.h
    KeychainItemWrapper.m

    参考:
    GenericKeychain
    Using the Keychain to store passwords on iOS

    本文出自 清风徐来,水波不兴 的博客,转载时请注明出处及相应链接。

    本文永久链接: http://www.winddisk.com/2012/04/09/keychain-api%e5%8f%8a%e5%85%b6%e5%b0%81%e8%a3%85/

  • 相关阅读:
    Oracle
    Oracle
    Oracle
    PTA | 1012 数字分类 (20分)
    PTA | 1010 一元多项式求导 (25分)
    PTA | 1009说反话(20分)
    PTA | 1008 数组元素循环右移问题 (20分)
    PTA | 1005 继续(3n+1)猜想 (25分)
    LeetCode 题解 | 70. 爬楼梯
    LeetCode 题解 | 242. 有效的字母异位词
  • 原文地址:https://www.cnblogs.com/greywolf/p/3461429.html
Copyright © 2020-2023  润新知