Storing CryptoKit Keys in the Keychain
At a glance
| Item | Summary |
|---|---|
| Purpose | Convert between strongly typed cryptographic keys and native keychain types. |
| App architecture | A Swift sample bundle with entry-bearing project variants CryptoKitKeychain, CryptoKitKeychainMac, each leading to CryptoKit APIs. |
| Main patterns | Protocol-oriented abstraction, Delegate or data-source callbacks, Central store, SwiftUI environment injection |
| Project style | 18 scanned source file(s) across Swift, organized around ranked entry, type, and file boundaries. |
| Execution model | No structured execution marker indexed; callback threading requires source review. |
| State/event model | Source-visible mechanisms: ObservableObject, @Published, SwiftUI state property wrapper. |
| Key frameworks/packages | Foundation, CryptoKit, SwiftUI, Security, UIKit; these are source dependencies, not architecture labels. |
Project structure
Source bundle/
├── CryptoKitKeychain/
│ ├── AppDelegate.swift
│ └── SceneDelegate.swift
├── CryptoKitKeychainMac/
│ └── AppDelegate.swift
├── Testing/
│ └── KeyTest.swift
├── Views/
│ ├── ContentView.swift
│ ├── CurveView.swift
│ ├── NISTView.swift
│ ├── SymmetricView.swift
│ └── ExecutionView.swift
└── Storage/
├── GenericPasswordStore.swift
├── SecKeyStore.swift
└── GenericPasswordConvertible.swift
Structure observations
- Architecturally prominent files are ranked from entry points and role-named declarations; resource-only paths are omitted.
- Primary languages: Swift.
- The verified tree contains 8 project/configuration file(s) and 19 source declaration(s).
Overall architecture
flowchart LR
Bundle["Sample bundle"]
V1["CryptoKitKeychain"]
V2["CryptoKitKeychainMac"]
Boundary["CryptoKit APIs"]
Bundle --> V1
V1 --> Boundary
Bundle --> V2
V2 --> Boundary
Reference code
CryptoKitKeychain/AppDelegate.swift:10 — architecture anchor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { }Interpretation
The branches represent separate entry-bearing project variants in the downloaded bundle, not runtime calls between those variants. Each branch is intentionally collapsed at the documented framework boundary; the detailed target-local flow remains in the cited files. Ownership is claimed only where the next section cites a stored property or assignment.
Ownership and state
classDiagram
AppDelegate o-- NSWindow : window
ContentView o-- KeyTest : tester
CurveView o-- KeyTest : tester
NISTView o-- KeyTest : tester
Ownership evidence
CryptoKitKeychainMac/AppDelegate.swift:14 — stored dependency or nearest verified ownership anchor
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// ...
var window: NSWindow!
// ...
}| Owner | Object or state | Relationship | Mutation authority |
|---|---|---|---|
AppDelegate |
NSWindow (window) |
stores or receives | App/module collaborators |
ContentView |
KeyTest (tester) |
receives environment-provided state | The environment provider is authoritative |
CurveView |
KeyTest (tester) |
receives environment-provided state | The environment provider is authoritative |
NISTView |
KeyTest (tester) |
receives environment-provided state | The environment provider is authoritative |
Composition arrows indicate a source-visible construction expression or locally owned value state; aggregation means the owner stores or receives a dependency without proving exclusive lifetime ownership.
Concurrency, scheduling, and thread safety
Evidence limit: actor isolation, async/await, or Task creation does not by itself prove background-thread execution; Sendable conformance alone does not prove thread-safe mutation.
No source-visible execution, scheduling, or synchronization boundary was found in the indexed source.
@MainActor/MainActor.run, DispatchQueue.main, and RunLoop.main are reported as distinct isolation, queue, and event-loop mechanisms. A plain Task is kept separate from Task.detached; neither is labeled as a background thread.
State propagation, frameworks, and dependencies
Evidence limit: an import proves a source-level compilation dependency at the cited line; it does not prove runtime use, architectural adoption, or whether a Swift package is a direct application dependency.
| Category | Mechanism or module | Verified role | Evidence |
|---|---|---|---|
| State propagation | ObservableObject |
ObservableObject supplies an observation contract. | Testing/KeyTest.swift:13 |
| State propagation | @Published |
A published property can emit owner-controlled changes. | Testing/KeyTest.swift:64 |
| State propagation | SwiftUI state property wrapper |
A SwiftUI property wrapper supplies or observes UI state. | Views/ContentView.swift:11 |
| Source import | Foundation |
The cited file imports this module; runtime use and architectural role are not inferred. | Storage/GenericPasswordConvertible.swift:8 |
| Source import | CryptoKit |
The cited file imports this module; runtime use and architectural role are not inferred. | Storage/GenericPasswordConvertible.swift:9 |
| Source import | SwiftUI |
The cited file imports this module; runtime use and architectural role are not inferred. | CryptoKitKeychain/SceneDelegate.swift:9 |
| Source import | Security |
The cited file imports this module; runtime use and architectural role are not inferred. | Storage/GenericPasswordStore.swift:10 |
| Source import | UIKit |
The cited file imports this module; runtime use and architectural role are not inferred. | CryptoKitKeychain/AppDelegate.swift:8 |
receive(on:) describes downstream delivery scheduling, while subscribe(on:) describes upstream subscription/request/cancel scheduling. An import Combine alone establishes neither behavior nor a Store, reducer, Redux, or other application architecture.
Class and protocol design
Storage/GenericPasswordConvertible.swift:12 — representative type boundary
protocol GenericPasswordConvertible: CustomStringConvertible {
/// Creates a key from a generic key representation.
init<D>(genericKeyRepresentation data: D) throws where D: ContiguousBytes
/// A generic representation of the key.
var genericKeyRepresentation: SymmetricKey { get }
}| Type | Responsibility | Depends on or conforms to |
|---|---|---|
AppDelegate |
Receives callback-driven events | UIResponder, UIApplicationDelegate |
AppDelegate |
Receives callback-driven events | NSObject, NSApplicationDelegate |
ContentView |
User-interface presentation and input forwarding | View |
CurveView |
User-interface presentation and input forwarding | View |
NISTView |
User-interface presentation and input forwarding | View |
SymmetricView |
User-interface presentation and input forwarding | View |
SceneDelegate |
Receives callback-driven events | UIResponder, UIWindowSceneDelegate |
GenericPasswordStore |
Centralized state or persistence access | Concrete collaborators/imported frameworks |
SecKeyStore |
Centralized state or persistence access | Concrete collaborators/imported frameworks |
ExecutionView |
User-interface presentation and input forwarding | View |
The source explicitly defines local protocol relationships: Curve25519.KeyAgreement.PrivateKey → GenericPasswordConvertible, Curve25519.Signing.PrivateKey → GenericPasswordConvertible, SymmetricKey → GenericPasswordConvertible, SecureEnclave.P256.KeyAgreement.PrivateKey → GenericPasswordConvertible, SecureEnclave.P256.Signing.PrivateKey → GenericPasswordConvertible, P256.Signing.PrivateKey → SecKeyConvertible.
Access control
| Symbol | Access | Verified effect | Likely rationale |
|---|---|---|---|
description (Storage/GenericPasswordConvertible.swift:23) |
public |
The symbol is visible to importing modules. | Inference: make the declaration available across a module or target boundary. |
description (Storage/KeyStoreError.swift:18) |
public |
The symbol is visible to importing modules. | Inference: make the declaration available across a module or target boundary. |
description (Storage/SecKeyConvertible.swift:23) |
public |
The symbol is visible to importing modules. | Inference: make the declaration available across a module or target boundary. |
testCurve (Testing/KeyTest+Curve.swift:13) |
internal |
No explicit modifier means the Swift declaration is internal to the module. | Inference: the language’s file or module boundary is sufficient for this sample collaboration. |
Reference code
Storage/GenericPasswordConvertible.swift:23 — representative boundary
public var description: String {
return self.genericKeyRepresentation.withUnsafeBytes { bytes in
return "Key representation contains \(bytes.count) bytes."
}
}Swift declarations without a modifier are internal; explicit private, fileprivate, private(set), public, or open entries above are interpreted by language semantics. Objective-C/C samples instead rely on header and implementation boundaries, which are not equivalent to Swift lexical privacy.
Logic ownership and placement
| Logic | Owning type or file | Placement rationale |
|---|---|---|
| Receives callback-driven events | AppDelegate, SceneDelegate |
The source’s Delegate suffix makes this role explicit. |
| Centralized state or persistence access | GenericPasswordStore, SecKeyStore |
The source’s Store suffix makes this role explicit. |
| User-interface presentation and input forwarding | ContentView, CurveView, ExecutionView, NISTView |
The source’s View suffix makes this role explicit. |
Design patterns
| Pattern | Source evidence | Purpose or tradeoff |
|---|---|---|
| Protocol-oriented abstraction | Storage/GenericPasswordConvertible.swift:31 |
A local protocol and concrete conformance create an explicit capability boundary. |
| Delegate or data-source callbacks | CryptoKitKeychain/AppDelegate.swift:11 |
Callback protocols invert event delivery back into the sample’s owner. |
| Central store | Storage/GenericPasswordStore.swift:12 |
A store-named type centralizes feature state or persistence. |
| SwiftUI environment injection | Views/ContentView.swift:11 |
The environment supplies state or a capability without threading it through every initializer. |
Naming conventions
- Types: Delegate: AppDelegate, SceneDelegate; Store: GenericPasswordStore, SecKeyStore; View: ContentView, CurveView, ExecutionView, NISTView, SymmetricView.
- Protocols:
GenericPasswordConvertible,SecKeyConvertible. - Methods:
applicationDidFinishLaunching,reset,run,scene. - Files:
CryptoKitKeychain/AppDelegate.swift,CryptoKitKeychainMac/AppDelegate.swift,Testing/KeyTest.swift,Views/ContentView.swift,Views/CurveView.swift,Views/NISTView.swift.
Architecture takeaways
AppDelegateis the main source-visible entry or composition anchor for this sample.- Framework work reaches CryptoKit, SwiftUI, Security, UIKit through a deliberately small high-level chain; the detailed API graph remains inside the cited implementation files.
- Stored-property evidence identifies lifecycle collaboration; it does not by itself prove exclusive object ownership.
- Access-control conclusions separate verified language visibility from the likely design rationale.
- Local protocol relationships provide an explicit substitution boundary.
Source map
| Source file | Relevant symbols |
|---|---|
CryptoKitKeychain/AppDelegate.swift |
Cited implementation, UIKit, AppDelegate |
CryptoKitKeychainMac/AppDelegate.swift |
Cited implementation, AppDelegate |
Storage/GenericPasswordConvertible.swift |
GenericPasswordConvertible, Cited implementation, Foundation, CryptoKit |
Storage/KeyStoreError.swift |
Cited implementation, KeyStoreError |
Storage/SecKeyConvertible.swift |
Cited implementation, SecKeyConvertible |
Testing/KeyTest+Curve.swift |
Cited implementation, Feature implementation |
Storage/GenericPasswordStore.swift |
GenericPasswordStore, Security |
Views/ContentView.swift |
Cited implementation, SwiftUI state property wrapper, ContentView, ContentViewPreviews |
Testing/KeyTest.swift |
ObservableObject, @Published, KeyTest, TestStatus, Category, Purpose, NISTSize, SymmetricSize |
CryptoKitKeychain/SceneDelegate.swift |
SwiftUI, SceneDelegate |
Views/CurveView.swift |
CurveView, CurveViewPreviews |
Views/NISTView.swift |
NISTView, NISTViewPreviews |
Views/SymmetricView.swift |
SymmetricView, SymmetricViewPreviews |
Storage/SecKeyStore.swift |
SecKeyStore |
Views/ExecutionView.swift |
ExecutionView |
Testing/KeyTest+NIST.swift |
Feature implementation |