I am trying to write a wrapper with following a tutorial to getting into Security
module and Keychain
api. The wrapper seems ok but when I trying to set a password into keychain I got an error with status number -50.
import Security
class SecureStore {
private func setupQueryDictionary(forKey key: String) throws -> [CFString: Any] {
guard let keyData = key.data(using: .utf8) else {
print("Error! Cannot convert the key to the expected format")
throw SecureStoreError.invalidContent
}
let query: [CFString: Any] = [kSecClass: kSecClassGenericPassword,
kSecAttrAccount: keyData]
return query
}
func set(entry: String, forKey key: String) throws {
guard !entry.isEmpty && !key.isEmpty else {
print("Cant add an empty string to the keychain")
throw SecureStoreError.queryEmptyWhenSet
}
try removeEntry(forKey: key)
var queryDictionary = try setupQueryDictionary(forKey: key)
queryDictionary[kSecClass] = entry.data(using: .utf8)
let status = SecItemAdd(queryDictionary as CFDictionary, nil)
guard status == errSecSuccess else {
print("status ==> ", status.description)
throw SecureStoreError.failureOnWrite(status)
}
}
func removeEntry(forKey key: String) throws {
guard !key.isEmpty else {
print("key must be valid")
throw SecureStoreError.queryEmptyWhenDelete
}
let queryDictionary = try setupQueryDictionary(forKey: key)
SecItemDelete(queryDictionary as CFDictionary)
}
func entry(forKey key: String) throws -> String? {
guard !key.isEmpty else {
print("key must be valid")
throw SecureStoreError.invalidContent
}
var queryDictionary = try setupQueryDictionary(forKey: key)
queryDictionary[kSecReturnData] = kCFBooleanTrue
queryDictionary[kSecMatchLimit] = kSecMatchLimitOne
var data: AnyObject?
let status = SecItemCopyMatching(queryDictionary as CFDictionary, &data)
guard status == errSecSuccess else {
print("status ==> ", status)
throw SecureStoreError.failureOnRead(status)
}
guard let itemData = data as? Data, let result = String(data: itemData, encoding: .utf8) else {
return nil
}
return result
}
}
enum SecureStoreError: Error {
case invalidContent
case queryEmptyWhenSet
case queryEmptyWhenDelete
case failureOnWrite(OSStatus)
case failureOnRead(OSStatus)
}
extension SecureStoreError: LocalizedError {
public var errorDescription: String? {
switch self {
case .invalidContent:
return NSLocalizedString("Cannot convert to the .utf8 format", comment: "")
case .queryEmptyWhenSet:
return NSLocalizedString("for set(:,:), parameters cannot be empty ", comment: "")
case .queryEmptyWhenDelete:
return NSLocalizedString("for removeEntry(:,:), parameters cannot be empty ", comment: "")
case .failureOnWrite(let status):
return NSLocalizedString("Error when write to keychain item (status.description)", comment: "")
case .failureOnRead(let status):
return NSLocalizedString("Error when read to keychain item (status.description)", comment: "")
}
}
}
Wrapper seems OK to me but I cannot get the real problem behind the error.
I've already done these:
1- Add capabilities in Xcode target and set a group.
2- Tried in the simulator, got the same error
3- I've tried it with the main thread, no effect.
This is my callers:
let security = SecureStore.init()
do {
try security.set(entry: "myPassword12345.12345", forKey: "_passwordForFacebook")
let password = try security.entry(forKey: "_passwordForFacebook")
print("password > ", password )
} catch {
print("error > ", error.localizedDescription)
}
Thanks in advance.
question from:
https://stackoverflow.com/questions/65858055/ios-swift-5-keychain-status-50-with-error-secitemadd 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…