Skip to content

Instantly share code, notes, and snippets.

@jeffrafter
Last active February 6, 2017 20:55
Show Gist options
  • Save jeffrafter/6dc43c3341e12cf4e359092dc8c56f33 to your computer and use it in GitHub Desktop.
Save jeffrafter/6dc43c3341e12cf4e359092dc8c56f33 to your computer and use it in GitHub Desktop.
Keychain generic password management in swift 3
//
// Keychain.swift
// rplcat
//
// Created by Jeffrey Rafter on 2/6/17.
// Copyright © 2017 Rplcat. All rights reserved.
//
import Foundation
import Security
class Keychain {
static func set(_ service: String, account: String, data: String) {
var item: SecKeychainItem? = nil
var status = SecKeychainFindGenericPassword(
nil,
UInt32(service.utf8.count),
service,
UInt32(account.utf8.count),
account,
nil,
nil,
&item)
if status != noErr && status != errSecItemNotFound {
print("Error finding keychain item to modify: \(status), \(SecCopyErrorMessageString(status, nil))")
return
}
if item != nil {
status = SecKeychainItemModifyContent(item!, nil, UInt32(data.utf8.count), data)
} else {
status = SecKeychainAddGenericPassword(
nil,
UInt32(service.utf8.count),
service,
UInt32(account.utf8.count),
account,
UInt32(data.utf8.count),
data,
nil)
}
if status != noErr {
print("Error setting keychain item: \(SecCopyErrorMessageString(status, nil))")
}
}
static func get(_ service: String, account: String) -> String? {
var passwordLength: UInt32 = 0
var password: UnsafeMutableRawPointer? = nil
let status = SecKeychainFindGenericPassword(
nil,
UInt32(service.utf8.count),
service,
UInt32(account.utf8.count),
account,
&passwordLength,
&password,
nil)
if status == errSecSuccess {
guard password != nil else { return nil }
let result = NSString(bytes: password!, length: Int(passwordLength), encoding: String.Encoding.utf8.rawValue) as String?
SecKeychainItemFreeContent(nil, password)
return result
}
return nil
}
static func delete(_ service: String, account: String) {
var item: SecKeychainItem? = nil
var status = SecKeychainFindGenericPassword(
nil,
UInt32(service.utf8.count),
service,
UInt32(account.utf8.count),
account,
nil,
nil,
&item)
if status == errSecItemNotFound {
return
}
if status != noErr {
print("Error finding keychain item to delete: \(SecCopyErrorMessageString(status, nil))")
}
if item != nil {
status = SecKeychainItemDelete(item!)
}
if status != noErr {
print("Error deleting keychain item: \(SecCopyErrorMessageString(status, nil))")
}
}
}
import Foundation
func sample() {
guard let identifier = Bundle.main.bundleIdentifier else { return }
let service = "\(identifier).oauth-token"
let account = "jeffrafter"
Keychain.set(service, account: account, data: "this-is-the-access-token")
print("The token: \(Keychain.get(service, account: account))")
Keychain.delete(service, account: account)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment