Skip to content

Instantly share code, notes, and snippets.

@alexbosworth
Last active January 5, 2021 08:26
Show Gist options
  • Save alexbosworth/1ff29728e7599e7a9d65 to your computer and use it in GitHub Desktop.
Save alexbosworth/1ff29728e7599e7a9d65 to your computer and use it in GitHub Desktop.
Swift Keychain Class
import UIKit
import Security
let serviceIdentifier = "com.company"
let accessGroup = "com.company.app"
let kSecClassValue = kSecClass as NSString
let kSecAttrAccountValue = kSecAttrAccount as NSString
let kSecValueDataValue = kSecValueData as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword as NSString
let kSecAttrServiceValue = kSecAttrService as NSString
let kSecMatchLimitValue = kSecMatchLimit as NSString
let kSecReturnDataValue = kSecReturnData as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne as NSString
class KeychainService: NSObject {
class func setString(value: NSString, forKey: String) {
self.save(serviceIdentifier, key: forKey, data: value)
}
class func stringForKey(key: String) -> NSString? {
var token = self.load(serviceIdentifier, key: key)
return token
}
class func removeItemForKey(key: String) {
self.save(serviceIdentifier, key: key, data: "")
}
class func save(service: NSString, key: String, data: NSString) {
var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
// Instantiate a new default keychain query
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionaryRef)
if data == "" { return }
// Add the new keychain item
var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
}
class func load(service: NSString, key: String) -> NSString? {
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, key, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain items
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
let opaque = dataTypeRef?.toOpaque()
var contentsOfKeychain: NSString?
if let op = opaque? {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
// Convert the data retrieved from the keychain into a string
contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
} else {
return nil
}
return contentsOfKeychain
}
}
@alexbosworth
Copy link
Author

OK fair warning, the code above only works if the Swift Compiler - Code Generation level is set at "none", not at "Fastest" which is the default

Make sure to test the code against your release scheme

@superarts
Copy link

I can confirm the issue @alexbosworth mentioned exists in xcode 6.1 as well. Nice catch dude!

@deniskr
Copy link

deniskr commented Dec 3, 2014

I have developed a Swift wrapper over the entire C Keychain API. See if it can be useful for you: https://github.com/deniskr/KeychainSwiftAPI

@alexbosworth
Copy link
Author

Another note about this, if you are using this code and you want the keys to be accessible from the lockscreen, like in a background fetch, you need to adjust the kSecAttrAccessible value

@chiliec
Copy link

chiliec commented Sep 28, 2015

up! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment