Es ist möglich, eine NSDictionary
im iPhone
Schlüsselbund zu speichern, mit KeychainItemWrapper
(oder ohne)? Wenn es nicht möglich ist, haben Sie eine andere Lösung?Store NSDictionary in Schlüsselbund
Antwort
Encoding: [dic description]
Decodierung: [dic propertyList]
Ich kann nicht vor morgen ... – malinois
Sie können alles speichern, Sie müssen es nur serialisieren.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
Sie sollten in der Lage sein, diese Daten im Schlüsselbund zu speichern.
Sie müssen richtig die NSDictionary
serialisiert bevor es in den Schlüsselbund zu speichern. Verwendung:
[dic description]
[dic propertyList]
Sie nur NSString
Objekte mit einer NSDictionary
Sammlung enden. Wenn Sie die Datentypen der Objekte pflegen möchten, können Sie NSPropertyListSerialization
verwenden.
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"arbitraryId" accessGroup:nil]
NSString *error;
//The following NSData object may be stored in the Keychain
NSData *dictionaryRep = [NSPropertyListSerialization dataFromPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
[keychain setObject:dictionaryRep forKey:kSecValueData];
//When the NSData object object is retrieved from the Keychain, you convert it back to NSDictionary type
dictionaryRep = [keychain objectForKey:kSecValueData];
NSDictionary *dictionary = [NSPropertyListSerialization propertyListFromData:dictionaryRep mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&error];
if (error) {
NSLog(@"%@", error);
}
Die NSDictionary
durch den zweiten Anruf zu NSPropertyListSerialization
zurückgegeben wird ursprünglichen Datentypen innerhalb der Sammlung NSDictionary
aufrechtzuerhalten.
Ich bearbeitet den Code, um genauer zu reflektieren, wie dies mit KeychainItemWrapper verwendet wird. –
Dies speichert die Daten in 'kSecAttrService', das kein verschlüsseltes Feld ist. Ich glaube, Sie wollten 'kSecValueData' hier verwenden, was die verschlüsselte Payload ist. –
Ihr Code funktioniert aus irgendeinem Grund nicht in ios7. Würde in Betracht ziehen, es zu aktualisieren, um klarer zu sein. Zum Beispiel sagen Sie, dass wir [dic description] verwenden müssen, aber in Ihrem Beispiel gibt es keine dic-Variable. – user798719
Ich fand, dass der Schlüsselbund Wrapper nur Zeichenfolgen will. Nicht einmal NSData. Um ein Wörterbuch zu speichern, müssen Sie das tun, wie Bret vorgeschlagen hat, aber mit einem zusätzlichen Schritt, um die NSData-Serialisierung in eine Zeichenfolge umzuwandeln. Wie folgt aus:
NSString *error;
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:MY_STRING accessGroup:nil];
NSData *dictionaryRep = [NSPropertyListSerialization dataFromPropertyList:dictToSave format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
NSString *xml = [[NSString alloc] initWithBytes:[dictionaryRep bytes] length:[dictionaryRep length] encoding:NSUTF8StringEncoding];
[keychain setObject:xml forKey:(__bridge id)(kSecValueData)];
Lesen sie zurück:
NSError *error;
NSString *xml = [keychain objectForKey:(__bridge id)(kSecValueData)];
if (xml && xml.length) {
NSData *dictionaryRep = [xml dataUsingEncoding:NSUTF8StringEncoding];
dict = [NSPropertyListSerialization propertyListWithData:dictionaryRep options:NSPropertyListImmutable format:nil error:&error];
if (error) {
NSLog(@"%@", error);
}
}
Nicht alle Daten sind gültig UTF-8, so dass dies nicht funktioniert. Die beste Option ist die Codierung nach Base64. – zaph
Es könnte funktionieren; Nach allem beginnt das XML mit der Behauptung der UTF-8-Codierung, xml version = "1.0" encoding = "UTF-8"?>. Ich glaube, dass Apple Daten als Base64 im XML verschlüsselt (Siehe https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/SerializePlist/SerializePlist.html für ein Beispiel). Wenn das fehlschlägt, ist Ihr Fallback zu Base64 eine gute Idee. –
Mit der KeychainItemWrapper
Abhängigkeit erfordert die Bibliothek/Beispielcode zu modifizieren NSData
als verschlüsselten Nutzdaten zu akzeptieren, die nicht zukunftssicher ist. Auch die NSDictionary > NSData > NSString
Konvertierungssequenz zu tun, nur so dass Sie KeychainItemWrapper
verwenden können, ist ineffizient: KeychainItemWrapper
wird Ihre Zeichenfolge trotzdem in NSData
konvertieren, um es zu verschlüsseln.
Hier ist eine vollständige Lösung, die das oben genannte durch die Verwendung der Schlüsselbundbibliothek direkt löst. Es wird als eine Kategorie implementiert, so dass Sie es wie folgt verwendet werden:
// to store your dictionary
[myDict storeToKeychainWithKey:@"myStorageKey"];
// to retrieve it
NSDictionary *myDict = [NSDictionary dictionaryFromKeychainWithKey:@"myStorageKey"];
// to delete it
[myDict deleteFromKeychainWithKey:@"myStorageKey"];
und hier ist die Kategorie:
@implementation NSDictionary (Keychain)
-(void) storeToKeychainWithKey:(NSString *)aKey {
// serialize dict
NSString *error;
NSData *serializedDictionary = [NSPropertyListSerialization dataFromPropertyList:self format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// encrypt in keychain
if(!error) {
// first, delete potential existing entries with this key (it won't auto update)
[self deleteFromKeychainWithKey:aKey];
// setup keychain storage properties
NSDictionary *storageQuery = @{
(id)kSecAttrAccount: aKey,
(id)kSecValueData: serializedDictionary,
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked
};
OSStatus osStatus = SecItemAdd((CFDictionaryRef)storageQuery, nil);
if(osStatus != noErr) {
// do someting with error
}
}
}
+(NSDictionary *) dictionaryFromKeychainWithKey:(NSString *)aKey {
// setup keychain query properties
NSDictionary *readQuery = @{
(id)kSecAttrAccount: aKey,
(id)kSecReturnData: (id)kCFBooleanTrue,
(id)kSecClass: (id)kSecClassGenericPassword
};
NSData *serializedDictionary = nil;
OSStatus osStatus = SecItemCopyMatching((CFDictionaryRef)readQuery, (CFTypeRef *)&serializedDictionary);
if(osStatus == noErr) {
// deserialize dictionary
NSString *error;
NSDictionary *storedDictionary = [NSPropertyListSerialization propertyListFromData:serializedDictionary mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&error];
if(error) {
NSLog(@"%@", error);
}
return storedDictionary;
}
else {
// do something with error
return nil;
}
}
-(void) deleteFromKeychainWithKey:(NSString *)aKey {
// setup keychain query properties
NSDictionary *deletableItemsQuery = @{
(id)kSecAttrAccount: aKey,
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecMatchLimit: (id)kSecMatchLimitAll,
(id)kSecReturnAttributes: (id)kCFBooleanTrue
};
NSArray *itemList = nil;
OSStatus osStatus = SecItemCopyMatching((CFDictionaryRef)deletableItemsQuery, (CFTypeRef *)&itemList);
// each item in the array is a dictionary
for (NSDictionary *item in itemList) {
NSMutableDictionary *deleteQuery = [item mutableCopy];
[deleteQuery setValue:(id)kSecClassGenericPassword forKey:(id)kSecClass];
// do delete
osStatus = SecItemDelete((CFDictionaryRef)deleteQuery);
if(osStatus != noErr) {
// do something with error
}
[deleteQuery release];
}
}
@end
In der Tat, können Sie sie ändern einfach jede Art von serialisierbares Objekt zu speichern, in der Schlüsselbund, nicht nur ein Wörterbuch. Machen Sie einfach eine NSData
Darstellung des Objekts, das Sie speichern möchten.
Einige kleine Änderungen an Dts-Kategorie vorgenommen. In ARC konvertiert und NSKeyedArchiver zum Speichern benutzerdefinierter Objekte verwenden.
@implementation NSDictionary (Keychain)
-(void) storeToKeychainWithKey:(NSString *)aKey {
// serialize dict
NSData *serializedDictionary = [NSKeyedArchiver archivedDataWithRootObject:self];
// encrypt in keychain
// first, delete potential existing entries with this key (it won't auto update)
[self deleteFromKeychainWithKey:aKey];
// setup keychain storage properties
NSDictionary *storageQuery = @{
(__bridge id)kSecAttrAccount: aKey,
(__bridge id)kSecValueData: serializedDictionary,
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenUnlocked
};
OSStatus osStatus = SecItemAdd((__bridge CFDictionaryRef)storageQuery, nil);
if(osStatus != noErr) {
// do someting with error
}
}
+(NSDictionary *) dictionaryFromKeychainWithKey:(NSString *)aKey {
// setup keychain query properties
NSDictionary *readQuery = @{
(__bridge id)kSecAttrAccount: aKey,
(__bridge id)kSecReturnData: (id)kCFBooleanTrue,
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword
};
CFDataRef serializedDictionary = NULL;
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)readQuery, (CFTypeRef *)&serializedDictionary);
if(osStatus == noErr) {
// deserialize dictionary
NSData *data = (__bridge NSData *)serializedDictionary;
NSDictionary *storedDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return storedDictionary;
}
else {
// do something with error
return nil;
}
}
-(void) deleteFromKeychainWithKey:(NSString *)aKey {
// setup keychain query properties
NSDictionary *deletableItemsQuery = @{
(__bridge id)kSecAttrAccount: aKey,
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll,
(__bridge id)kSecReturnAttributes: (id)kCFBooleanTrue
};
CFArrayRef itemList = nil;
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef)deletableItemsQuery, (CFTypeRef *)&itemList);
// each item in the array is a dictionary
NSArray *itemListArray = (__bridge NSArray *)itemList;
for (NSDictionary *item in itemListArray) {
NSMutableDictionary *deleteQuery = [item mutableCopy];
[deleteQuery setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
// do delete
osStatus = SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
if(osStatus != noErr) {
// do something with error
}
}
}
@end
Sieht gut aus. Ich habe deins verwendet, außer dass ich deleteFromKeychainWithKey eine Klassenmethode gemacht habe, so dass ich auch eine allgemeine Bereinigung durchführen konnte, ohne das Wörterbuch zu haben. – Fervus
Großartig !!!!!!!!! –
Funktioniert wie ein Charme. Ich habe die besten Teile aus dem KeychainItemWrapper hinzugefügt. – dogsgod
Ich habe Zugang Gruppenunterstützung und Simulator Sicherheit Amols Lösung:
//
// NSDictionary+SharedKeyChain.h
// LHSharedKeyChain
//
#import <Foundation/Foundation.h>
@interface NSDictionary (SharedKeyChain)
/**
* Returns a previously stored dictionary from the KeyChain.
*
* @param key NSString The name of the dictionary. There can be multiple dictionaries stored in the KeyChain.
* @param accessGroup NSString Access group for shared KeyChains, set to nil for no group.
*
* @return NSDictionary A dictionary that has been stored in the Keychain, nil if no dictionary for the key and accessGroup exist.
*/
+ (NSDictionary *)dictionaryFromKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
/**
* Deletes a previously stored dictionary from the KeyChain.
*
* @param key NSString The name of the dictionary. There can be multiple dictionaries stored in the KeyChain.
* @param accessGroup NSString Access group for shared KeyChains, set to nil for no group.
*/
+ (void)deleteFromKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
/**
* Save dictionary instance to the KeyChain. Any previously existing data with the same key and accessGroup will be overwritten.
*
* @param key NSString The name of the dictionary. There can be multiple dictionaries stored in the KeyChain.
* @param accessGroup NSString Access group for shared KeyChains, set to nil for no group.
*/
- (void)storeToKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
@end
//
// NSDictionary+SharedKeyChain.m
// LHSharedKeyChain
//
#import "NSDictionary+SharedKeyChain.h"
@implementation NSDictionary (SharedKeyChain)
- (void)storeToKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
{
// serialize dict
NSData *serializedDictionary = [NSKeyedArchiver archivedDataWithRootObject:self];
// encrypt in keychain
// first, delete potential existing entries with this key (it won't auto update)
[NSDictionary deleteFromKeychainWithKey:key accessGroup:accessGroup];
// setup keychain storage properties
NSDictionary *storageQuery = @{
(__bridge id)kSecAttrAccount: key,
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
(__bridge id)kSecAttrAccessGroup: accessGroup,
#endif
(__bridge id)kSecValueData: serializedDictionary,
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenUnlocked
};
OSStatus status = SecItemAdd ((__bridge CFDictionaryRef)storageQuery, nil);
if (status != noErr)
{
NSLog (@"%d %@", (int)status, @"Couldn't save to Keychain.");
}
}
+ (NSDictionary *)dictionaryFromKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
{
// setup keychain query properties
NSDictionary *readQuery = @{
(__bridge id)kSecAttrAccount: key,
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
(__bridge id)kSecAttrAccessGroup: accessGroup,
#endif
(__bridge id)kSecReturnData: (id)kCFBooleanTrue,
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword
};
CFDataRef serializedDictionary = NULL;
OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)readQuery, (CFTypeRef *)&serializedDictionary);
if (status == noErr)
{
// deserialize dictionary
NSData *data = (__bridge NSData *)serializedDictionary;
NSDictionary *storedDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
return storedDictionary;
}
else
{
NSLog (@"%d %@", (int)status, @"Couldn't read from Keychain.");
return nil;
}
}
+ (void)deleteFromKeychainWithKey:(NSString *)key accessGroup:(NSString *)accessGroup;
{
// setup keychain query properties
NSDictionary *deletableItemsQuery = @{
(__bridge id)kSecAttrAccount: key,
#if TARGET_IPHONE_SIMULATOR
// Ignore the access group if running on the iPhone simulator.
//
// Apps that are built for the simulator aren't signed, so there's no keychain access group
// for the simulator to check. This means that all apps can see all keychain items when run
// on the simulator.
//
// If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
// simulator will return -25243 (errSecNoAccessForItem).
#else
(__bridge id)kSecAttrAccessGroup: accessGroup,
#endif
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll,
(__bridge id)kSecReturnAttributes: (id)kCFBooleanTrue
};
CFArrayRef itemList = nil;
OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)deletableItemsQuery, (CFTypeRef *)&itemList);
// each item in the array is a dictionary
NSArray *itemListArray = (__bridge NSArray *)itemList;
for (NSDictionary *item in itemListArray)
{
NSMutableDictionary *deleteQuery = [item mutableCopy];
[deleteQuery setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
// do delete
status = SecItemDelete ((__bridge CFDictionaryRef)deleteQuery);
if (status != noErr)
{
NSLog (@"%d %@", (int)status, @"Couldn't delete from Keychain.");
}
}
}
@end
- 1. NSPredate (Nsdictionary + Array + Nsdictionary)
- 2. Swift Schlüsselbund und Bereitstellungsprofile
- 3. App Store Export Compliance - Umfasst dies Daten, die im Schlüsselbund gespeichert sind?
- 4. Vergleich Strings in NSDictionary
- 5. NSDictionary in NSUserDefaults speichern
- 6. NSArray in NSDictionary konvertieren
- 7. NSObject in NSDictionary konvertieren
- 8. konvertieren NSDictionary in NSString
- 9. Fehlender privater Schlüssel iphone Entwickler in Schlüsselbund
- 10. iOS speichern mehrere Passwörter in Schlüsselbund
- 11. Lesen von Schlüsselbund Ergebnisse in errSecItemNotFound 25300
- 12. Keine gültigen iOS Codesignierungsschlüssel in Schlüsselbund gefunden
- 13. OSX-Schlüsselbund ohne Passwort freischalten?
- 14. IKEv2 Passwort-Referenz von Schlüsselbund
- 15. NSDictionary setValue:
- 16. NSDictionary verwenden
- 17. Sortierung NSDictionary
- 18. NSDictionary writeToFile
- 19. Convert NSDictionary in Swift Dictionary
- 20. prüfen Schlüssel vorhanden in NSDictionary
- 21. NSArray in ein NSDictionary einfügen
- 22. hochladen iPhone-Anwendung in den Apple-Store
- 23. Importieren von Schlüsselbund zu Mac über die Befehlszeile aus vorhandenen Schlüsselbund-Datei
- 24. Mac-Code-Signierung: Umgehen Sie die Eingabeaufforderung für privaten Schlüsselbund mit Schlüsselbund Zugriff vom Terminal
- 25. Verwendet meine Anwendung Verschlüsselung (nur Schlüsselbund)?
- 26. Dieses Zertifikat hat einen ungültigen Issuer Schlüsselbund
- 27. NSDictionary zu NSArray?
- 28. NSDictionary Von NSMutableData
- 29. Firebase NSDictionary to Textview
- 30. NSDictionary und Core Data
Ja, aber wenn ich lesen, ich habe einen Verweis auf eine leere NSString. – malinois