使用KeyChain保存敏感信息

  1. Demo
  2. KeyChain基础
  3. 为什么使用KeyChain呢?
    第一个原因:安全性高。在iOS中保存数据的方式有很多,类如NSUserDefaults、plist文件保存、数据库等。但是这些方式的安全性都不高,如果是普通数据还可以使用,但如果要保存密码、序列号、证书等敏感信息时,那些方式就显得不太安全了。这时就需要用到KeyChain了。
    第二个原因:Keychain里保存的信息不会因App被删除而丢失。Keychain的信息是存在于每个应用(app)的沙盒之外的,所以keychain里保存的信息不会因App被删除而丢失,在用户重新安装App后依然有效,数据还在。
  4. 如何使用(这里以保存用户名和密码为例)
    第一步:新建一个类
#import 
#import 

@interface SZYKeychain : NSObject

+(void)saveKeychain:(NSString *)service withData:(id)data;
+(id)loadKeychain:(NSString *)service;
+(void)deleteKeyChain:(NSString *)service;

@end

第二步:实现方法

//
//  SZYKeychain.m
//  Keychain_Demo
//
//  Created by apple on 16/6/1.
//  Copyright © 2016年 apple. All rights reserved.
//

#import "SZYKeychain.h"

@implementation SZYKeychain

+(NSMutableDictionary *)getKeychainQuery:(NSString *)service {
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
            service,(__bridge_transfer id)kSecAttrService,
            service,(__bridge_transfer id)kSecAttrAccount,
            (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
            nil];
}

+(void)saveKeychain:(NSString *)service withData:(id)data {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data]
                      forKey:(__bridge_transfer id)kSecValueData];
    SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}

+(id)loadKeychain:(NSString *)service {
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    [keychainQuery setObject:(id)kCFBooleanTrue
                      forKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(id)kSecMatchLimitOne
                      forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        @try {
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
        }
        @catch (NSException *exception) {
            NSLog(@"Unarchive of %@ failed:%@",service, exception);
        }
        @finally {
        }
    }

    return ret;
}

+(void)deleteKeyChain:(NSString *)service {
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}

@end

第三步:使用
定义几个Key

static NSString *const kSZYKeyChain_USERNAME_PASSWORD = @"cc.suzhenyu.usernamepassword";
static NSString *const kSZYKeyChain_USERNAME = @"cc.suzhenyu.username";
static NSString *const kSZYKeyChain_PASSWORD = @"cc.suzhenyu.password";

存:

NSMutableDictionary *dataDict = [[NSMutableDictionary alloc] init];
[dataDict setObject:username forKey:kSZYKeyChain_USERNAME];
[dataDict setObject:password forKey:kSZYKeyChain_PASSWORD];
[SZYKeychain saveKeychain:kSZYKeyChain_USERNAME_PASSWORD withData:dataDict];

取:

NSMutableDictionary *dataDict = (NSMutableDictionary *)[SZYKeychain loadKeychain:kSZYKeyChain_USERNAME_PASSWORD];
NSLog(@"username:%@,password:%@",[dataDict objectForKey:kSZYKeyChain_USERNAME],[dataDict objectForKey:kSZYKeyChain_PASSWORD]);

删:

[SZYKeychain deleteKeyChain:kSZYKeyChain_USERNAME_PASSWORD];

参考资料:

  1. 为什么直接把密码存储在NSUserDefaults中不安全?

你可能感兴趣的:(使用KeyChain保存敏感信息)