### KeyChain에 Data를 저장하기 위해 필요한 요소에는 무엇이 있는지 확인해봅시다.
Data, Attribute, KeychainItem은 서로 어떤 관계일까요?
|<img src="https://i.imgur.com/y79NPx5.png" width=500>|
|--|
- Data: 암호화되서 item에 담기고,
- item : 키 체인에 저장되는 데이터로 암호화된 Data를 가짐.
- Attributes: item을 설명하는 특성
- item class에 따라 설정할 수 있는 attricutes가 달라진다.
- (예) 애플문서보면 클래스별로 다양한 attribute가 존재한다.
|<img width = 500, src = "https://i.imgur.com/3io7BHG.png">|
|--|
우리가 메인 화면에서 비밀번호를 만들어, Data로 저장하고 싶다면, 어떤 과정을 거쳐야 할까요?
- kSecClass 로는 kSecClassGenericPassword 를 활용합니다.
- 필요한 KeychainItem의 각 Attribute가 어떤 의미를 가지는지 이해해봅시다.

- kSecAttrAccessControl: keychain item의 access control condition을 포함하고 있다. access control이 의미하는 바는 기기의 잠금 상태에 따라 keychain item을 어느 정도까지 조작할 수 있는가이다.
- When Passcode Set: 사용자가 passcode를 설정하지 않았다면, 이 세팅하에서는 keychain item을 저장할 수 없다. 기기가 잠금 해제 되었을 때에만 keychain item에 접근할 수 있다. 앱이 foreground에서 실행 중일 때에만 keychain item에 대한 접근이 필요한 경우에 사용한다.
- When Unlocked: 기기가 잠금 해제 되었을 때에만 keychain item에 접근이 가능하다. 별도로 keychain item의 kSecAttrAccessControl을 지정해주지 않았다면 얘가 기본값이다.
- After First Unlock: 사용자가 기기를 재시작 한 후 처음으로 기기를 잠금 해제하거나, 기기에 passcode가 없을 때 이 조건을 만족하게 된다. 기기를 재시작하기 전까지 계속 조건을 만족한 상태(true)가 유지된다. 앱이 백그라운드에서 실행될 때 keychain item에 접근할 수 있어야 한다면 이걸 쓴다.
- Always: 기기의 잠금 상태와 무관하게 항상 keychain item에 접근할 수 있다. 비추.
- kSecAttrAccount: account name을 포함하며, 값 타입은 CFString이다.
- 이하 생략 너무 많음..
### KeyChain에 저장된 Data를 꺼내오는 방법을 확인해봅시다.
- SecItemCopyMatching 메서드의 두 매개변수를 확인해봅시다.
```swift
func SecItemCopyMatching(
_ query: CFDictionary,
_ result: UnsafeMutablePointer<CFTypeRef?>?
) -> OSStatus
```
- `query`
-
query는 무엇에 활용될까요?
query 를 구성하는 요소들에는 무엇이 있을까요?
result는 무엇에 활용될까요?
꺼내온 값에서 우리가 원하는 데이터(비밀번호)를 추출해봅시다.
메인 화면에서 새로 작성한 비밀번호가 KeyChain 속 비밀번호와 같은지 대조하고, 만약 같다면 일기장 ViewController를 보여줍니다.
저장성공
```swift!
@IBAction func addNewPassword(_ sender: Any) {
// UserDefaults 활용
// UserDefaults.standard.set(pwTextField.text, forKey: "pass")
// 키체인을 활용해 패스워드를 저장합니다.
guard let pass = pwTextField.text else {
print("비밀번호 empty")
return
}
var query: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecAttrLabel: "비밀번호",
kSecValueData: pass.data(using: String.Encoding.utf8)
]
let status = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
print("저장 성공")
} else if status == errSecDuplicateItem {
print("중복")
} else {
print("저장 실패")
}
}
```