Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-01-14 10:07:05 -06:00
parent 68b3830618
commit 5fa4f40099
3 changed files with 32 additions and 19 deletions

View File

@ -13,7 +13,7 @@ struct SecureStorgageSampleApp: App {
init() {
_ = WatchConnectivityService.shared
Task {
await EncryptionHelper.shared.registerKeyMaterialProvider(
await StorageRouter.shared.registerKeyMaterialProvider(
ExternalKeyMaterialProvider(),
for: SampleKeyMaterialSources.external
)

View File

@ -1,37 +1,26 @@
import CryptoKit
import Foundation
import LocalData
import Security
nonisolated
struct ExternalKeyMaterialProvider: KeyMaterialProviding {
private enum Constants {
static let service = "com.example.securestorage.externalkey"
static let keyLength = 32
}
func keyMaterial(for keyName: String) async throws -> Data {
if let existing = try await KeychainHelper.shared.get(
service: Constants.service,
key: keyName
) {
let key = StorageKeys.ExternalKeyMaterialKey(keyName: keyName)
if let existing = try await StorageRouter.shared.get(key) as Data? {
return existing
}
var bytes = [UInt8](repeating: 0, count: Constants.keyLength)
let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
guard status == errSecSuccess else {
let symmetricKey = SymmetricKey(size: .bits256)
let material = symmetricKey.withUnsafeBytes { Data($0) }
guard material.count == Constants.keyLength else {
throw StorageError.securityApplicationFailed
}
let material = Data(bytes)
try await KeychainHelper.shared.set(
material,
service: Constants.service,
key: keyName,
accessibility: .afterFirstUnlock,
accessControl: nil
)
try await StorageRouter.shared.set(material, for: key)
return material
}
}

View File

@ -0,0 +1,24 @@
import Foundation
import LocalData
extension StorageKeys {
/// Stores external key material used for encryption policies.
struct ExternalKeyMaterialKey: StorageKey {
typealias Value = Data
let name: String
let domain: StorageDomain = .keychain(service: "com.example.securestorage.externalkey")
let security: SecurityPolicy = .keychain(
accessibility: .afterFirstUnlock,
accessControl: nil
)
let serializer: Serializer<Data> = .data
let owner = "SampleApp"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
init(keyName: String) {
self.name = keyName
}
}
}