tutorial ios swift security keychain

ios - tutorial - Guardar y cargar desde KeyChain | Swift



keychain swift 4 (1)

Esta pregunta ya tiene una respuesta aquí:

Cómo almacenar simplemente una cadena en el llavero y cargarla cuando sea necesario. Hay varias soluciones de SO que se refieren principalmente a Git repo. Pero necesito la solución más pequeña y simple en la última versión de Swift. Ciertamente, no quiero agregar git framework para simplemente almacenar una contraseña en mi proyecto.

Hay una solución similar Guarda y recupera valor a través de KeyChain , que no funcionó para mí. Cansado de los errores del compilador.


Fuente mas simple

import Foundation import Security // Constant Identifiers let userAccount = "AuthenticatedUser" let accessGroup = "SecuritySerivice" /** * User defined keys for new entry * Note: add new keys for new secure item and use them in load and save methods */ let passwordKey = "KeyForPassword" // Arguments for the keychain queries let kSecClassValue = NSString(format: kSecClass) let kSecAttrAccountValue = NSString(format: kSecAttrAccount) let kSecValueDataValue = NSString(format: kSecValueData) let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword) let kSecAttrServiceValue = NSString(format: kSecAttrService) let kSecMatchLimitValue = NSString(format: kSecMatchLimit) let kSecReturnDataValue = NSString(format: kSecReturnData) let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne) public class KeychainService: NSObject { /** * Exposed methods to perform save and load queries. */ public class func savePassword(token: NSString) { self.save(passwordKey, data: token) } public class func loadPassword() -> NSString? { return self.load(passwordKey) } /** * Internal methods for querying the keychain. */ private class func save(service: NSString, data: NSString) { let dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! // Instantiate a new default keychain query let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue]) // Delete any existing items SecItemDelete(keychainQuery as CFDictionaryRef) // Add the new keychain item SecItemAdd(keychainQuery as CFDictionaryRef, nil) } private class func load(service: NSString) -> NSString? { // Instantiate a new default keychain query // Tell the query to return a result // Limit our results to one item let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue]) var dataTypeRef :AnyObject? // Search for the keychain items let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef) var contentsOfKeychain: NSString? = nil if status == errSecSuccess { if let retrievedData = dataTypeRef as? NSData { contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding) } } else { print("Nothing was retrieved from the keychain. Status code /(status)") } return contentsOfKeychain } }

Ejemplo de llamada

KeychainService.savePassword("Pa55worD") let password = KeychainService.loadPassword() // password = "Pa55worD"

SWIFT 4: VERSIÓN CON ACTUALIZACIÓN Y ELIMINAR CONTRASEÑA

import Cocoa import Security // see https://.com/a/37539998/1694526 // Arguments for the keychain queries let kSecClassValue = NSString(format: kSecClass) let kSecAttrAccountValue = NSString(format: kSecAttrAccount) let kSecValueDataValue = NSString(format: kSecValueData) let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword) let kSecAttrServiceValue = NSString(format: kSecAttrService) let kSecMatchLimitValue = NSString(format: kSecMatchLimit) let kSecReturnDataValue = NSString(format: kSecReturnData) let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne) public class KeychainService: NSObject { class func updatePassword(service: String, account:String, data: String) { if let dataFromString: Data = data.data(using: String.Encoding.utf8, allowLossyConversion: false) { // Instantiate a new default keychain query let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue]) let status = SecItemUpdate(keychainQuery as CFDictionary, [kSecValueDataValue:dataFromString] as CFDictionary) if (status != errSecSuccess) { if let err = SecCopyErrorMessageString(status, nil) { print("Read failed: /(err)") } } } } class func removePassword(service: String, account:String) { // Instantiate a new default keychain query let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, kCFBooleanTrue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue]) // Delete any existing items let status = SecItemDelete(keychainQuery as CFDictionary) if (status != errSecSuccess) { if let err = SecCopyErrorMessageString(status, nil) { print("Remove failed: /(err)") } } } class func savePassword(service: String, account:String, data: String) { if let dataFromString = data.data(using: String.Encoding.utf8, allowLossyConversion: false) { // Instantiate a new default keychain query let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue]) // Add the new keychain item let status = SecItemAdd(keychainQuery as CFDictionary, nil) if (status != errSecSuccess) { // Always check the status if let err = SecCopyErrorMessageString(status, nil) { print("Write failed: /(err)") } } } } class func loadPassword(service: String, account:String) -> String? { // Instantiate a new default keychain query // Tell the query to return a result // Limit our results to one item let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, account, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue]) var dataTypeRef :AnyObject? // Search for the keychain items let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef) var contentsOfKeychain: String? if status == errSecSuccess { if let retrievedData = dataTypeRef as? Data { contentsOfKeychain = String(data: retrievedData, encoding: String.Encoding.utf8) } } else { print("Nothing was retrieved from the keychain. Status code /(status)") } return contentsOfKeychain } }

Debe imaginar lo siguiente conectado a un campo de entrada de texto y una etiqueta, y luego tener cuatro botones conectados, uno para cada uno de los métodos.

class ViewController: NSViewController { @IBOutlet weak var enterPassword: NSTextField! @IBOutlet weak var retrievedPassword: NSTextField! let service = "myService" let account = "myAccount" // will only work after @IBAction func updatePassword(_ sender: Any) { KeychainService.updatePassword(service: service, account: account, data: enterPassword.stringValue) } @IBAction func removePassword(_ sender: Any) { KeychainService.removePassword(service: service, account: account) } @IBAction func passwordSet(_ sender: Any) { let password = enterPassword.stringValue KeychainService.savePassword(service: service, account: account, data: password) } @IBAction func passwordGet(_ sender: Any) { if let str = KeychainService.loadPassword(service: service, account: account) { retrievedPassword.stringValue = str } else {retrievedPassword.stringValue = "Password does not exist" } } }