Biometric authentication with Touch ID

Biometric authentication with Touch ID

Touch-ID-640x384

Passwords have become such a pain in the neck. Switching between different apps and websites you will usually find different password security policies. One site will inform you no more than 10 characters, other a 6 digits pin. While some other sites will insist in making you change your password every 15 days, and so on.

Why does this have to be so complicated, and hard to manage? Wouldn’t it be so much easier to use something that you have as a key instead of having to remember so many different passwords across a plethora of different sites!?

Well, there is something that most of us have. Something we were born with. Something we use every single day. That is our fingerprint. Each fingerprint has a unique pattern that can be used as key. In this blog post, I’ll talk about my experience of playing around with Apple’s Touch ID.

The Keychain in iOS

Keychain_Access_IconOk so you have your fingerprint, but what would you try to unlock with it? The answer is of course the Keychain Store! The Keychain is basically an encrypted database that stores protected information like passwords and chunks of text you might want to protect. It can also store certificates and cryptographic keys. On Macs, you can access it as a user through the ‘Keychain Access’ app. In addition, because iOS is built on the foundation of Mac OS X, it also has its own Keychain.

The way access to the Keychain works in iOS is anologous to the Mac. Your app doesn’t access it directly, and it has no knowledge of how to encrypt or decrypt the information stored within it. All the communication is done through a C API which ends up calling a system daemon known as ‘securityd‘. This daemon then checks your access entitlements to the item you want to access, and returns it decrypted. There is more information on iOS security here.

But where does your fingerprint fit into this equation?

Touch ID

touch-id-icon
Your fingerprint will be the key that ultimately opens the access to the Keychain Item you want access to. iOS devices have a very powerful fingerprint sensor, which is capable of reading fingerprints at any angle. It’s also pretty fast and keeps learning about your fingerprint patterns the more you use it.

When you register your fingerprint pattern, that information is never stored in the file system, or directly in memory. The patterns are stored in a vectorised form in the ‘Secure Enclave’. The Secure Enclave is a coprocessor part of the A7, and newer chips that provide all the cryptographic operations for data protection, which include fingerprint pattern matching, passcode storage, and key decryption. All these operations are done independently of the OS Kernel, and this maintains data protection integrity, even if a kernel should be compromised. Through the Keychain APIs, your app can store passwords and set ACL permissions.

At a high level, this is how it works:

  1. When your app tries to retrieve a password, the securityd daemon handles the initial request.
  2. It then retrieves the encrypted item from the Keychain, and passes it to the Secure Enclave, which then prompts for Touch ID authentication, depending on the ACL you set.
  3. The Secure Enclave decrypts the item and returns it to securityd. All of this happens outside the apps process space.
  4. The securityd damon will finally return the decrypted item to your app.

Keychain2

When storing your secret in the Keychain, you can specify when your item will be accessible if you try to read it later. The options go from accessible when the device unlocked to accessible anytime. It’s also possible to restrict the item to stay in the device only. This means the the secret will not be backed up. These options are explained in more details in here.

Ok, that’s great, but how do I actually implement Touch ID authentication?

Firstly, there is a shortcut if you are not interested in storing anything in the Keychain. For example, if you want to implement parental protection to certain features in your app. You can just prompt the user to authenticate through Touch ID and simply get a callback telling you if the authentication was successful or not, like so:


let laContext = LAContext()

//Find out if Touch ID is available
let touchIDAvilable = laContext.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: nil)

if touchIDAvilable {
  //This will present the UI prompting the user to authenticate using Touch ID
  laContext.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Please authenticate",
  reply: { (authenticated, error) -> Void in

    if authenticated {
      //Continue with the operation
    } else {
      //some error and the operation will be stopped
    }
  })

} else {
  //Show message TouchID not available
}

This will prompt a message like this:

TouchID UI

Protecting your precious treasures

gollum-n-the-ringA more secure option is actually storing your secret, in this case your password, in the Keychain itself. This can be done through the Keychain API that comes with the Security framework. The bad news is that it’s a C API, which makes it a little bit tricky. As a side note, wrapping some C APIs like this one in a higher level language is long overdue for Apple.

The good news is you can bridge this API using either Objective-C or Swift. To store your secret you need to call the ‘SecItemAdd’ function, and pass a dictionary with the different parameters. An important parameter to pass in the dictionary is the ‘AccessControlFlags‘. We need to create this ‘AccessControlFlags’ calling the C function ‘SecAccessControlCreateWithFlags‘:

var aclError: Unmanaged<CFErrorRef>?
var accessControl :Unmanaged<SecAccessControl> =
SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, SecAccessControlCreateFlags.UserPresence, &aclError)

If you want the tightest security level you can use ‘kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly‘ that will prevent the item to be synced, or backed up, and if for some reason the passcode is removed, the secret will no longer be accessible.

The value ‘SecAccessControlCreateFlags.UserPresence’ is the key that will prompt the user for authentication when trying to retrieve the item. You might have noticed the ‘Unmanaged‘ type defined above when declaring the ‘aclError’ and the ‘accessControl’ variables. We need to do this since we are calling a C API. This means that the C API will be allocating the memory for this variable. I know, it’s a little messy. But look on the bright side – there is no need to create a special interface in C and compiled it separately like other languages i.e. Java.

