KeyChainとは
ざっくり書くと
- 機密情報を安全に取り扱う仕組み
- パスワードや秘密鍵・公開鍵などの機密情報を安全に管理するための仕組み
また、KeyChainで管理する情報は暗号化されているとのこと
ユーザの情報を保存する仕組みとして UserDefaults
がありますが、これは設定ファイルなどのプリファレンス情報を管理するための仕組み。
UserDefaultsとの違い
- アプリが削除されてもデータが残る
- 同じKeychain Access Groupに属するアプリ同士でアクセスできる
- データが暗号化される
準備
プロジェクト作成
Frameworkの追加
Linked Frameworks and Libraries
から Security.framework
を追加する。
ライブラリインストール
今回はKeyChainの便利なライブラリを使用します。
Podfile
pod 'LUKeychainAccess', '~> 1.2'
$ pod install
$ open PROJECT_NAME.xcworkspace/
KeyChain準備
KeyChain Groupは私の場合は moe.nnsnodnb.*
のアプリ間で連携することができます。
GoogleさんがリリースされているアプリはこのKeyChain Groupを使って初めてのログイン以降は自動的にログインができるようになっているのではないでしょうか?
準備はとりあえず完了!!
アクセス制御
KeyChainはアプリを削除してもデータが残っているということでアクセス制御が Accessible属性
として存在しています。
今回は LUKeychainAccess
に実装されている Accessible属性
について
Accessible属性 | 概要 |
---|---|
LUKeychainAccessAttrAccessibleAfterFirstUnlock | 再起動後最初のアンロック以降/次の再起動まで |
LUKeychainAccessAttrAccessibleAfterFirstUnlockThisDeviceOnly | 再起動後最初のアンロック以降/次の再起動まで |
LUKeychainAccessAttrAccessibleAlways | 常にアクセス可 |
LUKeychainAccessAttrAccessibleAlwaysThisDeviceOnly | 常にアクセス可 |
LUKeychainAccessAttrAccessibleWhenUnlocked | デバイスがアンロックされた状態 |
LUKeychainAccessAttrAccessibleWhenUnlockedThisDeviceOnly | デバイスがアンロックされた状態 |
というような感じ
注意
- シミュレータによるビルドはシミュレータによるグループの取り扱いがすべて
test
となってしまうので実機でのビルドをすること - Debug用ビルドやAdHoc用ビルドなどでは、
Code Signing Identity
が異なるためKeyChainアクセスがアプリ間では行えません
ソースコード
今回はボタンを押すと「 小泉花陽ちゃん 」という文字が出力されるようなものを作成しました。
ViewController.m
#import "ViewController.h"
#import <LUKeychainAccess/LUKeychainAccess.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *label;
- (IBAction)callKeyChain:(id)sender;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
LUKeychainAccess *keychainAccess = [LUKeychainAccess standardKeychainAccess];
keychainAccess.accessibilityState = LUKeychainAccessAttrAccessibleWhenUnlocked;
[[LUKeychainAccess standardKeychainAccess] setString:@"小泉花陽ちゃん" forKey:@"rice"];
self.label.hidden = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (IBAction)callKeyChain:(id)sender {
self.label.hidden = NO;
self.label.text = [[LUKeychainAccess standardKeychainAccess] stringForKey:@"rice"];
}
@end
実行サンプル
いろんな型をKeyChainに管理させる
TestKeyChain.m
#import <XCTest/XCTest.h>
#import <LUKeychainAccess/LUKeychainAccess.h>
@interface sample_keychainTests : XCTestCase
@end
@implementation sample_keychainTests
- (void)setUp {
[super setUp];
// integer
[[LUKeychainAccess standardKeychainAccess] setInteger:1 forKey:@"integerKey"];
// float
[[LUKeychainAccess standardKeychainAccess] setFloat:1.0 forKey:@"floatKey"];
// double
[[LUKeychainAccess standardKeychainAccess] setDouble:1.0 forKey:@"doubleKey"];
// BOOL
[[LUKeychainAccess standardKeychainAccess] setBool:YES forKey:@"boolKey"];
// NSString
[[LUKeychainAccess standardKeychainAccess] setString:@"string" forKey:@"stringKey"];
// NSObject
[[LUKeychainAccess standardKeychainAccess] setObject:@"object" forKey:@"objectKey"];
}
- (void)tearDown {
[super tearDown];
}
- (void)testKeyChain {
XCTAssertEqual([[LUKeychainAccess standardKeychainAccess] integerForKey:@"integerKey"], 1);
XCTAssertEqual([[LUKeychainAccess standardKeychainAccess] floatForKey:@"floatKey"], 1.0);
XCTAssertEqual([[LUKeychainAccess standardKeychainAccess] doubleForKey:@"doubleKey"], 1.0);
XCTAssertEqual([[LUKeychainAccess standardKeychainAccess] boolForKey:@"boolKey"], YES);
XCTAssertEqualObjects([[LUKeychainAccess standardKeychainAccess] stringForKey:@"stringKey"], @"string");
XCTAssertEqualObjects([[LUKeychainAccess standardKeychainAccess] objectForKey:@"objectKey"], @"object");
}
@end
参考