Странное поведение KeychainItemWrapper, ошибка существующего/несуществующего элемента с тем же элементом

после того, как я столкнулся с множеством проблем с классом KeychainItemWrapper, предоставленным Apple, я смог заставить его работать, но потом я что-то сделал со своим кодом, и теперь он находится в нестабильном состоянии. На самом деле у меня есть оригинальный класс KeychainItemWrapper, я просто изменил следующие строки для проверки результатов:

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." );
}

Первая переменная cpy возвращает -25300 (Элемент не может быть найден)

SecItemAdd возвращает errSecDuplicateItem (-25299 элемент уже существует)

И затем я пытаюсь удалить элемент, если функция говорит, что элемент существует, а SecItemDelete снова возвращает -25300, так что... теперь я не могу понять, что происходит.

Я провожу этот тест на iPad с iOS 6.1.3, есть какие-нибудь мысли по этому поводу? Есть ли способ полностью сбросить связку ключей и начать с нуля?

Спасибо за любую помощь


person Rodrigo.C    schedule 19.07.2014    source источник


Ответы (1)


Я обнаружил проблему после информации, представленной в этой ссылке: Что делает связку ключей уникальный элемент (в iOS)?

«Для элемента цепочки для ключей класса kSecClassGenericPassword первичный ключ представляет собой комбинацию kSecAttrAccount и kSecAttrService».

Похоже, что образец класса KeychainItemWrapper, предоставленный Apple, использует неправильную комбинацию клавиш или бесполезен для того, что я пытался сделать.

Во всяком случае, я удалил этот класс, и теперь я использую какой-то упрощенный метод, я помещаю код здесь, возможно, это полезно для кого-то еще:

- (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;
}

Как это использовать:

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

[self setKeyChainItem:@"myStoredVvalue" withValue:@"12345"];
person Rodrigo.C    schedule 21.07.2014