1

after leading with a lot of problems with the class KeychainItemWrapper provided by Apple, I could make it works, but then I did something on my code and looks like now it's in an unstable state. Actually I have the original KeychainItemWrapper class, I just changed the following lines for checking the results:

OSStatus cpy = SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes);
NSLog(@"cpy result=%d", cpy);
if (cpy == noErr)
{
  ....
}
else
{
  // No previous item found; add the new one.
  result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
  if(result == errSecDuplicateItem) {
      result = SecItemDelete((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData]);
      NSLog(@"result=%d", result);
  }
  NSAssert( result == noErr, @"Couldn't add the Keychain Item." );
}

The first cpy variable returns -25300 (The item cannot be found)

SecItemAdd returns errSecDuplicateItem (–25299 the item already exists)

And then Im trying to remove the item if the function is saying that an item exists, and SecItemDelete returns -25300 again, so... now I cannot understand what's happening.

Im running this test with an iPad with iOS 6.1.3, any thoughs on this? Is there any way to reset the keychain completely and start from the scratch?

Thanks for any help

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Rodrigo.C
  • 1,123
  • 2
  • 10
  • 22

1 Answers1

3

I found the problem following the info provided in this link: What makes a keychain item unique (in iOS)?

"For a keychain item of class kSecClassGenericPassword, the primary key is the combination of kSecAttrAccount and kSecAttrService."

It looks like the KeychainItemWrapper sample class provided by Apple is using a wrong combination keys, or is not useful for what I was trying to do.

Anyway I removed that class and now Im using some simplified method, I put the code here, probably it's helpful for someone else:

- (NSString*) getKeyChainItem:(NSString*)key {
  NSString* keyChainValue = NULL;
  NSData *attributes = NULL;

  NSMutableDictionary* keyChainParams = [self createKeyChainDict:key];
  [keyChainParams setObject:key forKey:(id)kSecAttrService];
  [keyChainParams setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];

  if (SecItemCopyMatching((CFDictionaryRef)keyChainParams, (CFTypeRef *)&attributes) == noErr)
  {
    keyChainValue = [[[NSString alloc] initWithBytes:[attributes bytes] length:[attributes length]
                                            encoding:NSUTF8StringEncoding] autorelease];
  }
  return keyChainValue;
}

- (BOOL) setKeyChainItem:(NSString*)key withValue:(NSString*)value {
  NSMutableDictionary* keyChainParams = [self createKeyChainDict:key];
  [keyChainParams setObject:[value dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];

  return SecItemAdd((CFDictionaryRef)keyChainParams, NULL) == noErr;
}

- (NSMutableDictionary*)createKeyChainDict:(NSString*)key {
  NSMutableDictionary* keyChainParams = [[NSMutableDictionary alloc] init];
  [keyChainParams setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
  [keyChainParams setObject:@"" forKey:(id)kSecAttrLabel];
  [keyChainParams setObject:@"" forKey:(id)kSecAttrDescription];
  [keyChainParams setObject:key forKey:(id)kSecAttrService];
  [keyChainParams setObject:key forKey:(id)kSecAttrAccount];
  return keyChainParams;
}

How to use it:

NSString* myValue = [self getKeyChainItem:@"myStoredVvalue"];

[self setKeyChainItem:@"myStoredVvalue" withValue:@"12345"];
Community
  • 1
  • 1
Rodrigo.C
  • 1,123
  • 2
  • 10
  • 22