iOS 12及以下版本如何实现sharedSecretFromKeyAgreement功能?
没错,CryptoKit确实把ECDH密钥协商简化到了几行代码,但在iOS 12及更早版本,我们得依靠Security框架来实现同样的功能——毕竟这是Apple在CryptoKit之前提供的底层密码学工具。下面我会给你完整的实现方案,包括密钥对生成、公钥交换、共享密钥计算,完全对标你给出的CryptoKit示例。
核心思路
ECDH密钥协商的本质没变:双方各自生成椭圆曲线(这里用P256,和CryptoKit示例一致)的公私钥对,交换公钥后,用自己的私钥和对方的公钥计算出相同的共享密钥。在Security框架里,我们需要通过SecKey相关API来完成这些步骤,重点是正确配置密钥属性,以及处理密钥的导入导出(如果需要跨设备/传输公钥的话)。
完整示例代码
先上代码,和你的CryptoKit例子一一对应,方便你对比:
1. 定义辅助工具函数(处理错误和密钥属性)
import Security // 处理Security框架的OSStatus错误 func throwIfError(_ status: OSStatus, message: String) throws { guard status == errSecSuccess else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(status), userInfo: [NSLocalizedDescriptionKey: message]) } } // 生成P256椭圆曲线密钥对 func generateECDHKeyPair() throws -> (privateKey: SecKey, publicKey: SecKey) { let attributes: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeEC, kSecAttrKeySizeInBits: 256, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrECDSACurve: kSecP256KeyCurve // 和CryptoKit的P256对应 ] var publicKey: SecKey? var privateKey: SecKey? let status = SecKeyCreatePair(attributes as CFDictionary, &privateKey, &publicKey) try throwIfError(status, message: "Failed to generate ECDH key pair") guard let privKey = privateKey, let pubKey = publicKey else { throw NSError(domain: "ECDHError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Generated key pair is nil"]) } return (privKey, pubKey) } // 用自己的私钥和对方的公钥计算共享密钥 func calculateSharedSecret(privateKey: SecKey, peerPublicKey: SecKey) throws -> Data { var error: Unmanaged<CFError>? guard let sharedSecretData = SecKeyCreateKeyExchangeResult( privateKey, .ecdhKeyExchangeStandard, peerPublicKey, [kSecKeyKeyExchangeParameterRequestedSize: 32] as CFDictionary, // 生成32字节共享密钥,和CryptoKit默认一致 &error ) as Data? else { throw error!.takeRetainedValue() as Error } return sharedSecretData }
2. 模拟双方密钥协商(对应你的CryptoKit示例)
do { // Alice生成密钥对 let (alicePrivateKey, alicePublicKey) = try generateECDHKeyPair() // Eileen生成密钥对 let (eileenPrivateKey, eileenPublicKey) = try generateECDHKeyPair() // Alice用自己的私钥和Eileen的公钥计算共享密钥 let shared1 = try calculateSharedSecret(privateKey: alicePrivateKey, peerPublicKey: eileenPublicKey) // Eileen用自己的私钥和Alice的公钥计算共享密钥 let shared2 = try calculateSharedSecret(privateKey: eileenPrivateKey, peerPublicKey: alicePublicKey) // 验证两个共享密钥是否一致 if shared1 == shared2 { print("shared keys are equal") } else { print("shared keys are NOT equal") } } catch { print("Error: \(error.localizedDescription)") }
关键细节说明
- 曲线选择:示例中用了
kSecP256KeyCurve,和CryptoKit的P256完全匹配,保证了跨版本的兼容性。 - 共享密钥长度:CryptoKit的
sharedSecretFromKeyAgreement默认生成32字节的共享密钥,所以我们在SecKeyCreateKeyExchangeResult里指定了kSecKeyKeyExchangeParameterRequestedSize: 32,保持一致。 - 公钥传输注意事项:如果需要把公钥传给对方(比如跨设备),你需要把
SecKey导出为Data(比如DER格式),对方再导入为SecKey。可以用SecKeyCopyExternalRepresentation导出,SecKeyCreateWithData导入,记得配置正确的公钥属性。
和CryptoKit的差异
- Security框架的API更底层,需要手动处理错误码和密钥属性,不如CryptoKit简洁。
- Security框架返回的共享密钥是原始Data,而CryptoKit返回的是
SharedSecret对象,你可以根据需要对原始Data做进一步处理(比如用HKDF派生密钥,这一步在两个框架里都需要额外实现)。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

