一、Secure Enclave
1. Secure Enclave
https://support.apple.com/en-ng/guide/security/sec59b0b31ff/web
Secure Enclave 是集成到 Apple 系统 (SoC) 芯片 中的专用安全子系统。 Secure Enclave 与主处理器隔离,以提供额外的安全层,即使在应用处理器内核受到威胁时也能确保敏感用户数据的安全。 它遵循与 SoC 相同的设计原则——用于建立硬件信任根的引导 ROM、用于高效和安全加密操作的 AES 引擎以及受保护的内存。 虽然 Secure Enclave 不包括存储,但它有一种机制可以将信息安全地存储在附加存储上,该存储与应用处理器和操作系统使用的 NAND 闪存分开。
2. kSecAttrTokenIDSecureEnclave
https://developer.apple.com/documentation/security/ksecattrtokenidsecureenclave
Secure Enclave 支持的唯一钥匙串项是 256 位椭圆曲线私钥(密钥类型为 kSecAttrKeyTypeEC 的私钥)。 此类密钥必须使用 SecKeyGeneratePair(_,_,_)
函数直接在 Secure Enclave 上生成,并将参数字典中的 kSecAttrTokenID 密钥设置为 kSecAttrTokenIDSecureEnclave。
- 无法将预先存在的密钥导入 Secure Enclave。
- 无法导出使用 kSecAttrTokenIDSecureEnclave 生成的 Private Key。
二、使用系统钥匙串存储数据
- 钥匙串配置信息
private func VKgetKeychainQuery(_ service: String) -> [String: Any] {
let query = [
// kSecAttrService, kSecAttrAccount, and kSecClass
// uniquely identify the item to save in Keychain
kSecAttrService as String: service as Any,
kSecAttrAccount as String: service as Any,
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
]
return query
}
- 数据保存到钥匙串
/// 数据保存到钥匙串
@discardableResult
private func VKSave(_ service: String, data: String) -> Bool {
// Get search dictionary
var keychainQuery = VKgetKeychainQuery(service)
// Delete old item before add new item
SecItemDelete(keychainQuery as CFDictionary)
// Add new object to search dictionary(Attention:the data format)
guard let encodData = try? JSONEncoder().encode(data) else {
return false
}
keychainQuery[kSecValueData as String] = encodData
// Add item to keychain with the search dictionary
let status = SecItemAdd(keychainQuery as CFDictionary, nil)
return status == errSecSuccess
}
- 从钥匙串读取数据
/// 从钥匙串中读取数据
private func load(_ service: String) -> String? {
var keychainQuery = VKgetKeychainQuery(service)
keychainQuery[kSecReturnData as String] = kCFBooleanTrue
keychainQuery[kSecMatchLimit as String] = kSecMatchLimitOne
var keyData: AnyObject?
let status = SecItemCopyMatching(keychainQuery as CFDictionary, &keyData)
guard status == errSecSuccess else {
return nil
}
guard let keyData = keyData as? Data else {
return nil
}
guard let ret = try? JSONDecoder().decode(String.self, from: keyData) else {
return nil
}
return ret
}
- 从钥匙串删除数据
/// 删除钥匙串中的数据
@discardableResult
private func VKdelete(_ service: String) -> Bool {
let keychainQuery = VKgetKeychainQuery(service)
let status = SecItemDelete(keychainQuery as CFDictionary)
return status == errSecSuccess
}