You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 12及以下版本如何实现sharedSecretFromKeyAgreement功能?

iOS 12及以下版本实现ECDH密钥协商(替代CryptoKit的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:27:51