1

I want to save and retrieve the password and userAccount in keychain. I found a solution in stackoverflow and I use the code there. Save and Load from KeyChain | Swift. But this code only saves and load the password not the accountName. I think I figured out how to save the accountName but I need to figure out how to load it along with the password. Here is the code to save you some time from going into that link.

var userAccount = "AuthenticatedUser"
let accessGroup = "SecurityService"

// Mark: User defined keys for new entry
// Note: add new keys for new secure item and use them in load and save methods
let accountKey = "KeyForAccount"
let passwordKey = "KeyForPassword"

private class func save(service: String, data: String) {
        let dataFromString: NSData = data.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue), allowLossyConversion: false)! as NSData

        //Instantiate a new default keychain query
        let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue as NSCopying, kSecAttrAccountValue as NSCopying, kSecValueDataValue as NSCopying])

        //Add new keychain item
        let status = SecItemAdd(keychainQuery as CFDictionary, nil)
        if status != errSecSuccess {  //Always check status
            print("Write failed. Attempting update.")
            //updatePassword(token: data)
        }
    }
 private class func load(service: 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, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue as NSCopying, kSecAttrAccountValue as NSCopying, kSecReturnDataValue as NSCopying, kSecMatchLimitValue as NSCopying])

        var dataTypeRef: AnyObject?

        //Search for the keychain items
        let status : OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
        var contentsOfKeychain: String? = nil

        if status == errSecSuccess {
            if let retrieveData = dataTypeRef as? Data {
                contentsOfKeychain = String(data: retrieveData as Data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
            }
        } else {
            print("Nothing was retrieved from the keychain. Status code \(status)")
        }
            print(contentsOfKeychain ?? "none found")
            return contentsOfKeychain   
    }

Complete code is inside the link. Thanks all.

CRey
  • 1,150
  • 2
  • 9
  • 21

1 Answers1

0

But this code only saves and load the password not the accountName.

The code you show doesn't save or load the password or the account name.

What you have are two functions, one to save a key/value pair, one to load a key's value. It is how you call these two functions that determines what gets saved/loaded.

Somewhere in your code you call save to save the password, you need to call save (using a different key) to save the account name as well. Likewise for load. Your code does define the two keys to use (accountKey & passwordKey).

HTH

CRD
  • 52,522
  • 5
  • 70
  • 86
  • ``` public class func savePassword(token: String) { self.save(service: passwordKey as String, data: token) } public class func loadPassword() -> String? { return self.load(service: passwordKey)``` these are the 2 functions that calls it to save and load. How do I fix the loadPassword so it includes that account? Thanks. – CRey Jun 27 '17 at 13:37
  • The answer to your question in your comment is in the last paragraph of my answer above. If you wrote `savePassword` & `loadPassword`, and/or the calls to them in your code, then I'm probably misunderstanding what your question is as being both an author of Swift code and asking the question as I understand it doesn't make sense to me.. If you didn't write the code can you not ask the person who did that for you to explain this to you in detail? – CRD Jun 27 '17 at 16:57
  • Im new to swift. Basically, Im asking for the syntax. I've tried what I can with my abilities. Im quite confused because the load() method only returns a string. I dont think it can carry both account and password. I've tried returning an array but pulling the accountname out from the keychain was another issue that I dont know how to deal with. – CRey Jun 28 '17 at 02:36
  • 1
    " I dont think it can carry both account and password." - as the answer says "you need to call `save` (using a different key) to save the account name **as well**". With the functions as defined a call to `save`/`load` deals with a single key/value pair, so you call these functions **twice**, once for each key - just write `saveAccount`/`loadAccount`. If you wish you could instead write `saveAccountAndPassword`/`saveAccountAndPassword` to wrap two calls to `save`/`load`; in which case you probably want the load function to return a *tuple*; but that's just added complication at the moment. – CRD Jun 28 '17 at 03:00
  • Thank you sir. I've solved it. The solution was I used a different function that returns a dictionary. – CRey Jul 03 '17 at 02:42