Helper functions for saving text in Keychain securely for iOS, OS X, tvOS and watchOS.

Overview

Helper functions for storing text in Keychain for iOS, macOS, tvOS and WatchOS

Carthage compatible CocoaPods Version Swift Package Manager compatible License Platform

This is a collection of helper functions for saving text and data in the Keychain. As you probably noticed Apple's keychain API is a bit verbose. This library was designed to provide shorter syntax for accomplishing a simple task: reading/writing text values for specified keys:

let keychain = KeychainSwift()
keychain.set("hello world", forKey: "my key")
keychain.get("my key")

The Keychain library includes the following features:

What's Keychain?

Keychain is a secure storage. You can store all kind of sensitive data in it: user passwords, credit card numbers, secret tokens etc. Once stored in Keychain this information is only available to your app, other apps can't see it. Besides that, operating system makes sure this information is kept and processed securely. For example, text stored in Keychain can not be extracted from iPhone backup or from its file system. Apple recommends storing only small amount of data in the Keychain. If you need to secure something big you can encrypt it manually, save to a file and store the key in the Keychain.

Setup

There are four ways you can add KeychainSwift to your project.

Add source (iOS 7+)

Simply add KeychainSwiftDistrib.swift file into your Xcode project.

Setup with Carthage (iOS 8+)

Alternatively, add github "evgenyneu/keychain-swift" ~> 19.0 to your Cartfile and run carthage update.

Setup with CocoaPods (iOS 8+)

If you are using CocoaPods add this text to your Podfile and run pod install.

use_frameworks!
target 'Your target name'
pod 'KeychainSwift', '~> 19.0'

Setup with Swift Package Manager

Legacy Swift versions

Setup a previous version of the library if you use an older version of Swift.

Usage

Add import KeychainSwift to your source code unless you used the file setup method.

String values

let keychain = KeychainSwift()
keychain.set("hello world", forKey: "my key")
keychain.get("my key")

Boolean values

let keychain = KeychainSwift()
keychain.set(true, forKey: "my key")
keychain.getBool("my key")

Data values

let keychain = KeychainSwift()
keychain.set(dataObject, forKey: "my key")
keychain.getData("my key")

Removing keys from Keychain

keychain.delete("my key") // Remove single key
keychain.clear() // Delete everything from app's Keychain. Does not work on macOS.

Return all keys

let keychain = KeychainSwift()
keychain.allKeys // Returns the names of all keys

Advanced options

Keychain item access

Use withAccess parameter to specify the security level of the keychain storage. By default the .accessibleWhenUnlocked option is used. It is one of the most restrictive options and provides good data protection.

let keychain = KeychainSwift()
keychain.set("Hello world", forKey: "key 1", withAccess: .accessibleWhenUnlocked)

You can use .accessibleAfterFirstUnlock if you need your app to access the keychain item while in the background. Note that it is less secure than the .accessibleWhenUnlocked option.

See the list of all available access options.

Synchronizing keychain items with other devices

Set synchronizable property to true to enable keychain items synchronization across user's multiple devices. The synchronization will work for users who have the "Keychain" enabled in the iCloud settings on their devices.

Setting synchronizable property to true will add the item to other devices with the set method and obtain synchronizable items with the get command. Deleting a synchronizable item will remove it from all devices.

Note that you do NOT need to enable iCloud or Keychain Sharing capabilities in your app's target for this feature to work.

// First device
let keychain = KeychainSwift()
keychain.synchronizable = true
keychain.set("hello world", forKey: "my key")

// Second device
let keychain = KeychainSwift()
keychain.synchronizable = true
keychain.get("my key") // Returns "hello world"

We could not get the Keychain synchronization work on macOS.

Sharing keychain items with other apps

In order to share keychain items between apps on the same device they need to have common Keychain Groups registered in Capabilities > Keychain Sharing settings. This tutorial shows how to set it up.

Use accessGroup property to access shared keychain items. In the following example we specify an access group "CS671JRA62.com.myapp.KeychainGroup" that will be used to set, get and delete an item "my key".

let keychain = KeychainSwift()
keychain.accessGroup = "CS671JRA62.com.myapp.KeychainGroup" // Use your own access goup

keychain.set("hello world", forKey: "my key")
keychain.get("my key")
keychain.delete("my key")
keychain.clear()

Note: there is no way of sharing a keychain item between the watchOS 2.0 and its paired device: https://forums.developer.apple.com/thread/5938

Setting key prefix

One can pass a keyPrefix argument when initializing a KeychainSwift object. The string passed in keyPrefix argument will be used as a prefix to all the keys used in set, get, getData and delete methods. Adding a prefix to the keychain keys can be useful in unit tests. This prevents the tests from changing the Keychain keys that are used when the app is launched manually.

Note that clear method still clears everything from the Keychain regardless of the prefix used.

let keychain = KeychainSwift(keyPrefix: "myTestKey_")
keychain.set("hello world", forKey: "hello")
// Value will be stored under "myTestKey_hello" key

Check if operation was successful

One can verify if set, delete and clear methods finished successfully by checking their return values. Those methods return true on success and false on error.

if keychain.set("hello world", forKey: "my key") {
  // Keychain item is saved successfully
} else {
  // Report error
}

To get a specific failure reason use the lastResultCode property containing result code for the last operation. See Keychain Result Codes.

keychain.set("hello world", forKey: "my key")
if keychain.lastResultCode != noErr { /* Report error */ }

Returning data as reference

Use the asReference: true parameter to return the data as reference, which is needed for NEVPNProtocol.

let keychain = KeychainSwift()
keychain.set(dataObject, forKey: "my key")
keychain.getData("my key", asReference: true)

Using KeychainSwift from Objective-C

This manual describes how to use KeychainSwift in Objective-C apps.

❗️ Known critical issue - call to action ❗️

It has been reported that the library sometimes returns nil instead of the stored Keychain value. It may be connected with the Keychain issue reported on Apple developer forums. The issue is random and hard to reproduce. If you experienced this problem feel free to create an issue and share your story, so we can find solutions.

Video tutorial

Thanks to Alex Nagy from rebeloper.com for creating this two-part video tutorial.

Keychain Swift video tutorial

Demo app

Keychain Swift demo app

Alternative solutions

Here are some other Keychain libraries.

Thanks 👍

  • The code is based on this example: https://gist.github.com/s-aska/e7ad24175fb7b04f78e7
  • Thanks to diogoguimaraes for adding Swift Package Manager setup option.
  • Thanks to glyuck for taming booleans.
  • Thanks to pepibumur for adding macOS, watchOS and tvOS support.
  • Thanks to ezura for iOS 7 support.
  • Thanks to mikaoj for adding keychain synchronization.
  • Thanks to tcirwin for adding Swift 3.0 support.
  • Thanks to Tulleb for adding Xcode 8 beta 6 support.
  • Thanks to CraigSiemens for adding Swift 3.1 support.
  • Thanks to maxkramerbcgdv for fixing Package Manager setup in Xcode 8.2.
  • Thanks to elikohen for fixing concurrency issues.
  • Thanks to beny for adding Swift 4.2 support.
  • Thanks to xuaninbox for fixing watchOS deployment target for Xcode 10.
  • Thanks to schayes04 for adding Swift 5.0 support.
  • Thanks to mediym41 for adding ability to return data as reference.
  • Thanks to AnthonyOliveri for adding ability to run unit tests from Swift Package Manager.
  • Thanks to philippec for removing deprecated access options.
  • Thanks to lucasmpaim for adding ability to return the names of all keys.

Feedback is welcome

If you notice any issue, got stuck or just want to chat feel free to create an issue. We will be happy to help you.

License

Keychain Swift is released under the MIT License.

Comments
  • WatchOS 2

    WatchOS 2

    I'm wondering if setting a keychain key on iOS and trying to access it on Apple Watch is possible using this library. With WatchOS 2, Apple doesn't allow keychain sharing (using the capabilities but as far as I understand, the Apple Watch app has access to the keychain natively.

    Can you elaborate on this?

    opened by acegreen 19
  • Cannot make it to work on xcode 8 and swift 2.3 . platform tvOS

    Cannot make it to work on xcode 8 and swift 2.3 . platform tvOS

    I am using legacy framework and have everything setted up. The shared keychain is turned on, access group is setted to AppId + "." + groupIdentifier. I am using following method to write some data and it always print error

            if !keychainSwift.set(data, forKey: T.PersistorKey) {
                print("error occured")
            }
    
    opened by BProg 10
  • Cant store keys

    Cant store keys

    Hello i am trying to use the library but its not storying the keys i have this:

    
    let keychain = KeychainSwift()
                keychain.accessGroup = MyAccessGroup
                keychain.synchronizable = true
                if (keychain.set(token, forKey: "user token", withAccess: KeychainSwiftAccessOptions.AccessibleWhenUnlocked)) {
                    print(keychain.get("user token"))
                } else {
                    print("Error")
                }
    
    

    it goes to the print Error, is there somethign i have to enable in the project?

    opened by antonioreyna 10
  • carthage compile hangs

    carthage compile hangs

    Hi,

    trying to build with carthage (carthage update with github "marketplacer/keychain-swift" ~> 7.0 in my Cartfile), but it hangs on the ConcatenateSwiftFiles target. This is printed into the xcodebuild log file:

    === CLEAN LEGACY TARGET ConcatenateSwiftFiles OF PROJECT KeychainSwift WITH CONFIGURATION Release ==
    =
    
    Check dependencies
    
    ExternalBuildToolExecution ConcatenateSwiftFiles
        cd /Users/szotyi/Development/projects/4dmotion/iOS/4dmotion-ios/Carthage/Checkouts/keychain-swift
    
    ... # bunch of exports
    
        /Users/xxx/Carthage/Checkouts/keychain-swift/scripts/concatenate_swift_files.sh /Users/xxx/Carthage/Checkouts/keychain-swift/Sources /Users/xxx/Carthage/Checkouts/keychain-swift/Distrib/KeychainSwiftDistrib.swift //\
    //\ Keychain\ helper\ for\ iOS/Swift.\
    //\
    //\ https://github.com/marketplacer/keychain-swift\
    //\
    //\ This\ file\ was\ automatically\ generated\ by\ combining\ multiple\ Swift\ source\ files.\
    //
    

    After this line it waits forever. I would think it's something about the concatenate_swift_files.sh or the legacy target. I managed to overcome in a forked project by removing the target dependency from the scheme, but it's not the ideal solution for future releases. Thanks

    opened by szotyi 9
  • Enable

    Enable "swift test" command

    Fixes https://github.com/evgenyneu/keychain-swift/issues/112

    When I forked this project, I ran into the issue linked above when running swift test on my Mac. This PR fixes the tests by adding a test target to Package.swift, and adding import statements to all of the test files.

    One thing to note is that testClear() fails with error code -25244 (errSecInvalidOwnerEdit). I believe this is due to the fact that clear() is attempting to delete everything stored in the Mac keychain (which would obviously be a bad thing). Fortunately, keychain permissions prevent this from happening with the aforementioned error. Not sure how to get that test to pass.

    opened by AnthonyOliveri 8
  • Warning clarification

    Warning clarification

    Hello, can you please clarify the warning? The answer at stackoverflow says this is a problem with the simulator. It seems to work for me without the entitlement, but a colleague had the problem, that the keychain data was lost, when updating to a new build using testflight. Any insights?

    opened by bb-git 8
  • Keychain doesn't work with XCode 8 Beta 6

    Keychain doesn't work with XCode 8 Beta 6

    After porting my app to XCode 8 with Swift 2.3 (I waited until Beta 6 to do so), all of my tests passed with the exception of 1 set where I was storing Account information in the keychain and seeing if I could read it out. Everything I read out was nil. Note: I'm using a prefix.

    To see if this was my issue or a an issue with keychain-swift, I did the following:

    • Cloned the keychain-swift repository, checked out the Swift_2_3 branch.
    • Loaded it into XCode 8 Beta 6, selected the KeyChainSwift target and ran tests.

    What I got was a failure in KeychainWithPrefixTests.swift, line 35.

    Is there something I'm doing wrong?

    Btw, I'm not on Swift 3.0 because some other libraries I use are not yet compatible.

    opened by mark-anders 8
  • Keychain returns nil randomly

    Keychain returns nil randomly

    Occasionally a nil value is returned when trying to retrieve a string from the Keychain. There's no way to reproduce it, it appears to be random. Any one else had this problem, or know a fix for this? Will probably move away from KeychainSwift if not.

    opened by yusuftor 8
  • add lock to improve concurrency usage

    add lock to improve concurrency usage

    TL;DR

    • add lock to improve concurrency usage
    • added tests to check concurrency usage is correct

    The change is motivated because we found a crash in the letgo app (using keychain-swift). We found out that the reason is accessing the keychain concurrently from two threads. The crash is happening in getData method when calling SecItemCopyMatching.

    We implemented some tests in ConcurrencyTests.swift. If removing the NSLock usage and running them you'll see the above mentioned crash. Contribution by @elikohen

    opened by ahernandezlopez 6
  • get always returning nil

    get always returning nil

    i did the manual install by copying the KeychainSwiftDistrib.swift file into my project but i always get nil when i run the code below. I've tried with/without the access qualifier. am i missing something?

        let keychain = KeychainSwift()
    
        keychain.accessGroup = "CS671JRA62.com.myapp.KeychainGroup"
    
        keychain.set("Hello world", forKey: "my key", withAccess: .AccessibleAfterFirstUnlock)
    
        let testValue = keychain.get("my key")
    
    opened by geigerzaehler242 6
  • Added Access options to the get parameters with a default option set.

    Added Access options to the get parameters with a default option set.

    Added Access options to the get parameters with a default option set. As posted in:

    https://github.com/evgenyneu/keychain-swift/issues/78#issuecomment-549045569

    This provides a way for the developer to specify the same accessibility level that they saved the keychain item as to query out the keychain item. By default it is set to when unlocked, but it can be default to be afterFirst unlock to be able to access in the background

    Also Added some basic tests to validate the passing of the access options for the get parameter.

    opened by robertbarclay 5
  • can't not install with SPA

    can't not install with SPA

    Showing Recent Messages
    package at 'https://github.com/evgenyneu/keychain-swift.git' @ e43f9b99b172ae6a7253047f8ba95c7a0b05b99f is using Swift tools version 5.7.0 but the installed version is 5.5.0 in https://github.com/evgenyneu/keychain-swift.git
    

    my xcode version 13.2.1 swift version 5.5

    Please consider submitting the following information (if relevant):

    • Library setup method: file, Carthage, CocoaPods or Swift Package Manager.
    • Version of the library. Example: 8.0.
    • Xcode version. Example: 8.3.3.
    • OS version. Example: iOS 10.3.2.
    opened by LonYui 0
  • Could not find module 'KeychainSwift' for target 'x86_64-apple-ios-simulator'; found: arm64-apple-ios-simulator

    Could not find module 'KeychainSwift' for target 'x86_64-apple-ios-simulator'; found: arm64-apple-ios-simulator

    • CocoaPods
    • Version 20.0.0
    • Xcode version 14.0
    • iOS version 16.0

    When I add pod 'KeychainSwift' and import KeychainSwift I get the following build-time error:

    Could not find module 'KeychainSwift' for target 'x86_64-apple-ios-simulator'; found: arm64-apple-ios-simulator, at: /Users/Jordan/Library/Developer/Xcode/DerivedData/AppName-auabmrkvbmhhcuarlsdwrsooabxs/Index.noindex/Build/Products/Debug-iphonesimulator/KeychainSwift/KeychainSwift.framework/Modules/KeychainSwift.swiftmodule

    Seems KeychainSwift doesn't support Apple silicon Macs yet?

    opened by jordanhbuiltbyhq 0
  • Support kSecClassInternetPassword class?

    Support kSecClassInternetPassword class?

    Apple seems to recommend when saving a password to use kSecClassInternetPassword where you specify a username account, a server, and a password (documentation). There is a note that one should use kSecClassGenericPassword instead when you don’t need extra attributes for remote access. Now everything in this keychain library uses kSecClassGenericPassword it's not possible to use kSecClassInternetPassword.

    As an aside, it's mildly interesting, I suspect basically everyone is "misusing" the keychain API because I believe the "account" is not intended to be a key to look up like "MyServicePassword", it should seemingly be the user's account like their actual username. This makes it a bit tricky to look up later and migrate when the username changes. Wishing the keychain API were nicer fr. But perhaps this library could implement support for the recommended solution and even encourage correct usage? :)

    opened by jordanhbuiltbyhq 0
  • Keychain synchronization issues

    Keychain synchronization issues

    I am running an app on an iphone 8 and iphone 12 and I find that sometimes the keychain synchronization happens instantly and other times it doesn't sync the entire data between the devices or is not running at all.

    I am having a hard time understanding where the issue might be. How long does it usually take to see the changes in the keychain? Is there a reliable way to sync between devices instantly at runtime?

    opened by crisanvlad 0
  • Is keychain.clear() intended to always return false when no keys are saved?

    Is keychain.clear() intended to always return false when no keys are saved?

    I am implementing a feature to let the user reset the keychain in case there are issues and I check

    if keychain.clear() {
    // clearing successfull
    } else {
    //show error
    }
    

    And I was wondering if the clear() method shouldn't check inside if keychain.allKeys is empty before returning false.

    opened by crisanvlad 0
