import Foundation let groupName = "group.net.defined.mobileNebula" class KeyChain { class func save(key: String, data: Data, managed: Bool) -> Bool { var query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword as String, kSecAttrAccount as String: key, kSecValueData as String: data, kSecAttrAccessGroup as String: groupName, ] if managed { query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock } // Attempt to delete an existing key to allow for an overwrite _ = delete(key: key) return SecItemAdd(query as CFDictionary, nil) == 0 } class func load(key: String) -> Data? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne, kSecAttrAccessGroup as String: groupName, ] var dataTypeRef: AnyObject? let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef) if status == noErr { return dataTypeRef as! Data? } else { return nil } } class func delete(key: String) -> Bool { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword as String, kSecAttrAccount as String: key, kSecAttrAccessGroup as String: groupName, ] return SecItemDelete(query as CFDictionary) == 0 } } extension Data { init(from value: T) { var value = value var data = Data() withUnsafePointer(to: &value) { (ptr: UnsafePointer) in data = Data(buffer: UnsafeBufferPointer(start: ptr, count: 1)) } self.init(data) } func to(type _: T.Type) -> T { return withUnsafeBytes { $0.load(as: T.self) } } }