SecItemUpdate()不断返回errSecParam,我无法弄清楚原因

时间:2014-10-13 03:04:30

标签: ios swift ios8 keychain

以下是负责将值添加到加密存储中的整个函数。这是在XCode 6的iPhone6模拟器上运行。

func addOrUpdateGenericPassword(password: String, withService service: String, andAccount account: String, withAccessibility accessibility: SecurityAccessibility) -> ReturnStatus
{
    var sacObject: SecAccessControlRef
    var accessFlag: CFStringRef = kSecAttrAccessibleWhenUnlocked

    switch accessibility
    {
    case SecurityAccessibility.AccessibleAfterFirstUnlock:
        accessFlag = kSecAttrAccessibleAfterFirstUnlock
    case SecurityAccessibility.AccessibleAfterFirstUnlockThisDeviceOnly:
        accessFlag = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
    case SecurityAccessibility.AccessibleWhenUnlocked:
        accessFlag = kSecAttrAccessibleWhenUnlocked
    case SecurityAccessibility.AccessibleWhenUnlockedThisDeviceOnly:
        accessFlag = kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    }

    if touchIDEnabled
    {
        sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessFlag, .USerPresence, nil).takeRetainedValue()
    }
    else
    {
        sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessFlag, nil, nil).takeRetainedValue()
    }

    var dataFromString: NSData = password.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    var secKeys: [AnyObject] = [kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData, kSecAttrAccessControl]
    var secValues: [AnyObject] = [kSecClassGenericPassword, service, account, dataFromString, sacObject]
    var update = NSDictionary(objects: secValues, forKeys: secKeys)

    // attempt to get the value first to determine if it exists
    let (currentValue, rStatus) = getGenericPasswordWith(service, andAccount: account)
    if rStatus == ReturnStatus.errSecSuccess
    {
        // Item already exists, so do an Update
        // We need to build a query for the existing value here instead of using the one we built for updating
        var query = buildQueryValueForLookupWith(service, andAccount: account)
        var status = SecItemUpdate(query, update)
        return getReturnStatusCodeForOSStatusCode(status)
    }
    else if rStatus == ReturnStatus.errSecItemNotFound
    {
        // Item does not exist so add it
        var status = SecItemAdd(update, nil)
        return getReturnStatusCodeForOSStatusCode(status)
    }
    else
    {
        // some other error occured and we dont know what is going on!
        println("Unknown errr occured when checking if item already exists.  Status = \(returnStatusCodeToString(rStatus))")
        return ReturnStatus.errSecUnknownError
    }
}
func buildQueryValueForLookupWith(service: String, andAccount account: String) -> NSDictionary
{
    var secKeys: NSArray = [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData]
    var secValues: [AnyObject] = [kSecClassGenericPassword, service, account, true]
    var query = NSDictionary(objects: secValues, forKeys: secKeys)

    return query
}

该代码位于我编写的KeychainToolkit类中。以下是我收到错误时如何调用它的示例:

var status = keychain.addOrUpdateGenericPassword(value!, withService: "healthBIT.lastSync", andAccount: key, withAccessibility: KeychainToolkit.SecurityAccessibility.AccessibleWhenUnlocked)

在这种情况下,该值已经存在于钥匙串中,上面的代码正确检测到该值,并使用SecItemUpdate()来更新其值。然而,无论我做什么,它总是返回errSecParam,我无法弄清楚我的参数错误在哪里。

我也尝试过完全删除新的iOS8 kSecAttrAccessControl部分,结果相同。

1 个答案:

答案 0 :(得分:1)

我猜你不想在SecItemUpdate的查询字典中使用kSecReturnData。无法使用该API将数据返回给您。