这是负责将值添加到加密存储中的整个功能。它在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部分,并得到了相同的结果。
最佳答案
我猜你不想在SecItemUpdate的查询字典中使用kSecReturnData。使用该API无法将数据返回给您。
关于ios - SecItemUpdate()不断返回errSecParam,我不知道为什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26332351/