【问题标题】:iOS Keychain: NSDate vs NSStringiOS 钥匙串:NSDate 与 NSString
【发布时间】:2017-01-17 00:12:21
【问题描述】:

我想知道在准备Keychain item 时,您什么时候将NSString 转换为NSData

例如: 在本教程提供的代码中 http://hayageek.com/ios-keychain-tutorial/

它声明如下:

[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];

然而,在 David Thiel 的《iOS 应用程序安全》一书中使用了以下内容:

[dict setObject:@"dthiel" forKey:(__bridge id)kSecAttrAccount];

所以,我很困惑,我什么时候需要将NSString 转换为NSData 我怎么知道?

谢谢。

【问题讨论】:

    标签: ios objective-c nsstring


    【解决方案1】:

    您必须将值编码为 NSData。

    例如:

    #define KeychainIdentifier @"keychain.access.identifier"
    
    - (void)setKeyValue:(NSString *)key value:(NSString *)value {
        //The keychain identifier must be encoded as `NSData`.
        NSData *keychainItemID = [KeychainIdentifier dataUsingEncoding:NSUTF8StringEncoding];
    
    
        //Build the query. We need to QUERY the keychain and check if the item exists.
        //If it does, we will NOT be adding the item in the keychain. Note: You can "overwrite" the data if you want but for this example, I'm going to keep it simple and NOT do that.
        //For this example, the item stored is a "GenericPassword".
        //We will query for the existence of "one" item.
        //This query will only return attributes because we are not FETCHING from the keychain. Just "checking/querying".
        //Finally, the item is accessible when the device is unlocked.
        NSMutableDictionary *query = [@{
                                        (id)kSecClass             : (id)kSecClassGenericPassword,
                                        (id)kSecAttrGeneric       : keychainItemID,
                                        (id)kSecMatchLimit        : (id)kSecMatchLimitOne,
                                        (id)kSecReturnAttributes  : (id)kCFBooleanTrue,
                                        (id)kSecAttrAccessible    : (id)kSecAttrAccessibleWhenUnlocked,
                                        (id)kSecAttrAccount       : key
                                        } mutableCopy];
    
    
        //Query the keychain and get all the item's attributes.
        CFMutableDictionaryRef result = nil;
        OSStatus error = SecItemCopyMatching((__bridge CFMutableDictionaryRef)query, (CFTypeRef *)&result);
    
        if (error == errSecItemNotFound) {
            //Item does not exist, add it to the keychain.
            //To do that, we turn our query into an "INSERT".
            //That means we need to remove the "return" key because we are no longer fetching/querying and returning attributes. We also have to remove the match limit.
            //We also remove the match limit.
            [query removeObjectForKey:(id)kSecMatchLimit];
            [query removeObjectForKey:(id)kSecReturnAttributes];
    
            //Now we encode the data to be stored in the keychain and then we submit our "INSERT" to the keychain. This will add the item in the keychain.
            [query setObject:[value dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];
    
            error = SecItemAdd((__bridge CFMutableDictionaryRef)query, nil);
    
            if (error == noErr) {
                //Success.
            }
            else {
                //Something went wrong.
            }
        }
        else {
            //Item already exists.
        }
    }
    

    【讨论】:

    • 感谢您的样品。只是想知道,是否有必要拥有 kSecAttrGeneric?因为我记得kSecClassGenericPassword只需要kSecClasskSecAttrAccountkSecAttrServer来识别,这样对吗?
    • @KwokPingLau;这不是必要的。它是可选的。如您在此处看到的:stackoverflow.com/questions/11614047/… kSecClassGenericPassword 的主键是 kSecAttrAccount and kSecAttrService
    猜你喜欢
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多