LoginSignup
16
13

More than 3 years have passed since last update.

Keychain(iOS,Swift)対応

Last updated at Posted at 2021-01-17

KeyChain とは

キーチェーンと呼ばれる暗号化されたデータベースに
下記のユーザーデータの小さなビットを格納するメカニズムです。

・パスワード
・Trust Servicesで管理する暗号化キーと証明書
・秘密メモ

キーチェーンアクセス

パスワードやアカウント情報を保管するmacOSアプリケーション

iOSのUserDefaults

ユーザーのデフォルトデータベースへのインターフェイスです。

・長点: アプリの起動時にキーと値のペアを永続的に保存します。
    処理が簡単であること。
・短点: アプリ削除ですべて消えること。
    データがそのまま保存するため、安全ではないこと。
    構造体はそのまま保存できないため、Dataなどで変換して保存しないといけないこと。

iOSのKeychain

・長点: アプリ削除しても消えないこと。
    セキュアな値を保存できること(apple推奨)
・短点: 処理が少し複雑
    大量のデータ保存には向いてないこと。

kSecClass

kSecClassGenericPassword: パスワード(通常)
let kSecClassInternetPassword: パスワード(Internet)
let kSecClassCertificate: 証明書?
let kSecClassKey: 暗号鍵(秘密鍵、公開鍵など)
let kSecClassIdentity: 秘密鍵付き証明書

 let dic: [String: Any] = 
[kSecClass as String: kSecClassGenericPassword,
kSecAttrGeneric as String: key,           // 自由項目(グループ)
kSecAttrAccount as String: "account",     // アカウント(ログインIDなど)
kSecValueData as String: data]            // 保存情報

ユニークキー

検索時にある1つのアイテムを特定するキー(ユニークキー)は kSecClassGenericPassword の場合、
次の2つで構成されている
kSecAttrAccount
kSecAttrService

Keychain 登録/更新


// 保存データが存在するかの確認
let matchingStatus = SecItemCopyMatching(dic as CFDictionary, nil)
switch matchingStatus {
// 保存
case errSecItemNotFound: 
    SecItemAdd(dic as CFDictionary, nil)
// 更新
case errSecSuccess: 
   SecItemUpdate(dic as CFDictionary,
                 [kSecValueData as String: data] as CFDictionary)
default:
    debugPrint("キーチェーン保存失敗(\(matchingStatus)")
}

Keychain 取得

var dataTypeRef: AnyObject? = nil
let matchingStatus = withUnsafeMutablePointer(to: &dataTypeRef) {
    SecItemCopyMatching(dic as CFDictionary, UnsafeMutablePointer($0))
}
if matchingStatus == errSecSuccess,
   let getData = dataTypeRef as? Data {
       // キーチェーン取得結果
       String(data: getData, encoding: .utf8)
}

テストコード

func testKeychainIfSaveKeychainThenEqualToGetKeychainResult() throws {
    guard let data = "testtest".data(using: .utf8) else {
        XCTFail()
        return
    }
    let key = "encryptedkey"
    let value = SHA256.hash(data: data).hexStr
    KeychainAccess.saveKeyChain(key: key, vaule: value)
    let result = KeychainAccess.getKeyChain(key: key)
    XCTAssertTrue(value == result)
}

課題

・kSecClassKeyなど対応方法は?
 kSecClassGenericPassword を kSecClassKey変更した場合、キーチェーンから情報が取得できませんでした。

参照

キーチェーンアクセスユーザガイド
Apple - UserDefaults
KeyChain Services
Apple - Item Class Keys and Values
[iOS] Keychain Services とは

16
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
13