2010-11-29 167 views
27

保存鑰匙鏈時出錯使用Apple wraper for the keychain,並嘗試保存一個項目(在模擬器中運行,ios 4.1)。使用iphone sdk

我還沒有使用鑰匙扣的經驗。

我得到這個錯誤:

Couldn't add the Keychain Item. Error - 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"} 
} 
+0

你解決了這個問題嗎? – 2011-04-07 20:28:31

+0

我被這個困住了,所以我認爲賞金是個好主意。相同的errorCode,但iOS4.3但我想這是一個PEBKAC問題,並沒有與sdk的問題。 – 2011-04-07 20:37:56

+0

當我在` - (void)resetKeychainItem`中添加`[keychainItemData setObject:@「」forKey:(__ bridge id)kSecAttrService];`時,發生了此問題。然後,當我在閱讀下面的user379075的答案時,它響起了一個鐘聲,如果你「重置」它,你還必須設置它和v.v. – mrd3650 2012-04-13 15:52:37

回答

59

我知道這是從幾個月前,但我只是有同樣的問題,這是痛苦的,所以我想我會分享。我解決它通過加入這一行:

[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]; 
4

鑰匙扣是一種徹底的痛苦。您應該使用Buzz Andersen's STUtils庫作爲包裝。它會讓你的生活變得更容易。我從來沒有遇到過問題。

+2

這個github項目現在已被棄用;作者建議https://github.com/ldandersen/STUtils/blob/master/Security作爲替代。 – 2012-10-11 10:25:39

9

根據the documentation,您收到的錯誤-25299是「errSecDuplicateItem」,表示您嘗試添加的項目已經存在。查看KeychainItemWrapper的鏈接代碼,我猜測SecItemCopyMatching調用失敗,併發生errSecItemNotFound(-25300)以外的錯誤。

6

您可以使用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]; 
+0

在這種情況下kStoredData是什麼?試圖執行此操作時出現構建錯誤。 – 2011-04-21 23:34:30

0

我也有這個問題,解決它由於受主的答案和附加鏈接useyourloaf。

我的問題很有趣,我需要只保存一個值,並決定將其存儲在該領域kSecValueData,那是因爲我看到了其他關於使用鑰匙串並開始我自己的實現的帖子b在轉向KeychainItemWrapper之前。 這導致了以下問題:在我測試的第一個設備上(iPad第一代),我在writeToKeychain中出現錯誤。我改變了設備(也是ipad第一代),它的工作!回到第一個設備,它仍然沒有工作。

所以,我知道我之前在設備的鑰匙串中做了一些錯誤,無法輕易恢復。我得到的錯誤代碼是:writeToKeychain的SecItemCopyMatching(找不到項目)-25300和SecItemAdd的-25299之後。 (項目重複)

帶着這樣的疑問,這一切都讓感覺:該設備具有匹配的關鍵任何新的密鑰,但KeychainItemWrapper不能刪除,但密鑰不能被檢索。 只要我將相同的值添加到字段kSecAttrAccount,它就開始工作。長話短說,對於有這個問題的其他用戶,您的問題可能看起來不同,但要注意細節。如果您有-25300(找不到項目),然後是-25299(項目重複);確保你正在設置一個字段來定義鑰匙串項目的唯一性。如果它無法在一臺設備上工作,請嘗試另一臺設備,如果可以,您可以將問題隔離到一臺設備上。 蘋果鑰匙扣錯誤代碼:http://developer.apple.com/library/ios/#documentation/Security/Reference/keychainservices/Reference/reference.html#//apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG(搜索結果代碼)

1

對我來說,解決辦法是,我創建了一個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)]; 
} 

0

我試過所有的解決方案在上面聽,但沒有爲我工作。它只在一個實際的設備上工作,但不在模擬器上。

我在模擬器上運行它的解決方案是打開「共享鑰匙串權利」。

Share Keychain entitlement