以下是负责将值添加到加密存储中的整个函数。这是在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部分,结果相同。
答案 0 :(得分:1)
我猜你不想在SecItemUpdate的查询字典中使用kSecReturnData。无法使用该API将数据返回给您。