iOSのKeyChainについてゆるふわにまとめる


## KeyChainとは

ざっくり書くと

- 機密情報を安全に取り扱う仕組み
- パスワードや秘密鍵・公開鍵などの機密情報を安全に管理するための仕組み

また、KeyChainで管理する情報は暗号化されているとのこと
ユーザの情報を保存する仕組みとして `UserDefaults` がありますが、これは設定ファイルなどのプリファレンス情報を管理するための仕組み。

### UserDefaultsとの違い

- アプリが削除されてもデータが残る
- 同じKeychain Access Groupに属するアプリ同士でアクセスできる
- データが暗号化される

## 準備

### プロジェクト作成

![スクリーンショット 2016-08-04 午前10.05.27.png](https://qiita-image-store.s3.amazonaws.com/0/97280/ed2bcf71-28bf-87b4-e09f-504fb6c348fc.png "スクリーンショット 2016-08-04 午前10.05.27.png")

### Frameworkの追加

![スクリーンショット 2016-08-04 午前10.13.17.png](https://qiita-image-store.s3.amazonaws.com/0/97280/bd10559b-cc1a-27c5-54af-11716df350e0.png "スクリーンショット 2016-08-04 午前10.13.17.png")

`Linked Frameworks and Libraries` から `Security.framework` を追加する。

### ライブラリインストール

今回はKeyChainの便利なライブラリを使用します。

[TheLevelUp/LUKeychainAccess](https://github.com/TheLevelUp/LUKeychainAccess)

```ruby:Podfile
pod 'LUKeychainAccess', '~> 1.2'
```

```bash
$ pod install
$ open PROJECT_NAME.xcworkspace/
```

### KeyChain準備

![スクリーンショット_2016-08-04_午前10_20_37.png](https://qiita-image-store.s3.amazonaws.com/0/97280/16497b69-df8c-a2aa-7822-e42bcc3658da.png "スクリーンショット_2016-08-04_午前10_20_37.png")

![スクリーンショット_2016-08-04_午前10_20_32.png](https://qiita-image-store.s3.amazonaws.com/0/97280/b05b5433-4c5a-4b1f-e3a7-1e97d0b17e28.png "スクリーンショット_2016-08-04_午前10_20_32.png")

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アクセスがアプリ間では行えません

## ソースコード

今回はボタンを押すと「 __小泉花陽ちゃん__ 」という文字が出力されるようなものを作成しました。

```objective-c: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
```

## 実行サンプル

![Simulator Screen Shot 2016.08.04 午前10.49.21.png](https://qiita-image-store.s3.amazonaws.com/0/97280/69a20123-3216-ed3c-c2b7-c00da665b44e.png "Simulator Screen Shot 2016.08.04 午前10.49.21.png")

![Simulator Screen Shot 2016.08.04 午前10.49.23.png](https://qiita-image-store.s3.amazonaws.com/0/97280/2590b47a-4f8d-89b3-b221-65661cdb894c.png "Simulator Screen Shot 2016.08.04 午前10.49.23.png")

## いろんな型をKeyChainに管理させる

https://github.com/nnsnodnb/KeyChain-Sample/blob/master/sample-keychainTests/sample_keychainTests.m

```objective-c: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
```

## 参考

http://blog.odoruinu.net/2014/07/10/ios-keychain-sharing-data-between-apps/