Подтвердить что ты не робот

Ошибка сохранения в цепочке ключей с помощью iphone sdk

Я использую Apple wraper для брелка и пытаюсь сохранить элемент на нем (работает в симуляторе, ios 4.1).

Я раньше не встречался с брелками.

Я получаю эту ошибку:

Не удалось добавить элемент Keychain. Ошибка - 25299

В KeychainItemWrapper.m строка 304:

// No previous item found; add the new one.
result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
NSAssert( result == noErr, @"Couldn't add the Keychain Item." );

Вот как я делаю сохранение:

- (void) saveKey:(NSString *)key value:(NSString *)value {
    KeychainItemWrapper *keyItem = [[KeychainItemWrapper alloc] initWithIdentifier:key accessGroup:nil];
    [keyItem setObject:value forKey:(id)kSecValueData];
    [keyItem release];
}

И это значения, которые api пытается сохранить:

<CFBasicHash 0x7231f60 [0x320d380]>{type = mutable dict, count = 5,
entries =>
2 : <CFString 0x2e6eb98 [0x320d380]>{contents = "labl"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
3 : <CFString 0x2e6efb8 [0x320d380]>{contents = "v_Data"} = <CFString 0x727de60 [0x320d380]>{contents = "dit8"}
4 : <CFString 0x2e6ebc8 [0x320d380]>{contents = "acct"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
5 : <CFString 0x2e6eb58 [0x320d380]>{contents = "desc"} = <CFString 0x2fb018 [0x320d380]>{contents = ""}
6 : <CFString 0x2e6ebe8 [0x320d380]>{contents = "gena"} = <CFString 0x2ffd08 [0x320d380]>{contents = "userCode"}
}
4b9b3361

Ответ 1

Я знаю, что это было несколько месяцев назад, но у меня была одна и та же проблема, и мне было больно, поэтому я решил поделиться с вами. Я решил это, добавив эту строку:

[self.keychainItemWrapper setObject:@"MY_APP_CREDENTIALS" forKey:(id)kSecAttrService];
//@"MY_APP_CREDENTIALS" can be any string.

Я нашел эту запись в блоге очень полезной: "В терминах базы данных вы могли бы подумать о том, что они являются уникальным индексом для двух атрибутов kSecAttrAccount, kSecAttrService, требуя, чтобы комбинация этих двух атрибутов была уникальной для каждой записи в цепочке ключей". (от http://useyourloaf.com/blog/2010/4/28/keychain-duplicate-item-when-adding-password.html).

Кроме того, в примере проекта Apple, использующем этот код, они создают экземпляр KeychainItemWrapper в делегате приложения. Я не знаю, нужно ли это, но мне нравится как можно ближе следовать их примерам:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//there will be some standard code here.
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MY_APP_CREDENTIALS" accessGroup:nil];
self.keychainWrapper = wrapper;
[self.keychainWrapper setObject:@"MYOBJECT" forKey:(id)kSecAttrService];
[wrapper release];
}

Я думаю, что это ошибка в коде оболочки. Логика в основном говорит: "Есть ли эта запись уже? Нет, это не так. Хорошо, я добавлю ее. К сожалению, вы не можете добавить ее, потому что она уже существует".

Вам также может потребоваться установить kSecAttrAccount; Я никогда не пробовал это, не устанавливая это значение, так как он предназначен для сохранения имени пользователя, которое идет с паролем:

[self.wrapper setObject:txtUserName.text forKey:(id)kSecAttrAccount];   

Ответ 2

Согласно документации, ошибка -25299, которую вы получаете, это "errSecDuplicateItem", что означает, что элемент, который вы пытаетесь добавить, уже существует. Если посмотреть на связанный код для KeychainItemWrapper, я бы предположил, что вызов SecItemCopyMatching терпит неудачу с ошибкой, отличной от errSecItemNotFound (-25300).

Ответ 3

Вы можете легко сохранить и вернуть значения с помощью брелка с помощью SFHFKeychainUtils от Buzz Andersen.

  • Загрузите и скопируйте в свой проект SFHFKeychainUtils.h и .m
  • Добавить Security.framework в папку с вашей инфраструктурой
  • Убедитесь, что эти файлы добавлены в вашу цель.
  • Импортируйте SFHFKeychainUtils.h, где вы хотите его использовать.

Это небольшой пример того, как использовать эту библиотеку.

// To store data
NSError *error = nil;
[SFHFKeychainUtils storeUsername:username andPassword:password forServiceName:kStoredData updateExisting:YES error:&error];

// To retrieve data
NSString *password = [SFHFKeychainUtils getPasswordForUsername:username andServiceName:kStoredData error:&error];

// To delete data from keychain
[SFHFKeychainUtils deleteItemForUsername:username andServiceName:kStoredData error:&error];

Ответ 4

Брелок - полная боль. Вы должны использовать Buzz Andersen STUtils вместо оболочки. Это значительно упростит вашу жизнь. У меня никогда не было проблем с этим.

Ответ 5

Для меня решение заключалось в том, что я создал KeychainItemWrapper "singleton" и использовал его во всем приложении. (На самом деле, в моем случае, у меня был синглетный словарь, полный KeychainItemWrapper -s, потому что я использую более одного.)

Это решило проблему, когда я добирался до кодового пути, который эффективно сказал: "Этот элемент существует в цепочке ключей? Нет?" Затем добавьте его. Упс! NSAssert(), что я пытаюсь добавить элемент, который уже существует (Ошибка -25299) "

Пока я не уверен, я подозреваю, что проблема связана с синхронизацией keychain. У меня были схожие проблемы с NSUserDefaults, когда я пишу в NSUD, а затем в другом месте кода получаю standardUserDefaults и читаю от них, и обновление еще не выполнено (потому что я еще не сделал [ud synchronize], все же.)

В коде моя процедура выглядит так:

+ (KeychainItemWrapper*) keyChainWrapperForKeyID: (NSString*) keyID
{
    static dispatch_once_t onceToken = 0;
    static NSMutableDictionary *rfcuKeyChains = nil;
    dispatch_once(&onceToken, ^{
        rfcuKeyChains = [NSMutableDictionary new];
    });

    KeychainItemWrapper *keychain = nil;
    @synchronized (rfcuKeyChains)
    {
        keychain = [rfcuKeyChains objectForKey: keyID];
        if (keychain == nil)
        {
            keychain = [[KeychainItemWrapper alloc] initWithIdentifier: keyID accessGroup: nil];
            [rfcuKeyChains setObject: keychain forKey: keyID];
        }
    }

    return keychain;
}

И я использую его следующим образом:

KeychainItemWrapper *keychain = [RFCUtils keyChainWrapperForKeyID: keyID];
NSString *firstLaunch = [keychain objectForKey: (__bridge id)(kSecAttrAccount)];
if (firstLaunch == nil)
{
    [keychain setObject: MY_APP_KEY forKey: (__bridge id)(kSecAttrAccount)];
}

(и т.д., аналогичные вызовы в других местах.)

Ответ 6

У меня тоже была эта проблема и она была решена благодаря ответу accepter и дополнительной ссылке на useyourloaf.

Проблема, которая у меня была, была интересной, мне нужно было сохранить только одно значение и решил сохранить ее в поле kSecValueData​​strong > . Это потому, что я видел другие сообщения об использовании брелка и начал свою собственную реализацию, прежде чем перейти к KeychainItemWrapper. Это вызвало следующую проблему: на первом устройстве, которое я тестировал (iPad 1-го поколения), я получал ошибку в writeToKeychain. Я сменил устройство (также ipad 1-го поколения), и он сработает! Вернувшись к первому устройству, он все еще не работал.

Итак, я понял, что раньше я делал что-то неправильно в брелках устройства и не мог легко его отменить. Коды ошибок, которые я получал, были: -25300 на writeToKeychain SecItemCopyMatching (элемент не найден) и сразу после -25299 на SecItemAdd. (дубликат предметов)

С этим вопросом все это имело смысл: устройство имеет ключ, соответствующий любому новому ключу, но KeychainItemWrapper не может его удалить, но ключ не может быть восстановлен. Как только я добавил то же значение в поле kSecAttrAccount, он начал работать.

Короче говоря, для других пользователей, имеющих эту проблему, ваша проблема может выглядеть по-другому, но обратите внимание на детали. Если у вас есть -25300 (элемент не найден), за которым следует -25299 (дубликат предмета); убедитесь, что вы устанавливаете поле, которое определяет уникальность вашего объекта keychain. Если это не работает на одном устройстве, попробуйте другое, если вы можете выделить проблему на одном устройстве. Apple keychain Коды ошибок: http://developer.apple.com/library/ios/#documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG (поиск кодов результатов)

Ответ 7

Я пробовал все решения слушать выше, но ничего не работало для меня. Он работал только на реальном устройстве, но не на симуляторе.

Мое решение запустить его на симуляторе состояло в том, чтобы включить "Share keychain license".

Предоставить доступ к брелокам