I just found an interesting problem with my app. In the app I am saving the user's user name and password to the keychain.
keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil];
[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount];
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData];
When this code is run in Debug it seems to work just fine. It updates each time and I can later retrieve the items from the keychain. When it is run in Distribution however the keychain never gets updated. I have verified that yes these lines of code are hit in both builds. I am using Xcode 4.2 with the iOS5 SDK and running the app on an iPad 2 with iOS5 installed.
When you include
keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil];
[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount];
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData];
you also had to include
[keychainWrapper setObject:@"Myappstring" forKey: (id)kSecAttrService];
Or I get a "SIGABRT" error. (Myappstring) is a string defining your application.
Maybe I'm missing something, this should be done at least once.
I also had this problem, and it took me forever to figure out
There is a version of "KeychainWrapper" floating around that has it's SecItemUpdate within an NSAssert (among other things).
Whoever did this is a moron!, when building for release/distribution every NSAssert is nullified, meaning that code doesn't even get run.
For example:
NSAssert(SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck), @"Couldn't update the Keychain Item." );
Needs to become
OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
NSAssert(status == noErr, @"Couldn't update the Keychain Item." );
Notice how the actual SecItemUpdate is moved outside the NSAssert, and instead the result is checked
Important note: Attempting to update a value for kSecValueData, without also specifying a value for kSecAttrAccount, will cause the assertion to fail as well. So, if your intent is to store a single string of sensitive data (such as a list of credit card numbers), be sure to store some "account name" text in the kSecAttrAccount attribute, like so:
static NSString* kCardListXML = @"cardListXML";
static NSString* cardListAccountName = @"cardListAccount";
-(void)setCardListXML:(NSString*)xml {
KeychainItemWrapper* wrapper =
[[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil];
[wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)];
[wrapper setObject:xml forKey:(id)CFBridgingRelease(kSecValueData)];
}
-(NSString*)getCardListXML {
KeychainItemWrapper* wrapper =
[[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil];
[wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)];
return [wrapper objectForKey:CFBridgingRelease(kSecValueData)];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With