iOS Security Framework 密钥导出:从 PKCS#1 到 PKCS#8 的 2 种手动封装方案 iOS Security Framework 密钥导出从 PKCS#1 到 PKCS#8 的 2 种手动封装方案在 iOS/macOS 开发中处理密钥格式转换是密码学操作中常见的需求。特别是当我们需要将系统 API 生成的 PKCS#1 格式密钥转换为更通用的 PKCS#8 格式时这一过程需要开发者对 ASN.1 结构有深入理解。本文将详细介绍两种手动封装方案帮助开发者实现跨平台密钥交换。1. PKCS#1 与 PKCS#8 格式解析在开始转换之前我们需要清楚两种格式的本质区别。PKCS#1 格式特点专为 RSA 算法设计直接包含 RSA 私钥的核心参数n, e, d, p, q 等iOS 的SecKeyCopyExternalRepresentation默认生成此格式典型 PEM 文件头标记为-----BEGIN RSA PRIVATE KEY-----PKCS#8 格式特点支持多种非对称加密算法RSA、ECC 等包含算法标识符和版本号更通用的跨平台兼容性典型 PEM 文件头标记为-----BEGIN PRIVATE KEY-----1.1 ASN.1 结构对比通过 ASN.1 结构可以更直观地理解两种格式的差异PKCS#1 私钥结构RSAPrivateKey :: SEQUENCE { version Version, modulus INTEGER, -- n publicExponent INTEGER, -- e privateExponent INTEGER, -- d prime1 INTEGER, -- p prime2 INTEGER, -- q exponent1 INTEGER, -- d mod (p-1) exponent2 INTEGER, -- d mod (q-1) coefficient INTEGER, -- (inverse of q) mod p otherPrimeInfos OtherPrimeInfos OPTIONAL }PKCS#8 私钥结构PrivateKeyInfo :: SEQUENCE { version Version, algorithm AlgorithmIdentifier, privateKey PrivateKey, attributes [0] IMPLICIT Attributes OPTIONAL } AlgorithmIdentifier :: SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL }关键区别在于 PKCS#8 使用容器包装 PKCS#1 数据并添加了算法标识信息。2. 方案一基础 ASN.1 手动封装这是最直接的转换方法适合需要完全控制 ASN.1 结构的场景。2.1 实现步骤获取 PKCS#1 格式的 DER 数据var error: UnmanagedCFError? guard let pkcs1Data SecKeyCopyExternalRepresentation(privateKey, error) as Data? else { throw error!.takeRetainedValue() as Error }构建 PKCS#8 的 ASN.1 结构// 版本号 (0) let version Data([0x02, 0x01, 0x00]) // RSA 算法标识符 (1.2.840.113549.1.1.1) let rsaOID Data([0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00]) // 将PKCS1数据包装为OCTET STRING let pkcs1OctetString Data([0x04]) derLength(for: pkcs1Data) pkcs1Data // 拼接完整PKCS8结构 let pkcs8SequenceData version rsaOID pkcs1OctetString let pkcs8Data Data([0x30]) derLength(for: pkcs8SequenceData) pkcs8SequenceData转换为 PEM 格式let base64Content pkcs8Data.base64EncodedString(options: .lineLength64Characters) return -----BEGIN PRIVATE KEY-----\n\(base64Content)\n-----END PRIVATE KEY-----2.2 关键辅助函数private func derLength(for data: Data) - Data { let length data.count switch length { case 0..0x80: return Data([UInt8(length)]) case 0x80...0xFF: return Data([0x81, UInt8(length)]) case 0x100...0xFFFF: return Data([0x82, UInt8(length 8), UInt8(length 0xFF)]) default: return Data([0x83, UInt8(length 16), UInt8((length 8) 0xFF), UInt8(length 0xFF)]) } }2.3 使用示例do { let pkcs8PEM try privateKey.convertPKCS1ToPKCS8PEM() print(转换结果:\n\(pkcs8PEM)) } catch { print(转换失败: \(error)) }3. 方案二使用 Security Framework 高级封装对于需要更高安全性的场景我们可以利用 Security Framework 提供的功能进行封装。3.1 实现步骤创建临时密钥属性字典let keyAttributes: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsPermanent as String: false ]转换密钥格式var error: UnmanagedCFError? guard let pkcs8Data SecKeyCopyExternalRepresentation(privateKey, error) as Data?, let pkcs8Key SecKeyCreateWithData(pkcs8Data as CFData, keyAttributes as CFDictionary, error) else { throw error!.takeRetainedValue() as Error }导出 PKCS#8 格式let exportParams: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsExtractable as String: true ] guard let exportedData SecKeyCopyExternalRepresentation(pkcs8Key, error) as Data? else { throw error!.takeRetainedValue() as Error }3.2 完整实现func convertToPKCS8UsingSecurityFramework(privateKey: SecKey) throws - String { // 1. 定义密钥属性 let keyAttributes: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsPermanent as String: false ] // 2. 获取PKCS#1数据 var error: UnmanagedCFError? guard let pkcs1Data SecKeyCopyExternalRepresentation(privateKey, error) as Data? else { throw error!.takeRetainedValue() as Error } // 3. 重新创建密钥对象 guard let newKey SecKeyCreateWithData(pkcs1Data as CFData, keyAttributes as CFDictionary, error) else { throw error!.takeRetainedValue() as Error } // 4. 导出PKCS#8格式 let exportParams: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsExtractable as String: true ] guard let pkcs8Data SecKeyCopyExternalRepresentation(newKey, error) as Data? else { throw error!.takeRetainedValue() as Error } // 5. 转换为PEM格式 let base64Content pkcs8Data.base64EncodedString(options: .lineLength64Characters) return -----BEGIN PRIVATE KEY-----\n\(base64Content)\n-----END PRIVATE KEY----- }4. 两种方案的对比与选择特性方案一手动 ASN.1 封装方案二Security Framework 封装实现复杂度高需要了解 ASN.1 细节低使用系统 API灵活性高可完全控制结构中受限于系统实现性能较高较低涉及额外密钥操作安全性依赖开发者实现使用系统加密模块跨平台兼容性需要手动调整不同平台仅限 Apple 平台维护成本高低选择建议需要最大控制权或跨平台需求选择方案一开发仅运行在 Apple 平台的应用选择方案二对安全性要求极高的场景推荐方案二5. 实际应用中的注意事项密钥可导出性// 生成密钥时必须设置可导出属性 let keyPairAttributes: [CFString: Any] [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits: 2048, kSecAttrIsExtractable: true, // 必须为true kSecAttrIsPermanent: false ]内存安全处理// 安全清除内存中的敏感数据 pkcs1Data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in memset(UnsafeMutableRawPointer(mutating: buffer.baseAddress!), 0, buffer.count) }性能优化技巧// 预计算常用ASN.1结构 private static let rsaAlgorithmID: Data { var data Data() data.append(0x30) // SEQUENCE data.append(0x0D) // Length // ... 完整算法标识 return data }()错误处理最佳实践do { let pkcs8Key try convertToPKCS8(privateKey) // 使用转换后的密钥 } catch KeyConversionError.invalidKeyData { // 处理特定错误 } catch { // 处理未知错误 logError(密钥转换失败: \(error.localizedDescription)) }6. 验证转换结果为确保转换正确性我们可以通过 OpenSSL 验证结果# 验证PKCS#8格式 openssl rsa -in converted.pem -inform PEM -check # 提取公钥验证配对 openssl rsa -in converted.pem -pubout -out public.pem # 对比原始公钥和导出公钥 diff (openssl rsa -in original.key -pubout) public.pem也可以通过代码验证func verifyKeyPair(privateKey: SecKey, publicKey: SecKey) - Bool { let testData 验证数据.data(using: .utf8)! var error: UnmanagedCFError? guard let encrypted SecKeyCreateEncryptedData( publicKey, .rsaEncryptionPKCS1, testData as CFData, error) else { return false } guard let decrypted SecKeyCreateDecryptedData( privateKey, .rsaEncryptionPKCS1, encrypted, error) else { return false } return testData decrypted as Data }7. 高级话题性能优化与安全增强对于高频使用的场景我们可以进一步优化缓存 ASN.1 结构private struct ASN1Cache { static let rsaOID: Data { var data Data() data.append(0x30) // SEQUENCE data.append(0x0D) // Length // ... 完整OID数据 return data }() static let version: Data { return Data([0x02, 0x01, 0x00]) }() }安全内存处理扩展extension Data { mutating func secureErase() { withUnsafeMutableBytes { (buffer: UnsafeMutableRawBufferPointer) in memset(buffer.baseAddress!, 0, buffer.count) } } static func secureRandom(count: Int) - Data? { var data Data(count: count) let result data.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, count, $0.baseAddress!) } return result errSecSuccess ? data : nil } }批量处理优化func batchConvertKeys(keys: [SecKey]) throws - [String] { return try keys.concurrentMap { key in try convertToPKCS8(privateKey: key) } } extension Array { func concurrentMapT(_ transform: (Element) throws - T) throws - [T] { var results [ResultT, Error?](repeating: nil, count: count) let queue DispatchQueue(label: concurrent.map.queue) DispatchQueue.concurrentPerform(iterations: count) { index in do { let result try transform(self[index]) queue.sync { results[index] .success(result) } } catch { queue.sync { results[index] .failure(error) } } } return try results.map { try $0!.get() } } }8. 跨平台兼容性处理当需要与不同平台交互时还需要考虑以下因素Java 平台兼容性// Java 读取PKCS#8 PEM文件 private static PrivateKey loadPrivateKey(String filename) throws Exception { String content new String(Files.readAllBytes(Paths.get(filename))); content content.replace(-----BEGIN PRIVATE KEY-----, ) .replace(-----END PRIVATE KEY-----, ) .replaceAll(\\s, ); byte[] decoded Base64.getDecoder().decode(content); PKCS8EncodedKeySpec keySpec new PKCS8EncodedKeySpec(decoded); KeyFactory kf KeyFactory.getInstance(RSA); return kf.generatePrivate(keySpec); }Node.js 兼容性处理const fs require(fs); const crypto require(crypto); function loadPrivateKey(path) { const pem fs.readFileSync(path, utf8); return crypto.createPrivateKey({ key: pem, format: pem, type: pkcs8 }); }Python 兼容性示例from cryptography.hazmat.primitives import serialization def load_private_key(path): with open(path, rb) as key_file: return serialization.load_pem_private_key( key_file.read(), passwordNone, )9. 密钥转换的单元测试为确保转换可靠性应建立完善的测试套件class KeyConversionTests: XCTestCase { var testPrivateKey: SecKey! override func setUp() { super.setUp() testPrivateKey generateTestKey() } func testPKCS8Conversion() { do { let pkcs8PEM try convertToPKCS8(privateKey: testPrivateKey) XCTAssertTrue(pkcs8PEM.hasPrefix(-----BEGIN PRIVATE KEY-----)) XCTAssertTrue(pkcs8PEM.hasSuffix(-----END PRIVATE KEY-----\n)) // 验证可以重新导入 let attributes: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate ] var error: UnmanagedCFError? let key SecKeyCreateWithData( Data(pkcs8PEM.utf8) as CFData, attributes as CFDictionary, error) XCTAssertNotNil(key) XCTAssertNil(error) } catch { XCTFail(转换失败: \(error)) } } private func generateTestKey() - SecKey { let attributes: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsExtractable as String: true ] var error: UnmanagedCFError? guard let privateKey SecKeyCreateRandomKey(attributes as CFDictionary, error) else { fatalError(无法生成测试密钥: \(error!.takeRetainedValue())) } return privateKey } }10. 实际项目集成建议将密钥转换功能集成到项目时建议采用以下模式协议抽象protocol KeyFormatConverter { func convertToPKCS8(privateKey: SecKey) throws - String func convertFromPKCS8(pemString: String) throws - SecKey } struct DefaultKeyConverter: KeyFormatConverter { // 实现协议方法 }依赖注入class CryptoService { private let keyConverter: KeyFormatConverter init(converter: KeyFormatConverter DefaultKeyConverter()) { self.keyConverter converter } func exportKey(privateKey: SecKey) throws - String { return try keyConverter.convertToPKCS8(privateKey: privateKey) } }性能监控func measureConversionPerformance() { let metrics: [XCTMetric] [XCTClockMetric(), XCTMemoryMetric()] let measureOptions XCTMeasureOptions.default measureOptions.iterationCount 100 measure(metrics: metrics, options: measureOptions) { do { _ try convertToPKCS8(privateKey: testPrivateKey) } catch { XCTFail(性能测试失败: \(error)) } } }安全审计日志struct SecurityLogger { static func logKeyOperation(_ operation: String, metadata: [String: Any] [:]) { let logData: [String: Any] [ timestamp: Date().timeIntervalSince1970, operation: operation, metadata: metadata ] // 安全地记录到文件或发送到服务器 // 注意: 实际实现中不应记录密钥内容本身 } }11. 密钥生命周期管理完善的密钥管理策略应包括密钥生成最佳实践func generateSecureKeyPair() throws - (publicKey: SecKey, privateKey: SecKey) { let attributes: [String: Any] [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsExtractable as String: true, kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, // 如果可用 kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: false, kSecAttrAccessControl as String: SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage], nil)! ] ] var error: UnmanagedCFError? guard let privateKey SecKeyCreateRandomKey(attributes as CFDictionary, error), let publicKey SecKeyCopyPublicKey(privateKey) else { throw error!.takeRetainedValue() as Error } return (publicKey, privateKey) }密钥存储建议protocol KeyStorage { func store(key: SecKey, identifier: String) throws func retrieveKey(identifier: String) throws - SecKey? func deleteKey(identifier: String) throws } struct KeychainStorage: KeyStorage { // 实现安全的密钥存储 }密钥轮换策略class KeyRotationManager { private let keyStorage: KeyStorage private let cryptoService: CryptoService private let rotationInterval: TimeInterval init(storage: KeyStorage, service: CryptoService, rotationInterval: TimeInterval 30 * 24 * 60 * 60) { // 默认30天 self.keyStorage storage self.cryptoService service self.rotationInterval rotationInterval } func rotateIfNeeded(identifier: String) throws - SecKey { if let existingKey try keyStorage.retrieveKey(identifier: identifier), let creationDate getKeyCreationDate(key: existingKey), Date().timeIntervalSince(creationDate) rotationInterval { return existingKey } // 生成新密钥 let (publicKey, privateKey) try generateSecureKeyPair() try keyStorage.store(key: privateKey, identifier: identifier) // 这里可以添加密钥分发逻辑 distributeNewKey(publicKey) return privateKey } private func getKeyCreationDate(key: SecKey) - Date? { let query: [String: Any] [ kSecClass as String: kSecClassKey, kSecValueRef as String: key, kSecReturnAttributes as String: true ] var result: CFTypeRef? let status SecItemCopyMatching(query as CFDictionary, result) guard status errSecSuccess, let attributes result as? [String: Any], let creationDate attributes[kSecAttrCreationDate as String] as? Date else { return nil } return creationDate } }12. 故障排查与常见问题开发过程中可能遇到的典型问题及解决方案密钥不可导出错误错误信息Error DomainNSOSStatusErrorDomain Code-25300 Item not exportable解决方案// 确保生成密钥时设置了kSecAttrIsExtractable为true let keyAttributes: [String: Any] [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits: 2048, kSecAttrIsExtractable: true // 关键设置 ]ASN.1 结构错误错误信息ASN1 corrupted data解决方案// 验证DER长度编码是否正确 func validateDERLength(data: Data) - Bool { guard !data.isEmpty else { return false } let firstByte data[0] if firstByte 0x80 { return data.count 1 } let lengthOfLength Int(firstByte 0x7F) guard data.count 1 lengthOfLength else { return false } // 验证长度值是否匹配实际数据长度 return true }跨平台兼容性问题Java 报错InvalidKeySpecException解决方案// 确保PKCS#8格式符合标准特别是版本号和算法标识 let standardPKCS8Header Data([ 0x30, 0x82, 0x04, 0xA3, // SEQUENCE 0x02, 0x01, 0x00, // INTEGER (version 0) 0x30, 0x0D, // SEQUENCE (algorithm) 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, // OID 0x05, 0x00, // NULL 0x04, 0x82, 0x04, 0x8B // OCTET STRING ])性能优化检查表[ ] 预计算静态 ASN.1 结构[ ] 使用安全且高效的内存操作[ ] 实现批量处理并发机制[ ] 避免不必要的密钥复制操作[ ] 使用合适的缓冲区大小安全审计要点[ ] 确保敏感数据及时从内存清除[ ] 验证所有输入数据的有效性[ ] 实现完善的错误处理[ ] 记录关键安全事件[ ] 定期更新加密算法参数13. 进阶话题支持其他密钥类型上述方案主要针对 RSA 密钥但 PKCS#8 支持多种密钥类型。以下是扩展支持的方法ECC 密钥支持func convertECKeyToPKCS8(privateKey: SecKey) throws - String { // 获取原始密钥数据 var error: UnmanagedCFError? guard let pkcs1Data SecKeyCopyExternalRepresentation(privateKey, error) as Data? else { throw error!.takeRetainedValue() as Error } // ECC 特定算法标识 let ecOID: Data if #available(iOS 10.0, *) { guard let attributes SecKeyCopyAttributes(privateKey) as? [String: Any], let keySize attributes[kSecAttrKeySizeInBits as String] as? Int else { throw KeyConversionError.invalidKeyAttributes } // 根据密钥长度选择正确的OID switch keySize { case 256: ecOID Data([0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]) case 384: ecOID Data([/* 对应OID */]) default: throw KeyConversionError.unsupportedKeySize } } else { throw KeyConversionError.unsupportedPlatform } // 构建PKCS8结构 let version Data([0x02, 0x01, 0x00]) // 版本0 let pkcs8Data version ecOID Data([0x04]) derLength(for: pkcs1Data) pkcs1Data let finalData Data([0x30]) derLength(for: pkcs8Data) pkcs8Data // 转换为PEM let base64Content finalData.base64EncodedString(options: .lineLength64Characters) return -----BEGIN PRIVATE KEY-----\n\(base64Content)\n-----END PRIVATE KEY----- }多算法支持框架enum KeyAlgorithm { case rsa case ecc(curve: ECCurve) enum ECCurve { case p256 case p384 case p521 } var algorithmOID: Data { switch self { case .rsa: return Data([0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00]) case .ecc(let curve): switch curve { case .p256: return Data([/* P-256 OID */]) case .p384: return Data([/* P-384 OID */]) case .p521: return Data([/* P-521 OID */]) } } } } struct KeyConverter { let algorithm: KeyAlgorithm func convertToPKCS8(privateKey: SecKey) throws - String { // 通用转换逻辑使用algorithm.algorithmOID } }14. 密钥转换的性能基准测试了解不同实现的性能特征对于选择合适方案至关重要func runPerformanceBenchmark() { let keySizes [1024, 2048, 4096] let iterations 100 for size in keySizes { print(\n测试密钥大小: \(size) bits) // 生成测试密钥 let testKey generateTestKey(size: size) // 测试方案一 var time measureTime { for _ in 0..iterations { _ try? convertToPKCS8(privateKey: testKey) } } print(方案一平均时间: \(time/Double(iterations))秒) // 测试方案二 time measureTime { for _ in 0..iterations { _ try? convertToPKCS8UsingSecurityFramework(privateKey: testKey) } } print(方案二平均时间: \(time/Double(iterations))秒) } } private func measureTime(_ block: () - Void) - Double { let start CFAbsoluteTimeGetCurrent() block() return CFAbsoluteTimeGetCurrent() - start }典型结果可能如下密钥大小方案一平均时间方案二平均时间1024位0.002秒0.005秒2048位0.004秒0.008秒4096位0.015秒0.025秒15. 安全考虑与最佳实践内存安全处理defer { // 确保敏感数据被清除 privateKeyData.withUnsafeMutableBytes { (buffer: UnsafeMutableRawBufferPointer) in memset(buffer.baseAddress!, 0, buffer.count) } }密钥使用权限控制let accessControl SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.privateKeyUsage, .userPresence], nil)! let keyAttributes: [String: Any] [ kSecAttrAccessControl as String: accessControl, kSecAttrIsExtractable as String: true, kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave ]审计日志记录func logKeyOperation(_ operation: String, success: Bool, metadata: [String: Any] [:]) { let logEntry: [String: Any] [ timestamp: Date().timeIntervalSince1970, operation: operation, success: success, device: UIDevice.current.identifierForVendor?.uuidString ?? unknown, metadata: metadata ] // 安全地记录到文件或发送到服务器 // 注意: 不应记录实际的密钥内容 }防篡改机制func verifyKeyIntegrity(key: SecKey) - Bool { guard let publicKey SecKeyCopyPublicKey(key) else { return false } let testData Data(count: 32) var error: UnmanagedCFError? guard let signature SecKeyCreateSignature( key, .rsaSignatureMessagePKCS1v15SHA256, testData as CFData, error) else { return false } let verifyStatus SecKeyVerifySignature( publicKey, .rsaSignatureMessagePKCS1v15SHA256, testData as CFData, signature, error) return verifyStatus }16. 密钥转换在项目中的典型应用场景与后端服务通信struct APIClient { private let cryptoService: CryptoService func sendEncryptedRequest(_ request: Request) throws - Response { // 1. 获取当前密钥 let privateKey try keychainStorage.retrieveKey(identifier: currentKey) // 2. 转换为PKCS#8格式 let pemKey try cryptoService.exportKey(privateKey: privateKey) // 3. 使用密钥签名请求 let signature try cryptoService.sign(request.data, with: privateKey) // 4. 发送到服务器 let payload Payload(data: request.data, key: pemKey, signature: signature) return try post(to: endpoint, payload: payload) } }密钥备份与恢复class KeyBackupManager { func backupKey(privateKey: SecKey, to url: URL) throws { // 转换为PKCS#8 PEM格式 let pemKey try convertToPKCS8(privateKey: privateKey) // 加密备份文件 let encryptedData try encryptData(Data(pemKey.utf8)) // 写入安全位置 try encryptedData.write(to: url, options: .completeFileProtection) } func restoreKey(from url: URL) throws - SecKey { // 读取并解密 let encryptedData try Data(contentsOf: url) let pemKey try decryptData(encryptedData) // 从PEM导入 return try importPKCS8Key(pemKey) } }多平台密钥共享struct CrossPlatformKeySharer { func shareKey(privateKey: SecKey, with devices: [Device]) throws { // 转换为通用格式 let pemKey try convertToPKCS8(privateKey: privateKey) // 为每个设备加密 let encryptedKeys try devices.map { device in try encryptKey(pemKey, for: device) } // 分发密钥 try distributeEncryptedKeys(encryptedKeys) } private func encryptKey(_ key: String, for device: Device) throws - Data { // 使用设备公钥加密 let algorithm: SecKeyAlgorithm .rsaEncryptionOAEPSHA256 guard SecKeyIsAlgorithmSupported(device.publicKey, .