Skip to content

Instantly share code, notes, and snippets.

@desmondmc
Created March 28, 2017 08:47
Show Gist options
  • Save desmondmc/bde2f00cac34488722c330df75aca7dc to your computer and use it in GitHub Desktop.
Save desmondmc/bde2f00cac34488722c330df75aca7dc to your computer and use it in GitHub Desktop.
Simple String Key Value Access to iOS Keychain
import Foundation
import Security
private let SecClass: String = kSecClass as String
private let SecAttrService: String = kSecAttrService as String
private let SecAttrAccessible: String = kSecAttrAccessible as String
private let SecAttrGeneric: String = kSecAttrGeneric as String
private let SecAttrAccount: String = kSecAttrAccount as String
private let SecMatchLimit: String = kSecMatchLimit as String
private let SecReturnData: String = kSecReturnData as String
private let SecValueData: String! = kSecValueData as String
private let KeyChainAccessibility = kSecAttrAccessibleWhenUnlocked
class Keychain {
@discardableResult static func save(key: String, value: String) -> Bool {
var query = basicKeychainQuery(with: key)
let encodedValue = value.data(using: .utf8)!
query[SecValueData] = encodedValue
let status: OSStatus = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
return true
} else if status == errSecDuplicateItem {
return update(key: key, value: value)
} else {
return false
}
}
static func load(key: String) -> String? {
guard let data = keychainData(with: key) else { return nil }
return String(data: data, encoding: .utf8) as String?
}
@discardableResult static func delete(key: String) -> Bool {
let query = basicKeychainQuery(with: key)
let status = SecItemDelete(query as CFDictionary)
if status == errSecSuccess {
return true
} else {
return false
}
}
}
private func keychainData(with key: String) -> Data? {
var query = basicKeychainQuery(with: key)
query[SecMatchLimit] = kSecMatchLimitOne
query[SecReturnData] = kCFBooleanTrue
var result: AnyObject?
let status = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
if status == noErr {
return result as? Data
} else {
return nil
}
}
private func update(key: String, value: String) -> Bool {
let query = basicKeychainQuery(with: key)
let encodedValue = value.data(using: .utf8)!
let update = [SecValueData: encodedValue]
let status = SecItemUpdate(query as CFDictionary, update as CFDictionary)
if status == errSecSuccess {
return true
} else {
return false
}
}
private func basicKeychainQuery(with key: String) -> [String:Any] {
let encodedKey = key.data(using: .utf8)!
return [SecClass: kSecClassGenericPassword,
SecAttrService: Bundle.main.bundleIdentifier!,
SecAttrAccessible: KeyChainAccessibility,
SecAttrGeneric: encodedKey,
SecAttrAccount: encodedKey]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment