Keychain Services iOS [Working project]

I’ve been attempting to implement Keychain services for iOS because there has been some interest in it, and I see it as something I will probably need in the future, however I have reached an impasse because I cannot determine what value to use for the constant kCFBooleanTrue, which represents the true value for a CFBoolean. Using the Swift playground, and code:

import CoreFoundation var tmp = kCFBooleanTrue print(tmp)
I get an output of “1” indicating that kCFBooleanTrue should have a value of 1, however using a value of 1, an error is logged in the console:

Jan  5 19:22:17 s-kingj.local securityd[8344]:  securityd_xpc_dictionary_handler My iOS App.debug[62140] copy_matching The operation couldn’t be completed. (OSStatus error -50 - add_return: value 1 is not CFBoolean)

Determining the value of kCFBooleanTrue is the last step in my Keychain services implementation, but also the most important since it is required to retrieve a password stored on the keychain. Any help with this would be appreciated.

Project Link:
https://www.dropbox.com/s/yrk05fil2zys5ka/keychain%20access.xojo_binary_project?dl=0

Looks to me like it’s actually a pointer to a structure.

I think you might have to implement a function that returns the boolean value you want.

Check out CFNumber.h and follow the rabbit hole from there. Good luck. My head started hurting when I realized I need to look in multiple header files to figure this out. Maybe something is already implemented for NSBoolean in MacOS lib you could pull from. I didn’t check.

I got it working with NSNumber numberWithBool:

declare sub setObjectForKey lib FoundationLib selector "setObject:forKey:" (obj_id as ptr, obj as ptr, key as CFStringRef)
  declare function NSClassFromString lib FoundationLib (clsName as CFStringRef) as ptr
  Declare Function numberWithBool lib "Cocoa" selector "numberWithBool:" (class_ref as ptr,value as Boolean) as ptr
  dim kcfbooleantrue as ptr=numberWithBool(NSClassFromString("NSNumber"),true)
  
  setObjectForKey(dictRef, kcfbooleantrue, kSecReturnData)

Thanks Jim. That did it. The link has been updated to the working version.

Jason, how would you do the same thing as the desktop keychain examples at http://documentation.xojo.com/index.php/KeyChain ?

It works exactly the same as the desktop keychain, except that I called the class JK_KeychainItem and the module KeychainServices incase Xojo adds keychain support so that there is no duplicate naming.

To save a password you create a new item and set the account name, label, or any other properties you want to, then call KeychainServices.AddPassword:

dim item as new KeychainServices.JK_KeychainItem item.AccountName = "Foo" KeychainServices.AddPassword(item,"Bar")

To retrieve a password, you create a new item, set the same properties you used to save the password, then retrieve the password with KeychainServices.FindPassword:

dim item2 as new KeychainServices.JK_KeychainItem item2.AccountName = "Foo" dim pswd as Text = KeychainServices.FindPassword(item2) //pswd is set to "Bar"

[quote=157409:@Jason King]It works exactly the same as the desktop keychain, except that I called the class JK_KeychainItem and the module KeychainServices incase Xojo adds keychain support so that there is no duplicate naming.

To save a password you create a new item and set the account name, label, or any other properties you want to, then call KeychainServices.AddPassword:

dim item as new KeychainServices.JK_KeychainItem item.AccountName = "Foo" KeychainServices.AddPassword(item,"Bar")

To retrieve a password, you create a new item, set the same properties you used to save the password, then retrieve the password with KeychainServices.FindPassword:

dim item2 as new KeychainServices.JK_KeychainItem item2.AccountName = "Foo" dim pswd as Text = KeychainServices.FindPassword(item2) //pswd is set to "Bar"[/quote]

Superb. Thank you :slight_smile:

You’re welcome :slight_smile:

I’m having a bit of trouble with this though I’m probably using it the wrong way.

I want to store my user’s username (accountname) and password in the keychain if they choose to have the app remember their login details. According to the docs it looks as though I should be able to do this but I only seem to be able to retrieve the password, not the accountname property.