Since the Keychain is essentially a database, we need to define the fields we want to insert using the dictionary. We use ‘kSecAttrAccessControl’ to specify the ACL. Again due to the fact we are talking to C we need to define our Dictionary as ‘<String:AnyObject>’ since the ‘SecItemAdd’ expects a CFDictionaryRef:

let password = “password”
let secret :NSData = password.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
//Prepare the query
let query :[String: AnyObject] = [
  String(kSecClass): kSecClassGenericPassword,
  String(kSecAttrService): “MyService”,
  String(kSecAttrAccount): “fooUser”,
  String(kSecValueData): secret,
  String(kSecAttrAccessControl) : accessControl.takeRetainedValue()
]

let status = SecItemAdd(query, nil)
if status != errSecSuccess {
  //We check the error code
}

Using Touch ID to retrieve your treasures

Retrieving the secret back is not too different than storing it. We just need to build our query. We define a dictionary very similar to the one we used when storing the secret the difference is that we need to specify two additional parameters.

  • kSecReturnData‘ tells the function ‘SecItemCopyMatching‘ that we want to retrieve the secret.
  • kSecUseOperationPrompt‘ allows you to define the message that will be shown when presenting the Touch ID view.

The function expects 2 parameters the first one is the dictionary with the query parameters and the second is a reference as a placeholder to pass the retrieved secret back:

let returnData: NSNumber = true
let query :[String:AnyObject] = [
  String(kSecClass): kSecClassGenericPassword,
  String(kSecAttrService): &quot;serviceName&quot;,
  String(kSecAttrAccount): &quot;username&quot;,
  String(kSecReturnData) : returnData,
  String(kSecUseOperationPrompt) : prompt
]
var passwordPointer :Unmanaged&lt;AnyObject&gt;?
let status = SecItemCopyMatching(query, &amp;passwordPointer)
if status != errSecSuccess {
  //Check the error
}

if let passwordRetrieved = passwordPointer {
  let passwordData :NSData = passwordRetrieved.takeRetainedValue() as! NSData
  return NSString(data: passwordData, encoding:NSUTF8StringEncoding) as! String
}

The secret will be returned in ‘passwordPointer’. We need to convert it to ‘NSData’ and then encode the bytes in it as a UTF string.

With this option, you will get 3 attempts with Touch ID, and 5 with passcode. After this, the access will be locked for a minute. If after a minute you fail again to enter the passcode correctly, it will lock you out for 5 minutes. Then it will go up to 15m.. 30m .. 1hr, and so on. This is not exactly ideal, but there is a better way to handle this…

Circumventing the rolling lock outs

The better way of retrieving your treasures without the risk of lock outs, is to store the password in the keychain by specifying ‘SecAccessControlCreateFlags.allZeros’ when creating the ACL. Using this option, the user won’t be prompted to authenticate when calling ‘SecItemCopyMatching’, and you will have all the security advantages outlined above.

Before retrieving the password you can use ‘LAContext::evaluatePolicy’. This will present the UI for authentication through Touch ID. If user authentication fails, the error will be ‘AuthenticationFailed’. A much better solution would be to delete the password in the Keychain, and ask the user to re-enter the password.

laContext.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: &quot;Please authenticate&quot;,
reply: { (authenticated, error) -&gt; Void in
  if authenticated {
    //We retrieve the secret here from the keychain
  }
  else {
    let laError = LAError(rawValue: error.code)
    if laError == LAError.AuthenticationFailed || laError == LAError.UserFallback {
      //Delete the secret
      let query = [
        String(kSecClass): kSecClassGenericPassword,
        String(kSecAttrService): serviceName ,
        String(kSecAttrAccount): username
      ]

      let status = SecItemDelete(query);
      //check error
    }
  }
})

TOTP – the icing on the cake

baker_16048826

You could even add a TOTP secret to your Keychain. In a previous blog post, I went through how to implement TOTP server side using Java, and the Spring Framework. Since TOTP is just an algorithm based on a shared secret, and the current timestamp, you can simply implement the algorithm yourself, or use this library.

In addition, iOS supports natively reading QRCodes, and it’s pretty easy to get working. You just need to import ‘AVFundation‘, and implement the AVCaptureMetadataOutputObjectsDelegate protocol, then set your View Controller as the delegate. Finally, you will get a callback when a QRCode has been captured, and receive the value decoded as a String. That String can be simply parsed to extract the secret.

If you are curious about the details, you can look at the demo project that I wrote here. It’s developed in Objective-C, and I haven’t had time to port it to Swift yet!

So you have the secret, and you can now store it in the Keychain. When authenticating with your server you can use ‘LAContext‘ to ask the user to authenticate through Touch ID, and if the authentication is successful you can retrieve the secret and run it through the TOTP algorithm to calculate the token.

Now that you have the username, password and token they can be sent to the server to proceed with the authentication.

Of course you should delete the password and the TOTP secret if the Touch ID fails or the server gets back to you with the wrong credentials error.

Conclusion

Keychain and Touch ID are very powerful tools and, if you implement them well, they can help alleviate user frustration related to entering passwords all the time. They also make your credentials more secure as they eliminate the risk of someone looking over your shoulder when you are typing your password. As with all sensitive/private information, it’s always good to be very careful once you recover the information from the Keychain. Never store it in a global variable, and never store decrypted information in memory longer than it’s needed.

No Comments

Leave a Reply

Discover more from Shine Solutions Group

Subscribe now to keep reading and get access to the full archive.

Continue reading