Save and Load from KeyChain | Swift [duplicate] Save and Load from KeyChain | Swift [duplicate] ios ios

Save and Load from KeyChain | Swift [duplicate]


##Simplest Source##

import Foundationimport Security// Constant Identifierslet 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 querieslet 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    }}

##Example of Calling##

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

##SWIFT 4: VERSION WITH UPDATE AND REMOVE PASSWORD

import Cocoaimport Security// see https://stackoverflow.com/a/37539998/1694526// Arguments for the keychain querieslet 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    }    }

You need to imagine the following wired up to a text input field and a label, then having four buttons wired up, one for each of the methods.

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" }    }}

##Swift 5##Kosuke's version for swift 5

import Securityimport UIKitclass KeyChain {    class func save(key: String, data: Data) -> OSStatus {        let query = [            kSecClass as String       : kSecClassGenericPassword as String,            kSecAttrAccount as String : key,            kSecValueData as String   : data ] as [String : Any]        SecItemDelete(query as CFDictionary)        return SecItemAdd(query as CFDictionary, nil)    }    class func load(key: String) -> Data? {        let query = [            kSecClass as String       : kSecClassGenericPassword,            kSecAttrAccount as String : key,            kSecReturnData as String  : kCFBooleanTrue!,            kSecMatchLimit as String  : kSecMatchLimitOne ] as [String : Any]        var dataTypeRef: AnyObject? = nil        let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)        if status == noErr {            return dataTypeRef as! Data?        } else {            return nil        }    }    class func createUniqueID() -> String {        let uuid: CFUUID = CFUUIDCreate(nil)        let cfStr: CFString = CFUUIDCreateString(nil, uuid)        let swiftString: String = cfStr as String        return swiftString    }}extension Data {    init<T>(from value: T) {        var value = value        self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))    }    func to<T>(type: T.Type) -> T {        return self.withUnsafeBytes { $0.load(as: T.self) }    }}

Example usage:

let int: Int = 555let data = Data(from: int)let status = KeyChain.save(key: "MyNumber", data: data)print("status: ", status)    if let receivedData = KeyChain.load(key: "MyNumber") {    let result = receivedData.to(type: Int.self)    print("result: ", result)}