Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

ios5 - iOS KeychainItemWrapper not updating

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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)];
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...