1. 程式人生 > >iOS的密碼管理系統 Keychain的介紹和使用

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);

2、測試結果的展示

這裡寫圖片描述