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

iOS Swift中如何利用服务器十六进制ECDH公钥生成共享密钥

解决服务器十六进制EC公钥转SecKey并生成共享密钥问题

步骤1:将十六进制公钥转为Data

首先把服务器返回的十六进制字符串转成二进制Data,注意:如果服务器返回的公钥是仅包含x、y坐标拼接的64字节十六进制(无04前缀),需要先补上04前缀——Apple的SecKey要求EC公钥遵循X9.63未压缩格式(开头为04,后续接32字节x坐标+32字节y坐标,共65字节)。

// 十六进制转Data工具方法
func hexStringToData(_ hexString: String) -> Data? {
    let cleanedStr = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
    var data = Data(capacity: cleanedStr.count / 2)
    var index = cleanedStr.startIndex
    while index < cleanedStr.endIndex {
        let nextIndex = cleanedStr.index(index, offsetBy: 2)
        guard let byte = UInt8(cleanedStr[index..<nextIndex], radix: 16) else {
            return nil
        }
        data.append(byte)
        index = nextIndex
    }
    // 补04前缀(如果是64字节的坐标拼接数据)
    if data.count == 64 {
        var prefixedData = Data([0x04])
        prefixedData.append(data)
        return prefixedData
    }
    return data
}

步骤2:构造公钥属性字典

属性需和你本地生成密钥对时的参数完全匹配,保证密钥类型、大小、曲线一致:

let publicKeyAttrs: [String: Any] = [
    kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
    kSecAttrKeySizeInBits as String: 256,
    kSecAttrIsPermanent as String: false
]

步骤3:生成SecKey实例

用SecKeyCreateWithData将二进制Data转换为SecKey对象:

var error: Unmanaged<CFError>?
// serverHexPublicKey为服务器返回的十六进制公钥字符串
guard let serverPubKeyData = hexStringToData(serverHexPublicKey),
      let serverPublicKey = SecKeyCreateWithData(serverPubKeyData as CFData,
                                                 publicKeyAttrs as CFDictionary,
                                                 &error) else {
    if let err = error?.takeRetainedValue() {
        print("公钥转换失败:\(err.localizedDescription)")
    }
    return
}

步骤4:生成共享密钥

用本地私钥和转换后的服务器公钥执行ECDH密钥交换,逻辑和你本地测试的一致:

let algorithm: SecKeyAlgorithm = .ecdhKeyExchangeStandardX963SHA256
let exchangeParams: [String: Any] = [
    SecKeyKeyExchangeParameter.requestedSize.rawValue as String: 32
]

guard let sharedSecret = SecKeyCopyKeyExchangeResult(localPrivateKey,
                                                    algorithm,
                                                    serverPublicKey,
                                                    exchangeParams as CFDictionary,
                                                    &error) as Data? else {
    if let err = error?.takeRetainedValue() {
        print("共享密钥生成失败:\(err.localizedDescription)")
    }
    return
}

print("服务器端共享密钥:\(sharedSecret.base64EncodedString())")

常见排查点

  • 检查十六进制字符串是否有多余空格、特殊字符,确保格式正确。
  • 确认服务器公钥的曲线和本地一致(你用的是P-256曲线,对应256位密钥),若服务器用P-384等其他曲线,需修改kSecAttrKeySizeInBits为对应值。
  • 若服务器返回的是压缩格式公钥(33字节,开头为02或03),需先自行解压为未压缩格式(Apple SecKey不直接支持压缩EC公钥)。

内容的提问来源于stack exchange,提问作者Shreedharshan Msd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 08:13:24