web-dev-qa-db-ja.com

iPhone SDKでキーチェーンに保存中にエラーが発生しました

私は キーチェーン用のAppleラッパー を使用し、その上にアイテムを保存しようとします(シミュレーターで実行、iOS 4.1)。

これまでにキーチェーンを使ったことがありません。

私はこのエラーを受け取ります:

キーチェーンアイテムを追加できませんでした。エラー-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"}
}
29
mamcx

これは数か月前のものであることはわかっていますが、同じ問題が発生しただけで苦痛だったので、共有したいと思いました。私はこの行を追加してそれを解決しました:

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

私はこのブログエントリが非常に役に立ったと感じました。「データベースの用語では、2つの属性kSecAttrAccount、kSecAttrServiceの一意のインデックスであると考えることができます。これらの2つの属性の組み合わせは、キーチェーンのエントリごとに一意である必要があります。」 ( 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];   
60
Dwayne Driskill

ドキュメント によると、取得するエラー-25299は "errSecDuplicateItem"です。これは、追加しようとしているアイテムが既に存在することを意味します。 KeychainItemWrapperのリンクされたコードを見ると、SecItemCopyMatching呼び出しがerrSecItemNotFound(–25300)以外のエラーで失敗していると思います。

9
Anomie

Buzz Andersenによる SFHFKeychainUtils を使用すると、キーチェーンを使用して値を簡単に保存および取得できます。

  1. プロジェクトSFHFKeychainUtils.hおよび.mをダウンロードしてコピーします。
  2. Security.frameworkをフレームワークフォルダーに追加する
  3. これらのファイルがターゲットに追加されていることを確認してください
  4. 使用したい場所に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];
6
matteodv

キーホルダーは完全な痛みです。代わりにラッパーとして Buzz AndersenのSTUtils ライブラリを使用する必要があります。それはあなたの人生を大幅に容易にします。私はそれについて問題を経験したことがありません。

3
Andy McSherry

私にとっての解決策は、KeychainItemWrapper「シングルトン」を作成し、それをアプリ全体で使用することでした。 (実際、私の場合、私はKeychainItemWrapper- sでいっぱいのシングルトンディクショナリを持っていました。

これにより、「このアイテムはキーチェーンに存在しますか?いいえ?次に追加します。おっと!NSAssert()が既にアイテムを追加しようとしています。存在します(エラー-25299)」

確かではありませんが、問題はキーチェーンの同期に関係しているのではないかと思います。私は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)];
}

(他の場所での同様の呼び出しなど)

1
Olie

上記のすべてのソリューションを試してみましたが、何もうまくいきませんでした。実際のデバイスでのみ機能し、シミュレータでは機能しませんでした。

それをシミュレーターで実行するための私の解決策は、「共有キーチェーン資格」をオンにすることでした。

共有キーチェーン資格

0
Seeler99

私にもこの問題があり、アクセプターの回答とuseyourloafへの追加リンクのおかげで解決しました。

私が抱えていた問題は興味深いものでした。値を1つだけ保存する必要があり、それをフィールドkSecValueDataに格納することにしました。これは、Keychainの使用に関する他の投稿を見て、KeychainItemWrapperに進む前に独自の実装を開始したためです。これにより、次の問題が発生しました。最初にテストしたデバイス(iPadの第1世代)で、writeToKeychainでエラーが発生しました。デバイス(iPad 1st gen)を変更したところ、うまくいきました!最初のデバイスに戻りましたが、まだ機能しませんでした。

そのため、その時点で、デバイスのキーチェーンで以前に何か問題があり、簡単に元に戻すことができないことを知っていました。私が取得していたエラーコードは、writeToKeychainのSecItemCopyMatching(アイテムが見つからない)で-25300、SecItemAddで-25299の直後です。 (アイテムの複製)

この質問では、これはすべて理にかなっています。デバイスにはany新しいキーと一致するキーがありますが、KeychainItemWrapperはそれを削除できませんが、キーを取得できません。同じ値をフィールドkSecAttrAccountに追加するとすぐに、機能し始めました。

一言で言えば、この問題を抱えている他のユーザーにとって、あなたの問題は異なって見えるかもしれませんが、詳細に注意を払います。 -25300(アイテムが見つからない)に続いて-25299(アイテムが重複している)の場合。キーチェーンアイテムの一意性を定義するフィールドを設定していることを確認してください。 1つのデバイスで機能しない場合は、問題を1つのデバイスに特定できる可能性がある場合は、別のデバイスを試してください。 Apple keychainエラーコード: http://developer.Apple.com/library/ios/#documentation/Security/Reference/keychainservices/Reference/reference.html#//Apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG (結果コードを検索)

0
Kuoni