2012/08/24

iOS儲存機密資料

怎麼在iOS上儲存機密資料呢,譬如密碼,這些資料必須加密後存放,不能被第三方輕易地竊取。到網路上搜尋後,大概會找到Apple官方的Keychain Service這套API,以及GenericKeychain這份範例程式碼。

經過一番奮鬥,詳細研讀Apple官方文件與網路上的教學文章後,我似乎勉強搞懂 SecItemCopyMatching、SecItemAdd、SecItemUpdate、SecItemDelete的用法與各種相關資料結構與常數的意義了。但是,這套API似乎太低階,當初設計的初衷大概考慮了讓多支軟體在同個環境內能共享或保護私密資料,對於我來說(只是想儲存專供我軟體使用的機密資料),非常難用,障礙很多,很容易出錯。

這種情形不就跟Joel說的一樣嗎,世界上有0.1%的人能學會C++寫程式,卻只有0.01%的人能搞懂ATL,而且每個人都留鬍子戴眼鏡,哇賽,還真的有這種讓人頭昏眼花的API啊。

或許Keychain Service還沒到那個地步,但實在不夠好用,還好,有人將Keychain Service雜七雜八的細節包了起來,提供一套輕便簡易的API,讓我們可以輕易地儲存機密資料,那就是STKeychain(前身為scifihifi-iphone)。

STKeychain原始碼放在GitHub的ldandersen / STUtils裡,位於子目錄Security裡,裡面有兩支檔案STKeychain.h與STKeychain.m,加入專案後,再加入Security.framework開發框架便完成了準備動作。(ldandersen / STUtils有許多子目錄,為其他不同功能,有興趣請自行試試看。)

因為我只使用STKeychain這兩支檔案,所以要把STKeychain.m前面的「#import "STUtils"」改成「STKeychain.h」。

STKeychain並未使用ARC,若你使用ARC的話記得在STKeychain.m檔加入編譯參數 -fno-objc-arc。

介面有三個,非常清楚。

首先是儲存,傳入你想儲存的username、password、serviceName,一般來說,username與serviceName是公開的,會儲存在別的地方,而這裡是把username與serviceName當做「鍵」的角色,將password儲存在安全的地方。參數updateExisting的意思是,若該筆資料已經存在的話要不要覆蓋過去,當出錯時可從參數error得到錯誤訊息,不需要就傳入nil;回傳BOOL代表儲存成功或失敗。
+ (BOOL)storeUsername:(NSString *)username andPassword:(NSString *)password forServiceName:(NSString *)serviceName updateExisting:(BOOL)updateExisting error:(NSError **)error;

然後是取出,傳入先前使用的username與serviceName,找出相對應的password回傳。
+ (NSString *)getPasswordForUsername:(NSString *)username andServiceName:(NSString *)serviceName error:(NSError **)error;

底下是刪除,應該無需多作說明。
+ (BOOL)deleteItemForUsername:(NSString *)username andServiceName:(NSString *)serviceName error:(NSError **)error;

這套API在iOS與Mac OS X上皆可使用,非常方便、簡單,太好囉,不用再跟Apple的Keychain Service奮鬥了!

No comments:

Post a Comment