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

We have to refactor the whole func more or less. Here’s what I have working…

@IBAction func touchIDButtonAction() {
// 1.
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error:nil) {
  
  // 2.
  context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics,
                         localizedReason: "Logging in with Touch ID") {
                         (success, evaluateError) in
                          
                          if (success) {
                            DispatchQueue.main.async {
                              // User authenticated successfully, take appropriate action
                              self.performSegue(withIdentifier: "dismissLogin", sender: self)
                            }
                          } else {
                            
                            if let error: LAError = evaluateError as! LAError? {
                              var message: String
                              var showAlert : Bool
                                
                              switch error {
                                
                              case LAError.authenticationFailed:
                                message = "There was a problem verifying your identity."
                                showAlert = true
                              case LAError.userCancel:
                                message = "You pressed cancel."
                                showAlert = true
                              case LAError.userFallback:
                                message = "You pressed password."
                                showAlert = true
                              default:
                                showAlert = true
                                message = "Touch ID may not be configured"
                              }
                              
                              if showAlert {
                                let alertView = UIAlertController(title: "Error",
                                                                  message: message as String, preferredStyle:.alert)
                                let okAction = UIAlertAction(title: "Darn!", style: .default, handler: nil)
                                alertView.addAction(okAction)
                                self.present(alertView, animated: true, completion: nil)
                              }
                            }
                          }
                          
  }
} else {
  // 5.
  let alertView = UIAlertController(title: "Error",
                                    message: "Touch ID not available" as String, preferredStyle:.alert)
  let okAction = UIAlertAction(title: "Darn!", style: .default, handler: nil)
  alertView.addAction(okAction)
  self.present(alertView, animated: true, completion: nil)
}
  }

Thank you so much! It’s working like a charm.

Vinnie

Hi, I am learning Swift and managed to make the login example work in a different app in Swift 3. So it is a great tutorial if a novice like me can make it work!

Like d07Jansen, I tried to extend what I learnt to save another item in the key chain, but got confused by the use of the “v_Data” key. I assume it is pre-defined but I can’t find it documented anywhere. Does it relate to kSecValueData?

Is it easy to explain how to add more than one item to the key chain or is that a whole other tutorial?

Thanks

Sorted the issue - using a more complete / easier wrapper downloaded from GitHub.

Hi sorry about the delay, I was having trouble logging in to the forum. (It doesn’t use Touch ID :wink:

Glad you figured it out. Can you tell me what GitHub wrapper you chose?

Best
Tim

Tim,

Thanks for your reply - I used KeychainAccess by Kishi Kawakatsumi. https://github.com/kishikawakatsumi/KeychainAccess

Seems to work well and written in swift - which makes it easier for me to figure what’s happening since I don’t know Objective C. Wrote engineering / CAD systems in Fortran / assembler in the 1980s so a whole generation of modern programming languages passed me by!

cheers, Ross

Great tutorial!

One question: Why are you enforcing that the user already created an account before allowing them to use 1Password? The value of a password manager is to not have to remember or write down your credentials. You first generate the password and save it to the password manager. Then you register for the site using the credentials you created.

The current approach seems to be a simplifying assumption so you don’t have to handle the additional case of a new user registering with 1Password.

Thanks for your feedback.

I’m not “enforcing” anything. The tutorial was written with three goals. 1 Show users how to create an app that uses the Keychain to save credentials. 2. Show how to set up Touch ID. 3. Show how to use 1Password. All the while providing a fallback if users don’t have TouchID or 1Password.

At the time the tutorial was first written, the iPhone 5 had just come out. Around that time not many people had access to Touch ID, especially on iPad. We wanted to make sure that we could provide a fallback for users who couldn’t use the framework. There are still lots of iPad 2’s, 3’s and iPad Mini’s out there

Additionally when I started writing the tutorial, the 1Password SDK had just come out, I wasn’t aware that it didn’t work directly with Touch ID, in fact if I recall correctly, it didn’t. It does support Touch ID now to open the Extension as well.

So the tutorial was written to provide enough information for someone to build upon. It is in no way intended to be the ideal workflow. There are also plenty of Swift based Keychain Wrappers out there now. There weren’t many when the tutorial was first written.

Glad you enjoyed the tutorial and I’m also pleased that you can see the flaws. That means you’ll probably take the idea to the next level.

How do I test the credentials which saved in IOS keychain?
As a tester, I want to test the credentials which saved in IOS keychain. scenarios which App can not contact the keychain, Crashed credentials (how to crash?), does the correct credentials use in all the times, Does the credentials remove when the app close and uninstall… etc. How do I do that as a tester?

If you’re asking about writing a unit test you would need to mock the data. So inside your test function you would create a record to store in the keychain and then follow it up with a XCTAssertEqual(_:slight_smile: [or True] to see if the value gets stored as expected or not.

Does that answer your question?

Since Keychain is synchronized over iCloud. So, that means if a User logs in with his/her iCloud account in 2 devices, both the devices will have the same Keychain. Am I Right?

I’m running the KeyChain wrapper on xcode 8.3.2 for iOS 10

I’m able to successfully build my project.

However while running the application I get an exception while execution reaches the point to save password to keychain

The error is logged as

Assertion failure in -[KeychainWrapper writeToKeychain]
/Users/val/Desktop/IOS/Projects/EprojectApp/EprojectApp/KeychainWrapper.m:247
NSInternalInconsistencyException’, reason: 'Couldn’t add the Keychain Item

I googled a bit and found a solution about adding the KeyChain sharing entitlements to my Build Capabilities but this didn’t resolve the error.

We’ve just finished updating the tutorial for Swift 3.0 using a Swift Wrapper. It should be out soon. I’ll take a look at your problem and get back to you.

Hmm. Interesting question. I’ll have to try that. I think as long as the App identifier is the same it should work. You may need to tweak the Keychain capability to make that work.

For security help and tips go to https://babasupport.org/apple/iphone-error-4005/ and learn how to secure the confidential data.

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!