Skip to content

Instantly share code, notes, and snippets.

@algrid
algrid / KeychainBio.swift
Last active April 16, 2019 21:26
Reading a biometry-protected entry in iOS keychain - loadBioProtected
static func loadBioProtected(key: String, context: LAContext? = nil,
prompt: String? = nil) -> Data? {
var query: [String: Any] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue,
kSecAttrAccessControl as String: getBioSecAccessControl(),
kSecMatchLimit as String : kSecMatchLimitOne ]
if let context = context {
@algrid
algrid / KeychainBio.swift
Last active April 16, 2019 21:29
Reading a biometry-protected entry in iOS keychain - without an LAContext
checkBiometryState { success in
guard success else {
// Biometric authentication is not available
return
}
DispatchQueue.global().async {
var result = ""
if let data = KeychainHelper.loadBioProtected(key: self.entryName,
prompt: "Access sample keychain entry") {
let dataStr = String(decoding: data, as: UTF8.self)
@algrid
algrid / KeychainBio.swift
Last active April 12, 2019 20:20
Preparing to read a biometry-protected iOS keychain entry
private func checkBiometryState(_ completion: @escaping (Bool)->Void) {
let bioState = self.biometryState
guard bioState != .notAvailable else {
// Can't read entry, biometry not available
completion(false)
return
}
if bioState == .locked {
// To unlock biometric authentication iOS requires user to enter a valid passcode
let authContext = LAContext()
@algrid
algrid / KeychainBio.swift
Last active April 10, 2019 15:27
Creating a biometry-protected keychain item in iOS
static func getBioSecAccessControl() -> SecAccessControl {
var access: SecAccessControl?
var error: Unmanaged<CFError>?
if #available(iOS 11.3, *) {
access = SecAccessControlCreateWithFlags(nil,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.biometryCurrentSet,
&error)
} else {
@algrid
algrid / KeychainBio.swift
Last active April 10, 2019 15:30
Biometric authentication availability in iOS
enum BiometryState {
case available, locked, notAvailable
}
var biometryState: BiometryState {
let authContext = LAContext()
var error: NSError?
let biometryAvailable = authContext.canEvaluatePolicy(
LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error)
@algrid
algrid / KeychainSamples.swift
Last active March 27, 2019 14:49
Reading a password-protected iOS keychain entry using a given password
let context = LAContext()
let password = pwTextField.text ?? ""
context.setCredential(Data(password.utf8), type: .applicationPassword)
let data = KeychainHelper.loadPassProtected(key: self.entryName, context: context)
// Update UI for data
@algrid
algrid / KeychainSamples.swift
Created March 26, 2019 11:18
Reading a password-protected iOS keychain entry using LAContext.evaluateAccessControl
let context = LAContext()
let accessControl = KeychainHelper.getPwSecAccessControl()
context.evaluateAccessControl(accessControl, operation: .useItem, localizedReason: "Not used") { (success, error) in
DispatchQueue.main.async {
guard success else {
self.showStatus("evaluateAccessControl failed: \(error?.localizedDescription ?? "no error")")
return
}
let data = KeychainHelper.loadPassProtected(key: self.entryName, context: context)
// Update UI for data
@algrid
algrid / KeychainSamples.swift
Created March 26, 2019 10:55
Synchronously read a password-protected entry from iOS keychain
DispatchQueue.global().async {
let data = KeychainHelper.loadPassProtected(key: self.entryName)
DispatchQueue.main.async {
// Update UI for data
}
}
@algrid
algrid / KeychainSamples.swift
Created March 19, 2019 14:39
Reading a password-protected item data from iOS keychain
static func loadPassProtected(key: String, context: LAContext? = nil) -> Data? {
var query: [String: Any] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue,
kSecAttrAccessControl as String: getPwSecAccessControl(),
kSecMatchLimit as String : kSecMatchLimitOne]
if let context = context {
query[kSecUseAuthenticationContext as String] = context
@algrid
algrid / KeychainSamples.swift
Created March 19, 2019 14:25
Creating a password-protected entry in iOS keychain
static func getPwSecAccessControl() -> SecAccessControl {
var access: SecAccessControl?
var error: Unmanaged<CFError>?
access = SecAccessControlCreateWithFlags(nil,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.applicationPassword,
&error)
precondition(access != nil, "SecAccessControlCreateWithFlags failed")
return access!