Reputation: 36013
I am storing passwords on keychain using Apple's KeychainItemWrapper
. At some point, if I try to fetch a password that was not setup yet using
KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:identifier accessGroup:nil];
NSString *password = [keychain objectForKey:kSecValueData];
password returns with this identification on the debugger
password = (_NSZeroData *) class name = _NSZeroData
If I let the code go on and try to use this value it will crash.
This value is not a nil. If I test using if (!password)
it will fail... and is not a string empty value (it will crash if I try to test it as a NSString).
How do I test this thing to see if it is valid before proceeding?
Upvotes: 3
Views: 1610
Reputation: 36013
I discovered the problem and by the way, I hate with passion the crappy documentation Apple writes about everything.
This is the problem. Despite the documentation suggesting that you should store passwords like plain strings like this using kSecValueData
:
NSString *myPassword = @"12345";
KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:identifier accessGroup:nil];
[keychain setObject:myPassword forKey:(__bridge id)kSecValueData];
you should never do that. In fact kSecValueData
, as the name suggests and the documentation should say, expects a NSData
object. So, you must convert the NSString
to NSData before storing it, like this:
NSString *myPassword = @"12345";
KeychainItemWrapper* keychain = [[KeychainItemWrapper alloc] initWithIdentifier:identifier accessGroup:nil];
NSData *myPasswordData = [myPassword dataUsingEncoding:NSUTF8StringEncoding];
[keychain setObject:myPasswordData forKey:(__bridge id)kSecValueData];
when getting it back you must cast it to NSData
and convert it back to NSString
:
NSData *myPasswordData = (NSData *)[keychain objectForKey:(__bridge id)kSecValueData];
NSString *myPassword = [[NSString alloc] initWithData: myPasswordData
encoding:NSUTF8StringEncoding];
Upvotes: 4