Releases(2.0.1)
Owner
Evgenii Neumerzhitckii
🐋🦔🐢🐝wow
Evgenii Neumerzhitckii
A wrapper to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

A wrapper (written only in Swift) to make it really easy to deal with iOS, macOS, watchOS and Linux Keychain and store your user's credentials securely.

Ezequiel Aceto 2 Mar 29, 2022
Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.

KeychainAccess KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and OS X. Makes using Keychain APIs extremely easy and much mor

Kishikawa Katsumi 7.2k Dec 30, 2022
A simple Swift Keychain Wrapper for iOS, watchOS, and OS X.

Latch A simple Swift 2.0 Keychain Wrapper for iOS, watchOS 2, and OS X. Usage A proper example of how to use Latch can be seen in the tests. import La

Danielle 56 Oct 25, 2022
Helper/wrapper for mautrix-imessage for jailbroken devices

Brooklyn This readme is out-of-date. Blame Ethan, he's working on it. Components Rubicon "The die is cast." Crosses Apple's last river between IMCore

Ethan Chaffin 11 Jun 24, 2022
Simple Objective-C wrapper for the keychain that works on Mac and iOS

SAMKeychain SAMKeychain is a simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system Keyc

Sam Soffes 5.4k Dec 29, 2022
Generate passwords and save them in Keychain. Made with SwiftUI.

lockd Generate strong passwords and save them in Keychain. Join lockd Beta on TestFlight: https://testflight.apple.com/join/xJ5AlvS3 Features: Generat

Iliane 56 Dec 29, 2022
A simple wrapper for the iOS Keychain to allow you to use it in a similar fashion to User Defaults. Written in Swift.

SwiftKeychainWrapper A simple wrapper for the iOS / tvOS Keychain to allow you to use it in a similar fashion to User Defaults. Written in Swift. Prov

Jason 1.5k Dec 30, 2022
A powerful, protocol-oriented library for working with the keychain in Swift.

Locksmith A powerful, protocol-oriented library for working with the keychain in Swift. ?? iOS 8.0+ ?? Mac OS X 10.10+ ⌚️ watchOS 2 ?? tvOS ?? I make

Matthew Palmer 2.9k Dec 21, 2022
KeyClip is yet another Keychain library written in Swift.

KeyClip KeyClip is yet another Keychain library written in Swift. Features Multi Types ( String / NSDictionary / NSData ) Error Handling Settings ( kS

Shinichiro Aska 43 Nov 6, 2022
A really simple key-value wrapper for keychain.

PlainKeychain A really simple key-value wrapper for keychain. Features ✅ Key-value pairs using kSecClassGenericPassword. ❌ Internet passwords (kSecCla

Benjamin Barnard 0 Nov 27, 2021
The IDAGIO WatchOS app using swift

IDAGIORedesignWatchOS I redesigned the IDAGIO WatchOS app as an exercise Old App

Francesco Junior Iaccarino 0 Dec 23, 2021
Virgil Core SDK allows developers to get up and running with Virgil Cards Service API quickly and add end-to-end security to their new or existing digital solutions to become HIPAA and GDPR compliant and more.

Virgil Core SDK Objective-C/Swift Introduction | SDK Features | Installation | Configure SDK | Usage Examples | Docs | Support Introduction Virgil Sec

Virgil Security, Inc. 27 Jul 26, 2022
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

Kitura 122 Dec 16, 2022
Safe and easy to use crypto for iOS and macOS

Swift-Sodium Swift-Sodium provides a safe and easy to use interface to perform common cryptographic operations on macOS, iOS, tvOS and watchOS. It lev

Frank Denis 483 Jan 5, 2023
RSA public/private key encryption, private key signing and public key verification in Swift using the Swift Package Manager. Works on iOS, macOS, and Linux (work in progress).

BlueRSA Swift cross-platform RSA wrapper library for RSA encryption and signing. Works on supported Apple platforms (using Security framework). Linux

Kitura 122 Dec 16, 2022
Native and encrypted password manager for iOS and macOS.

Open Sesame Native and encrypted password manager for iOS and macOS. What is it? OpenSesame is a free and powerful password manager that lets you mana

OpenSesame 432 Jan 7, 2023
Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities.

Description Oversecured Vulnerable iOS App is an iOS app that aggregates all the platform's known and popular security vulnerabilities. List of vulner

Oversecured Inc 135 Dec 15, 2022
Simple, secure password and data management for individuals and teams

Padloc Simple, secure password and data management for individuals and teams (formerly known as Padlock). This repo is split into multiple packages: P

Padloc 2.1k Jan 8, 2023
PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. PGPro is made in Switzerland.

PGPro can encrypt and decrypt messages as well as manage all your OpenPGP keys. It is free, simple and lightweight. Everything stays on your device. P

Luca Näf 250 Jan 4, 2023