Kodeco Forums

How To Secure iOS User Data: The Keychain, Touch ID, and 1Password

Learn how to secure your iOS app's user data with this hands-on tutorial covering the Keychain, Touch ID, and the 1Password extension for iOS 8


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/2052-how-to-secure-ios-user-data-the-keychain-touch-id-and-1password

How to remove data from keychain or clear keychain data from app while logout.

Great tutorial. I especially liked the 1Password integration part.

1Password is one of my most used apps. I use it several times a day myself.

I’m not sure that you can actually “remove” items from the keychain. That’s the point of it - to save items so that they persist between app launches.

If you want to delete a SecItem (secure item), the method to use is:
func SecItemDelete(_ query: CFDictionary) -> OSStatus

Me too. Bought it last week. Totally worth the money.

Got it working very easily. The one thing I can’t understand is why the code looks for a key of “v_Data” when checking the password. Is this something that is hard-coded in the KeyChain?

thanks!

Yes, that’s one of the keys in the keychain Item Data that we’re passing in

Thanks. Can you tell me where it is documented in the Apple documentation?

How to get the password of each KeychainWrapper if I have multiple passwords? Using the “v_Data” just giving me the last written password to Keychain. Thanks!

Hi,

I have just an small questions:

File LoginViewController.swift

On step 5

// 5.
      MyKeychainWrapper.mySetObject(passwordTextField.text, forKey:kSecValueData)
      MyKeychainWrapper.writeToKeychain()
      NSUserDefaults.standardUserDefaults().setBool(true, forKey: "hasLoginKey")
      NSUserDefaults.standardUserDefaults().synchronize()
      loginButton.tag = loginButtonTag

File KeychainWrapper.m

// Implement the mySetObject:forKey method, which writes attributes to the keychain:
- (void)mySetObject:(id)inObject forKey:(id)key
{
    if (inObject == nil) return;
    id currentObject = [_keychainData objectForKey:key];
    if (![currentObject isEqual:inObject])
    {
        [_keychainData setObject:inObject forKey:key];
        [self writeToKeychain];
    }
}

The question is:
Why we’re using MyKeychainWrapper.writeToKeychain() method if the method mySetObject(id:forKey) save it inside of his implementation?
Is there any particular reason why we’re saving again?

This tutorial was pretty good, thanks for sharing the knowledge.

Is there a way to get notified when the user adds a new fingerprint?

I don’t think that there is. It would be mentioned in the developer documentation. Touch ID works no matter what fingerprint is stored. If more than one is store, they would all authenticate the app

No compelling reason at all.

Great writeup Quick question, I understand “v_Data” is a key in the keychain Item Data, Do you have a list of keys or the choices of keys and their use? I’m sort of confused on that. Can you forward me to the apple documentation? I tried looking for “v_Data” but cannot find any explanation on that or any other keys.

Please update the tutorial to Swift 3.0 using Xcode Beta 5. Great tutorial. Thanks. :slight_smile:

Any plans for updating this to Xcode 8 - Swift 3? I had his working until my code got converted to Swift 3

No official plans at the moment that I’m aware of. I do plan on taking a look at this myself. I just have to get through this week :wink:

What is not working for you? One thing I had to do myself, was enable the KeyChain Sharing entitlement. It doesn’t seem to writeToKeychain() in iOS 10 without it.

Has there been any update on this? Mine stopped working as well with IOS 10. I’ve turned on the KeyChain sharing entitlement as well.

I think my problem is in canEvaluatePolicy

           if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error:nil) && useTouchID
            {
                context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics,
                    localizedReason: "Logging in with Touch ID",
                    reply: { (success : Bool, error : NSError? ) -> Void in
                        DispatchQueue.main.async(execute: {
                            if success
                            {
                                self.passwordTextField.text = password
                                self.usernameTextField.text = username
                                let request = URLRequest(url: self.url!)
                                _ = NSURLConnection(request: request, delegate: self, startImmediately: true)
                            }       // END if
                        })              // END dispatch asynch
                } as! (Bool, Error?) -> Void)                  // END evaluatePolicy