iOS的密碼管理系統 Keychain的介紹和使用
Keychain 的介紹
Keychain 是蘋果公司 Mac OS(也包含 Mac OSX) 中的密碼管理系統。
Keychain的作用
Keychain 可以包含許多種型別的資料:密碼(包括網站、FTP伺服器、SSH賬戶、網路共享、無線網路、群組軟體、加密磁碟映象),私鑰,電子證書、加密筆記等。
Keychain 的四個方法介紹
1、儲存資料的方法
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result)
@attributes : 是要新增的資料。
@result : 這是儲存資料後,返回一個指向該資料的引用,如果不是使用該引用時可以傳入 NULL 。
2、根據條件查詢資料
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result)
@query : 要查詢資料的條件。
@result: 根據條件查詢得到資料的引用。
3、更新資料
OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0);
@query : 要更新資料的查詢條件。
@attributesToUpdate : 要更新的資料。
4、刪除資料
OSStatus SecItemDelete(CFDictionaryRef query)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_2_0);
@query : 刪除的資料的查詢條件。
5、總結
以上四個方法,就是Keychain 的常用的四個方法,也就是 增、刪、改、查 。一般應用這四個方法就可以完全滿足。
Keychain 的一些Key 和 Value 的解釋和介紹
1、設定資訊的保密程度
2、kSecClass 的可選value
3、kSecClassGenericPassword 密碼所包含的所有型別引數
其他密碼的引數和普通密碼的引數大致相同,就不一一列舉。
Keychain 的封裝類KeyChainManager 的介紹和使用
1、該類的 .h 檔案
//
// KeyChainManager.h
// KeyChain
//
// Created by MAC on 2017/11/8.
// Copyright © 2017年 NetworkCode小賤. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface KeyChainManager : NSObject
/*!
儲存資料
@data 要儲存的資料
@identifier 儲存資料的標示
*/
+(BOOL) keyChainSaveData:(id)data withIdentifier:(NSString*)identifier ;
/*!
讀取資料
@identifier 儲存資料的標示
*/
+(id) keyChainReadData:(NSString*)identifier ;
/*!
更新資料
@data 要更新的資料
@identifier 資料儲存時的標示
*/
+(BOOL)keyChainUpdata:(id)data withIdentifier:(NSString*)identifier ;
/*!
刪除資料
@identifier 資料儲存時的標示
*/
+(void) keyChainDelete:(NSString*)identifier ;
@end
2、該類的 .m 檔案
//
// KeyChainManager.m
// KeyChain
// Created by MAC on 2017/11/8.
// Copyright © 2017年 NetworkCode小賤. All rights reserved.
//
#import "KeyChainManager.h"
#import <Security/Security.h>
@implementation KeyChainManager
/*!
建立生成儲存資料查詢條件
*/
+(NSMutableDictionary*) keyChainIdentifier:(NSString*)identifier {
NSMutableDictionary * keyChainMutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,kSecClass,identifier,kSecAttrService,identifier,kSecAttrAccount,kSecAttrAccessibleAfterFirstUnlock,kSecAttrAccessible, nil];
return keyChainMutableDictionary;
}
/*!
儲存資料
*/
+(BOOL) keyChainSaveData:(id)data withIdentifier:(NSString*)identifier{
// 獲取儲存的資料的條件
NSMutableDictionary * saveQueryMutableDictionary = [self keyChainIdentifier:identifier];
// 刪除舊的資料
SecItemDelete((CFDictionaryRef)saveQueryMutableDictionary);
// 設定新的資料
[saveQueryMutableDictionary setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
// 新增資料
OSStatus saveState = SecItemAdd((CFDictionaryRef)saveQueryMutableDictionary, nil);
// 釋放物件
saveQueryMutableDictionary = nil ;
// 判斷是否儲存成功
if (saveState == errSecSuccess) {
return YES;
}
return NO;
}
/*!
讀取資料
*/
+(id) keyChainReadData:(NSString*)identifier{
id idObject = nil ;
// 通過標記獲取資料查詢條件
NSMutableDictionary * keyChainReadQueryMutableDictionary = [self keyChainIdentifier:identifier];
// 這是獲取資料的時,必須提供的兩個屬性
// TODO: 查詢結果返回到 kSecValueData
[keyChainReadQueryMutableDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
// TODO: 只返回搜尋到的第一條資料
[keyChainReadQueryMutableDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
// 建立一個數據物件
CFDataRef keyChainData = nil ;
// 通過條件查詢資料
if (SecItemCopyMatching((CFDictionaryRef)keyChainReadQueryMutableDictionary , (CFTypeRef *)&keyChainData) == noErr){
@try {
idObject = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)(keyChainData)];
} @catch (NSException * exception){
NSLog(@"Unarchive of search data where %@ failed of %@ ",identifier,exception);
}
}
if (keyChainData) {
CFRelease(keyChainData);
}
// 釋放物件
keyChainReadQueryMutableDictionary = nil;
// 返回資料
return idObject ;
}
/*!
更新資料
@data 要更新的資料
@identifier 資料儲存時的標示
*/
+(BOOL)keyChainUpdata:(id)data withIdentifier:(NSString*)identifier {
// 通過標記獲取資料更新的條件
NSMutableDictionary * keyChainUpdataQueryMutableDictionary = [self keyChainIdentifier:identifier];
// 建立更新資料字典
NSMutableDictionary * updataMutableDictionary = [NSMutableDictionary dictionaryWithCapacity:0];
// 儲存資料
[updataMutableDictionary setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
// 獲取儲存的狀態
OSStatus updataStatus = SecItemUpdate((CFDictionaryRef)keyChainUpdataQueryMutableDictionary, (CFDictionaryRef)updataMutableDictionary);
// 釋放物件
keyChainUpdataQueryMutableDictionary = nil;
updataMutableDictionary = nil;
// 判斷是否更新成功
if (updataStatus == errSecSuccess) {
return YES ;
}
return NO;
}
/*!
刪除資料
*/
+(void) keyChainDelete:(NSString*)identifier {
// 獲取刪除資料的查詢條件
NSMutableDictionary * keyChainDeleteQueryMutableDictionary = [self keyChainIdentifier:identifier];
// 刪除指定條件的資料
SecItemDelete((CFDictionaryRef)keyChainDeleteQueryMutableDictionary);
// 釋放記憶體
keyChainDeleteQueryMutableDictionary = nil ;
}
@end
KeyChainManager 類的測試使用
1、測試程式碼
// 儲存資料
BOOL save = [KeyChainManager keyChainSaveData:@"思念訴說,眼神多像雲朵" withIdentifier:Keychain];
if (save) {
NSLog(@"儲存成功");
}else {
NSLog(@"儲存失敗");
}
// 獲取資料
NSString * readString = [KeyChainManager keyChainReadData:Keychain];
NSLog(@"獲取得到的資料:%@",readString);
// 更新資料
BOOL updata = [KeyChainManager keyChainUpdata:@"長髮落寞,我期待的女孩" withIdentifier:Keychain];
if (updata) {
NSLog(@"更新成功");
}else{
NSLog(@"更新失敗");
}
// 讀取資料
NSString * readUpdataString = [KeyChainManager keyChainReadData:Keychain];
NSLog(@"獲取更新後得到的資料:%@",readUpdataString);
// 刪除資料
[KeyChainManager keyChainDelete:Keychain];
// 讀取資料
NSString * readDeleteString = [KeyChainManager keyChainReadData:Keychain];
NSLog(@"獲取刪除後得到的資料:%@",readDeleteString);