Skip to content

Instantly share code, notes, and snippets.

@bnickel
Created February 23, 2015 22:43
Show Gist options
  • Save bnickel/4c1dcdfa0e98f5eec0ee to your computer and use it in GitHub Desktop.
Save bnickel/4c1dcdfa0e98f5eec0ee to your computer and use it in GitHub Desktop.
Application passwords in Swift using function overloading
import Security
import Foundation
// MARK: - Redefining boilerplate code
func SecKeychainOpen(path:String) -> SecKeychainRef? {
var keychain:Unmanaged<SecKeychainRef>? = nil
if SecKeychainOpen((path as NSString).UTF8String, &keychain) == errSecSuccess {
return keychain?.takeRetainedValue()
} else {
return nil
}
}
func SecKeychainCopySearchList() -> [SecKeychainRef]? {
var keychains:Unmanaged<CFArray>? = nil
if SecKeychainCopySearchList(&keychains) == errSecSuccess {
if let keychains:AnyObject = keychains?.takeRetainedValue() {
return map(keychains as [AnyObject], { $0 as SecKeychainRef })
} else {
return nil
}
} else {
return nil
}
}
func SecKeychainFindGenericPassword(keychains:[SecKeychainRef], serviceName:String, accountName:String) -> (String, SecKeychainItemRef)? {
if let keychains = SecKeychainCopySearchList() {
let serviceNameData = (serviceName as NSString).UTF8String
let accountNameData = (accountName as NSString).UTF8String
var passwordLength:UInt32 = 0
var passwordData:UnsafeMutablePointer<Void> = nil
var unmanagedItem:Unmanaged<SecKeychainItemRef>? = nil
if SecKeychainFindGenericPassword(keychains, UInt32(strlen(serviceNameData)), serviceNameData, UInt32(strlen(accountNameData)), accountNameData, &passwordLength, &passwordData, &unmanagedItem) == errSecSuccess {
let password = NSString(bytes: UnsafePointer(passwordData), length: Int(passwordLength), encoding: NSUTF8StringEncoding)!
SecKeychainItemFreeContent(nil, passwordData)
return (password, unmanagedItem!.takeRetainedValue())
} else {
return nil
}
} else {
return nil
}
}
func SecKeychainItemModifyData(item:SecKeychainItemRef, password:String) -> Bool {
let passwordData = (password as NSString).UTF8String
return SecKeychainItemModifyAttributesAndData(item, nil, UInt32(strlen(passwordData)), passwordData) == errSecSuccess
}
func SecKeychainAddGenericPassword(keychain:SecKeychainRef, serviceName:String, accountName:String, password:String) -> Bool {
let serviceNameData = (serviceName as NSString).UTF8String
let accountNameData = (accountName as NSString).UTF8String
let passwordData = (password as NSString).UTF8String
return SecKeychainAddGenericPassword(keychain, UInt32(strlen(serviceNameData)), serviceNameData, UInt32(strlen(accountNameData)), accountNameData, UInt32(strlen(passwordData)), passwordData, nil) == errSecSuccess
}
// MARK: - The fun begins here
if let keychain = SecKeychainOpen("login.keychain") {
if let (_, item) = SecKeychainFindGenericPassword([keychain], "Setec Astronomy", "Password") {
SecKeychainItemModifyData(item, "Modified")
} else {
SecKeychainAddGenericPassword(keychain, "Setec Astronomy", "Password", "Initial")
}
}
if let (password, item) = SecKeychainFindGenericPassword(SecKeychainCopySearchList()!, "Setec Astronomy", "Password") {
println("The secret word is is \(password)")
if password == "Modified" {
println("Too many secrets!")
SecKeychainItemDelete(item)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment