|
4 | 4 | [](https://swift.org/package-manager) |
5 | 5 | [](http://mit-license.org) |
6 | 6 |
|
7 | | -SwiftSecurity is a modern Swift wrapper for [Security](https://developer.apple.com/documentation/security) framework (Keychain Services API, SharedWebCredentials API). Secure the data your app manages in a much easier way with compile-time checks. |
| 7 | +SwiftSecurity is a modern Swift API for Apple [Security](https://developer.apple.com/documentation/security) framework (Keychain API, SharedWebCredentials API, etc). Secure the data your app manages in a much easier way with compile-time checks. |
8 | 8 |
|
9 | 9 | ## Features |
10 | 10 |
|
11 | 11 | How does SwiftSecurity differ from other wrappers? |
12 | 12 |
|
13 | | -* Support for every [Keychain item class](https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_class_keys_and_values) (Generic & Internet Password, Key, Certificate and Identity). |
14 | | -* Generic code prevents the creation of an incorrect set of [attributes](https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values) for items. |
15 | | -* Compatibility with [CryptoKit](https://developer.apple.com/documentation/cryptokit/) and [SwiftUI](https://developer.apple.com/documentation/swiftui/). |
16 | | -* Native-like API experience. Clear of any deprecated and legacy calls. |
| 13 | +* Supports every [Keychain item class](https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_class_keys_and_values) (Generic & Internet Password, Key, Certificate and Identity). |
| 14 | +* Prevents creation of an incorrect set of [attributes](https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values) for items. |
| 15 | +* Compatible with [CryptoKit](https://developer.apple.com/documentation/cryptokit/) and [SwiftUI](https://developer.apple.com/documentation/swiftui/). |
| 16 | +* Clear of deprecated and legacy calls. |
17 | 17 |
|
18 | 18 | ## Installation |
19 | 19 |
|
@@ -190,6 +190,21 @@ print(query.debugDescription) // ["Class: GenericPassword", ..., "Service: OpenA |
190 | 190 | print(keychain.debugDescription) |
191 | 191 | ``` |
192 | 192 |
|
| 193 | +#### Error Handling |
| 194 | + |
| 195 | +```swift |
| 196 | +do { |
| 197 | + let token: String? = try Keychain.default.store("8e9c0a7f", query: .credential(for: "OpenAI")) |
| 198 | +} catch { |
| 199 | + switch error as? SwiftSecurityError { |
| 200 | + case .duplicateItem: |
| 201 | + // handle duplicate |
| 202 | + default: |
| 203 | + // unhandled |
| 204 | + } |
| 205 | +} |
| 206 | +``` |
| 207 | + |
193 | 208 | ## How to Choose Keychain |
194 | 209 |
|
195 | 210 | #### Default |
@@ -231,6 +246,7 @@ let keychain = Keychain(accessGroup: .appGroupID("group.com.example.app")) |
231 | 246 | #### Store protected item |
232 | 247 |
|
233 | 248 | ```swift |
| 249 | +// Store with specified `AccessPolicy` |
234 | 250 | try keychain.store( |
235 | 251 | secret, |
236 | 252 | query: .credential(for: "FBI"), |
@@ -274,6 +290,42 @@ if success { |
274 | 290 | > [!WARNING] |
275 | 291 | > Include the [NSFaceIDUsageDescription](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW75) key in your app’s Info.plist file. Otherwise, authentication request may fail. |
276 | 292 |
|
| 293 | +## 🔖 Data Types |
| 294 | + |
| 295 | +You can store, retrieve, and remove various types of values. |
| 296 | + |
| 297 | +```swift |
| 298 | +Foundation: |
| 299 | + - Data // GenericPassword, InternetPassword |
| 300 | + - String // GenericPassword, InternetPassword |
| 301 | +CryptoKit: |
| 302 | + - SymmetricKey // GenericPassword |
| 303 | + - Curve25519 -> PrivateKey // GenericPassword |
| 304 | + - SecureEnclave.P256 -> PrivateKey // GenericPassword (Key Data is Persistent Identifier) |
| 305 | + - P256, P384, P521 -> PrivateKey // SecKey (ANSI x9.63 Elliptic Curves) |
| 306 | +SwiftSecurity: |
| 307 | + - X509.DER.Data // SecCertificate (DER-Encoded X.509 Data) |
| 308 | + - PKCS12.Data // SecIdentity (PKCS #12 Blob) |
| 309 | +``` |
| 310 | + |
| 311 | +To add support for custom types, you can extend them by conforming to the following protocols. |
| 312 | + |
| 313 | +```swift |
| 314 | +// Store as Data (GenericPassword, InternetPassword) |
| 315 | +extension CustomType: SecDataConvertible {} |
| 316 | + |
| 317 | +// Store as Key (ANSI x9.63, Elliptic Curves) |
| 318 | +extension CustomType: SecKeyConvertible {} |
| 319 | + |
| 320 | +// Store as Certificate (X.509) |
| 321 | +extension CustomType: SecCertificateConvertible {} |
| 322 | + |
| 323 | +// Import as Identity (PKCS #12) |
| 324 | +extension CustomType: SecIdentityConvertible {} |
| 325 | +``` |
| 326 | + |
| 327 | +These protocols are inspired by Apple's sample code from the [Storing CryptoKit Keys in the Keychain](https://developer.apple.com/documentation/cryptokit/storing_cryptokit_keys_in_the_keychain) article. |
| 328 | + |
277 | 329 | ## 🔑 Shared Web Credential |
278 | 330 |
|
279 | 331 | > [!TIP] |
@@ -304,41 +356,13 @@ SharedWebCredential.remove("https://example.com", account: "username") { result |
304 | 356 | // - Use `ASAuthorizationController` to make an `ASAuthorizationPasswordRequest`. |
305 | 357 | ``` |
306 | 358 |
|
307 | | -## 🔖 Data Types |
308 | | - |
309 | | -You can store, retrieve, and remove various types of values. |
310 | | - |
311 | | -```swift |
312 | | -Foundation: |
313 | | - - Data // GenericPassword, InternetPassword |
314 | | - - String // GenericPassword, InternetPassword |
315 | | -CryptoKit: |
316 | | - - SymmetricKey // GenericPassword |
317 | | - - Curve25519 // GenericPassword |
318 | | - - P256, P384, P521 // SecKey (ANSI x9.63, Elliptic Curves) |
319 | | -SwiftSecurity: |
320 | | - - X509.DER.Data // SecCertificate (DER-Encoded X.509 Data) |
321 | | - - PKCS12.Data // SecIdentity (PKCS #12 Blob) |
322 | | -``` |
323 | | - |
324 | | -To add support for custom types, you can extend them by conforming to the following protocols. |
| 359 | +## 🔒 Secure Data Generator |
325 | 360 |
|
326 | 361 | ```swift |
327 | | -// Store as Data (GenericPassword, InternetPassword) |
328 | | -extension CustomType: SecDataConvertible {} |
329 | | - |
330 | | -// Store as Key (ANSI x9.63, Elliptic Curves) |
331 | | -extension CustomType: SecKeyConvertible {} |
332 | | - |
333 | | -// Store as Certificate (X.509) |
334 | | -extension CustomType: SecCertificateConvertible {} |
335 | | - |
336 | | -// Import as Identity (PKCS #12) |
337 | | -extension CustomType: SecIdentityConvertible {} |
| 362 | +// Data with 20 uniformly distributed random bytes |
| 363 | +let randomData = SecureRandomDataGenerator(count: 20).next() |
338 | 364 | ``` |
339 | 365 |
|
340 | | -These protocols are inspired by Apple's sample code from the [Storing CryptoKit Keys in the Keychain](https://developer.apple.com/documentation/cryptokit/storing_cryptokit_keys_in_the_keychain) article. |
341 | | - |
342 | 366 | ## Security |
343 | 367 |
|
344 | 368 | The framework’s default behavior provides a reasonable trade-off between security and accessibility. |
|
0 commit comments