This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static func getBioSecAccessControl() -> SecAccessControl { | |
| var access: SecAccessControl? | |
| var error: Unmanaged<CFError>? | |
| if #available(iOS 11.3, *) { | |
| access = SecAccessControlCreateWithFlags(nil, | |
| kSecAttrAccessibleWhenUnlockedThisDeviceOnly, | |
| .biometryCurrentSet, | |
| &error) | |
| } else { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| enum BiometryState { | |
| case available, locked, notAvailable | |
| } | |
| var biometryState: BiometryState { | |
| let authContext = LAContext() | |
| var error: NSError? | |
| let biometryAvailable = authContext.canEvaluatePolicy( | |
| LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| DispatchQueue.global().async { | |
| let data = KeychainHelper.loadPassProtected(key: self.entryName) | |
| DispatchQueue.main.async { | |
| // Update UI for data | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static func getPwSecAccessControl() -> SecAccessControl { | |
| var access: SecAccessControl? | |
| var error: Unmanaged<CFError>? | |
| access = SecAccessControlCreateWithFlags(nil, | |
| kSecAttrAccessibleWhenUnlockedThisDeviceOnly, | |
| .applicationPassword, | |
| &error) | |
| precondition(access != nil, "SecAccessControlCreateWithFlags failed") | |
| return access! |
NewerOlder