J'utilise l'enveloppe Apple pour le trousseau et essaie d'enregistrer un élément dessus (fonctionnant dans un simulateur, ios 4.1).
Je n'ai pas d'expérience avec le trousseau avant.
Je reçois cette erreur:
Impossible d'ajouter l'élément de trousseau. Erreur - 25299
Dans KeychainItemWrapper.m, ligne 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." );
Voici comment je fais la sauvegarde:
- (void) saveKey:(NSString *)key value:(NSString *)value {
KeychainItemWrapper *keyItem = [[KeychainItemWrapper alloc] initWithIdentifier:key accessGroup:nil];
[keyItem setObject:value forKey:(id)kSecValueData];
[keyItem release];
}
Et ce sont les valeurs que l’API essaie de sauvegarder:
<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"}
}
Je sais que cela remonte à plusieurs mois auparavant, mais j'avais juste le même problème et c'était douloureux alors j'ai pensé partager. Je l'ai résolu en ajoutant cette ligne:
[self.keychainItemWrapper setObject:@"MY_APP_CREDENTIALS" forKey:(id)kSecAttrService];
//@"MY_APP_CREDENTIALS" can be any string.
J'ai trouvé cette entrée de blog très utile: "En termes de base de données, on pourrait penser qu'il s'agit d'un index unique sur les deux attributs kSecAttrAccount, kSecAttrService nécessitant que la combinaison de ces deux attributs soit unique pour chaque entrée du trousseau." (from http://useyourloaf.com/blog/2010/4/28/keychain-duplicate-item-when-adding-password.html ).
De plus, dans l'exemple de projet d'Apple utilisant ce code, ils instancient KeychainItemWrapper dans le délégué de l'application. Je ne sais pas si c'est nécessaire, mais j'aime suivre leurs exemples aussi étroitement que possible:
- (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];
}
Je pense que c'est un bogue dans le code wrapper. La logique dit en gros "Cette entrée existe-t-elle déjà? Non, ce n'est pas le cas. OK, je vais l'ajouter. Oups, vous ne pouvez pas l'ajouter car elle est déjà là."
Vous devrez peut-être également définir kSecAttrAccount; Je ne l'ai jamais essayé sans définir également cette valeur car il est destiné à enregistrer le nom d'utilisateur associé au mot de passe:
[self.wrapper setObject:txtUserName.text forKey:(id)kSecAttrAccount];
Selon la documentation , l'erreur -25299 que vous obtenez est "errSecDuplicateItem", ce qui signifie que l'élément que vous essayez d'ajouter existe déjà. En regardant le code lié à KeychainItemWrapper, je suppose que l'appel SecItemCopyMatching
échoue avec une erreur autre que errSecItemNotFound (–25300).
Vous pouvez facilement stocker et récupérer des valeurs avec un trousseau en utilisant SFHFKeychainUtils de Buzz Andersen.
Ceci est un petit exemple sur la façon d'utiliser cette bibliothèque.
// 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];
Le trousseau est une douleur totale. Vous devriez utiliser STUtils library de Buzz Andersen à la place comme wrapper. Cela vous facilitera considérablement la vie. Je n'ai jamais eu de problème avec ça.
Pour moi, la solution a été de créer un "singleton" KeychainItemWrapper
et de l’utiliser dans l’application. (En fait, dans mon cas, j’avais un dictionnaire singleton plein de KeychainItemWrapper
- s, parce que j’en utilise plus d’un.)
Cela a résolu le problème suivant: j'arrivais à un chemin de code qui disait effectivement "cet élément existe-t-il sur le trousseau? Non? Ajoutez-le ensuite. Whoops! NSAssert()
j'essaie d'ajouter un élément déjà existant (Erreur -25299) "
Bien que je ne sois pas certain, je pense que le problème est lié à la synchronisation du trousseau. J'ai eu des problèmes similaires avec NSUserDefaults
, lorsque j'écris à NSUD, puis, ailleurs dans le code, récupère la standardUserDefaults
et la lit, et la mise à jour n'a pas encore eu lieu (parce que je n'ai pas encore [ud synchronize]
.).
Dans le code, ma routine ressemble à ceci:
+ (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;
}
Et je l'utilise comme ça:
KeychainItemWrapper *keychain = [RFCUtils keyChainWrapperForKeyID: keyID];
NSString *firstLaunch = [keychain objectForKey: (__bridge id)(kSecAttrAccount)];
if (firstLaunch == nil)
{
[keychain setObject: MY_APP_KEY forKey: (__bridge id)(kSecAttrAccount)];
}
(etc., appels similaires ailleurs.)
J'ai essayé toutes les solutions d'écoute ci-dessus mais rien n'a fonctionné pour moi. Cela ne fonctionnait que sur un appareil réel, mais pas sur le simulateur.
Ma solution pour l’exécuter sur le simulateur consistait à activer le "droit au trousseau de partage".
J'ai eu ce problème aussi et je l'ai résolu grâce à la réponse d'accepter et au lien supplémentaire à useyourloaf.
Le problème que j’avais était intéressant, je n’avais besoin de sauvegarder qu’une valeur et j’ai décidé de la stocker dans le champ kSecValueData. En effet, j’ai vu d’autres publications sur l’utilisation du trousseau et commencé ma propre implémentation avant de me tourner vers KeychainItemWrapper. Cela provoquait le problème suivant: Sur le premier périphérique que je testais (iPad 1ère génération), une erreur se produisait dans writeToKeychain. J'ai changé d'appareil (également ipad 1ère génération) et cela a fonctionné! De retour au premier appareil, cela ne fonctionnait toujours pas.
Donc, je savais que j'avais déjà fait quelque chose de mal avec le trousseau de l'appareil et que je ne pouvais pas le retourner facilement. Les codes d'erreur que j'obtenais sont les suivants: -25300 sur SecItemCopyMatching de writeToKeychain (élément introuvable) et juste après -25299 sur SecItemAdd. (article en double)
Avec cette question, tout cela a du sens: le périphérique a une clé qui correspond à toute nouvelle clé, mais KeychainItemWrapper ne peut pas la supprimer mais la clé ne peut pas être récupérée . Dès que j'ai ajouté la même valeur à le champ kSecAttrAccount, il a commencé à fonctionner.
En bref, pour les autres utilisateurs ayant ce problème, votre problème peut paraître différent, mais faites attention aux détails. Si vous avez -25300 (élément non trouvé) suivi de -25299 (élément dupliqué); assurez-vous que vous définissez un champ qui définit le caractère unique de votre élément de trousseau. Si cela ne fonctionne pas sur un périphérique, essayez-en un autre si vous le pouvez. Vous pourrez peut-être isoler le problème sur un périphérique . Apple keychain Codes d'erreur: http://developer.Apple.com/library/ios /#documentation/Security/Reference/keychainservices/Reference/reference.html#//Apple_ref/doc/uid/TP30000898-CH5g-CJBEABHG (recherche de codes de résultat)