When the user chooses “remember me” on my Login View, I save their username and password:

dim kc as new KeychainServices.JK_KeychainItem kc.ServiceName = "myAppName" kc.AccountName = User.Username KeychainServices.AddPassword(kc, User.Password)

When my app next starts, I call FindPassword to find the keychain item and then access the AccountName property to retrieve the username:

dim kc as new KeychainServices.JK_KeychainItem kc.ServiceName = "myAppName" User.Password = KeychainServices.FindPassword(kc) User.Username = kc.AccountName

However the AccountName property is always blank. The AddPassword method only seems to save the password and not the other properties, including AccountName.

Am I using it the wrong way?

Or rather, looking at the code, it seems to be that FindPassword doesn’t populate the KeychainItem.

I don’t really have iOS, nor have I read much of this thread, but while you’re doing auth stuff you should make an easy 1Password integration thing :stuck_out_tongue:

What do you think @Jason King ? Am I missing a step to save the AccountName along with the Password?

Hi Jason, I made the project so it mimicked the Keychainitem we are used to for desktop. Unfortunately that means that the username cannot be saved as well as it is implemented. (I’m actually not sure if it’s possible to save the username anyway.) Maybe you could save the username and password as two separate items on the keychain?

Hi Jason

Thanks and yes it “mimics” the desktop KeyChainItem partially, except that the desktop KeyChainItem allows saving of the additional KeyChainItem properties, such as the AccountName.

So if you add this code to a desktop app, both the AccountName and Password will be saved to the KeyChain:

[quote]'Save username and password
dim kc as new KeychainItem
kc.ServiceName = “myAppName”
kc.AccountName = “AppUser”
System.KeyChain.AddPassword(kc, “AppPassword”)
[/quote]

And then if you add this code to a desktop app, both the AccountName and Password will be returned from the KeyChain:

[quote]'Retrieve username and password
dim kc as new KeychainItem
kc.ServiceName = “myAppName”
dim passWord as string = System.Keychain.FindPassword(kc)
dim userName as string = kc.AccountName[/quote]

So while your implementation is able to save a password to the KeyChain, it seems to ignore the other properties of the KeyChainItem. These other properties make the KeyChainItem particularly useful as they allow you to save and retrieve all of a user’s login credentials if they choose to have these remembered by the app.

Ok I overlooked that functionality of the Xojo KeychainItem. I’ll see if I can fix it later this week.

As always, thank you Jason. :slight_smile:

I updated the project so that it has the exact same functionality as the Desktop KeychainItem and will fill the properties of a passed KeychainItem when performing a lookup with KeychainServices.FindPassword(). Please redownload the project from the link below because there were substantial changes to the code. Enjoy!

https://www.dropbox.com/s/77ffoa6mt7jwtls/keychain%20services%202.0.xojo_binary_project?dl=0

It’s working perfectly for me. Thank you again Jason!

Jason, I downloaded the file at the link above and the code doesn’t compile. It was no biggie to fix. Maybe you were testing something? I just wanted to put this here in case anyone else has the problem.

Putting this on View1 Open will work:

[code] using KeychainServices

dim item1 as new JK_KeychainItem
item1.ServiceName = “awesomeApp”
item1.AccountName = “username”
item1.Comment = “This is a comment”
item1.Description = “Username and password”
item1.Label = “Unlabeled”
KeychainServices.AddPassword item1, “password”

dim item2 as new JK_KeychainItem
item2.ServiceName = “awesomeApp”
dim thePassword as Text = KeychainServices.FindPassword(item2)
dim theAccountName as Text = Item2.AccountName
dim theComment as Text = Item2.Comment
dim theDescription as Text = Item2.Description
dim theLabel as Text = Item2.Label
dim theServiceName as Text = Item2.ServiceName

Break[/code]

Yeah I was testing something, looks like I didn’t revert all of the changes. A more complete demo will be included in the next version of iOSKit.