29

This question discusses encrypting data on the iPhone using the crypt() function. As an alternative, is there a keychain on the iPhone and if so, what code would I use to access it in order to store login details and then retrieve them for us in an application?

Community
  • 1
  • 1
davidmytton
  • 38,604
  • 37
  • 87
  • 93

7 Answers7

45

One other thing to note: the keychain APIs don't work in the simulator when using older versions (2.x, 3.x) of the iPhone SDK. This could save you a lot of frustration when testing!

Brad The App Guy
  • 16,255
  • 2
  • 41
  • 60
Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
34

There is a keychain you can use - for code, the best bet is to check out the GenericKeychain sample application from Apple:

GenericKeychain sample

GeneralMike
  • 2,951
  • 3
  • 28
  • 56
Adam Byram
  • 1,422
  • 10
  • 8
8

I really like Buzz Anderson's Keychain abstraction layer and I eagerly await Jens Alfke's MYCrypto to reach a usable state. The latter does a competent job of allowing use on Mac OS X and the iPhone using the same code, though its features only mimic a small subset of the Keychain's.

bbrown
  • 6,370
  • 5
  • 37
  • 43
8

Here is what i use to store Key/Value pairs in the keychain. Make sure to add Security.framework to your project

#import <Security/Security.h>

// -------------------------------------------------------------------------
-(NSString *)getSecureValueForKey:(NSString *)key {
    /*

     Return a value from the keychain

     */

    // Retrieve a value from the keychain
    NSDictionary *result;
    NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecReturnAttributes, nil] autorelease];
    NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, kCFBooleanTrue, nil] autorelease];
    NSDictionary *query = [[NSDictionary alloc] initWithObjects: objects forKeys: keys];

    // Check if the value was found
    OSStatus status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &result);
    [query release];
    if (status != noErr) {
        // Value not found
        return nil;
    } else {
        // Value was found so return it
        NSString *value = (NSString *) [result objectForKey: (NSString *) kSecAttrGeneric];
        return value;
    }
}




// -------------------------------------------------------------------------
-(bool)storeSecureValue:(NSString *)value forKey:(NSString *)key {
    /*

     Store a value in the keychain

     */

    // Get the existing value for the key
    NSString *existingValue = [self getSecureValueForKey:key];

    // Check if a value already exists for this key
    OSStatus status;
    if (existingValue) {
        // Value already exists, so update it
        NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, nil] autorelease];
        NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, nil] autorelease];
        NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
        status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionary dictionaryWithObject:value forKey: (NSString *) kSecAttrGeneric]);
    } else {
        // Value does not exist, so add it
        NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrGeneric, nil] autorelease];
        NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, key, value, nil] autorelease];
        NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease];
        status = SecItemAdd((CFDictionaryRef) query, NULL);
    }

    // Check if the value was stored
    if (status != noErr) {
        // Value was not stored
        return false;
    } else {
        // Value was stored
        return true;
    }
}

It is worth noting that these key/values will not get deleted if the user deletes your app. If a user deletes your app, then reinstalls it, the key/values will still be accessible.

AlBeebe
  • 8,101
  • 3
  • 51
  • 65
  • This code worked fine for me on the simulator running iOS 4.3 – AlBeebe Sep 06 '11 at 02:09
  • 2
    There is a bug in Selector getSecureValueForKey: When you return the value, it is already released. It is released by "[result release];" – Mhh Lecker Feb 03 '12 at 16:03
  • I modified to be C functions instead of Objective-C methods. In my case, I would like to make this functionality available to any object on my app, and the functionality itself doesn't seem to require any kind of persistent storage (ivars). But otherwise, great snippet! – Nicolas Miari Jun 25 '12 at 08:54
5

Also remember that when generating an AppID, if you want more than one application to access the same Keychain information, you have to generate a wild card AppID (#####.com.prefix.*)...

whoisjake
  • 622
  • 4
  • 7
4

With the latest version 1.2 of the GenericKeychain sample Apple provides a keychain wrapper that also runs on the iPhone Simulator. Check out at this article for details: http://dev-metal.blogspot.com/2010/08/howto-use-keychain-in-iphone-sdk-to.html

joobik
  • 57
  • 1
0

Here is one more good wrapper class from Mr.Granoff https://github.com/granoff/Lockbox Thanks

Bhavin Kansagara
  • 2,866
  • 1
  • 16
  • 20