Swift中使用Security框架DH交换EC密钥后私钥恢复失败(返回nil)
解决Swift中ECDH密钥交换后无法从CFData恢复私钥的问题
兄弟,我太懂你这个坑了!之前我在做ECDH加解密的时候也踩过一模一样的雷——你拿到的shared1/shared2根本不是可以直接恢复的非对称私钥,这就是为啥你调用恢复API会返回nil的核心原因!
问题根源:对ECDH共享密钥的误解
ECDH(椭圆曲线迪菲-赫尔曼)交换后生成的sharedSecret是对称密钥原材料,不是非加密体系里的私钥。它只是一个字节序列,需要经过KDF(密钥派生函数)处理后,才能变成可用的对称加密密钥(比如AES密钥),不能直接用私钥恢复的API去解析它。
正确的实现步骤
我结合你的代码片段,给你梳理完整的正确流程:
1. 生成EC密钥对并计算共享密钥材料
首先补全密钥生成和共享密钥计算的代码,确保拿到正确的密钥材料:
import Security import CryptoKit // 定义密钥属性 let attributes: [String: Any] = [ kSecAttrKeySizeInBits as String: 256, kSecAttrKeyType as String: kSecAttrKeyTypeEC, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecPrivateKeyAttrs as String: [kSecAttrIsPermanent as String: false] ] var error: Unmanaged<CFError>? // 生成本地密钥对 guard let localPrivateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { fatalError("生成本地私钥失败: \(error!.takeRetainedValue())") } let localPublicKey = SecKeyCopyPublicKey(localPrivateKey)! // 模拟获取对方公钥(实际场景中从网络接收对方的公钥数据) // 这里假设我们已经拿到了对方公钥的Data guard let peerPublicKey = SecKeyCreateWithData(peerPublicKeyData, attributes as CFDictionary, &error) else { fatalError("解析对方公钥失败: \(error!.takeRetainedValue())") } // 计算ECDH共享密钥材料 guard let sharedSecretData = SecKeyCopyKeyExchangeResult( localPrivateKey, .ecdhKeyExchangeStandard, peerPublicKey, attributes as CFDictionary, &error ) as Data? else { fatalError("计算共享密钥失败: \(error!.takeRetainedValue())") }
2. 用KDF派生可用的对称密钥
拿到sharedSecretData后,我们用HKDF(基于哈希的密钥派生函数)把它转换成标准的AES密钥:
// 自定义盐和信息字段(可以根据业务需求调整,增强密钥唯一性) let salt = Data("MyECDHSalt".utf8) let info = "ECDH-AES-256-Encryption".data(using: .utf8)! // 使用SHA256作为哈希算法派生256位AES密钥 let hkdf = HKDF<SHA256>( inputKeyMaterial: sharedSecretData, salt: salt, info: info ) let aes256Key = hkdf.deriveSymmetricKey(size: 256)
3. 用派生的对称密钥完成加解密
现在就可以用这个AES密钥来加密和解密字符串了,推荐用CryptoKit的AES-GCM模式(自带认证,更安全):
// 加密字符串 func encryptString(_ plainText: String, with key: SymmetricKey) throws -> Data { let plainData = plainText.data(using: .utf8)! let sealedBox = try AES.GCM.seal(plainData, using: key) // 返回包含密文、IV和认证标签的组合数据 return sealedBox.combined! } // 解密数据 func decryptData(_ encryptedData: Data, with key: SymmetricKey) throws -> String { let sealedBox = try AES.GCM.SealedBox(combined: encryptedData) let decryptedData = try AES.GCM.open(sealedBox, using: key) guard let plainText = String(data: decryptedData, encoding: .utf8) else { throw NSError(domain: "ECDH解密失败", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法将解密数据转换为字符串"]) } return plainText }
最后再划个重点
别再把ECDH的共享密钥材料当成私钥来处理啦!它的作用是给双方生成一个相同的对称密钥原材料,经过KDF处理后,就可以用对称加密算法来完成数据的加解密了。
内容的提问来源于stack exchange,提问作者Dany
相关产品推荐
相关产品推荐

