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

如何用ECDSA密钥对执行ECDH生成共享密钥?

C# 使用ECDSA密钥对执行ECDH生成共享密钥的实现方案

我需要用ECDSA密钥对执行ECDH算法获取Alice和Bob的共享密钥,但全网找不到可用的C#示例,且给定的ECDSA密钥不符合ANS.1标准,常规Microsoft或Bouncy Castle的标准密钥加载方式无法兼容。由于通信渠道公开,只能采用ECDH而非DHKE,经过多次尝试后,我完成了可行的实现方案,分享如下:

给定密钥对:

string alicePrivateKeyHex = "6105a3237a98d2843a35ac35fb63ba2cfbde4deabc97faa9664f42762103e0de";
string alicePublicKeyHex = "04cadf4b345e6f62a858fb2c25509bace24d81fd600dfb3aa40dcf021902bfc012ba1a8c2364b6323b71ab659891ef856cba546b58c881311fafc75103111a5bdb";

string bobPrivateKeyHex = "7034a8fe220fa73704be34e0fdf82d5671598a19c49f71cec3bce5cee5b30e59";
string bobPublicKeyHex = "04e7526b124f22c8549a2b91783b34a8df067a74df9b601447bc7561a4e7eaea7a652582d1510b59365a7684195f99e4464a6b612441e5a8c2b63664d957384ba9";

实现步骤与代码

这里采用Bouncy Castle库处理椭圆曲线运算,需要先通过NuGet安装BouncyCastle.Crypto包。核心思路是直接从原始字节加载密钥参数,绕过标准ANS.1格式解析:

using System;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;

class EcdhExample
{
    static void Main()
    {
        // 采用secp256r1(P-256)曲线参数,匹配给定密钥的长度
        var ecParams = SecNamedCurves.GetByName("secp256r1");
        var domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H);

        // 十六进制转字节数组
        byte[] alicePrivKeyBytes = HexStringToByteArray(alicePrivateKeyHex);
        byte[] alicePubKeyBytes = HexStringToByteArray(alicePublicKeyHex);
        byte[] bobPrivKeyBytes = HexStringToByteArray(bobPrivateKeyHex);
        byte[] bobPubKeyBytes = HexStringToByteArray(bobPublicKeyHex);

        // Alice用自己的私钥和Bob的公钥计算共享密钥
        BigInteger alicePrivKey = new BigInteger(1, alicePrivKeyBytes);
        ECPrivateKeyParameters alicePrivateParams = new ECPrivateKeyParameters(alicePrivKey, domainParams);
        ECPublicKeyParameters bobPublicParams = LoadPublicKeyFromBytes(bobPubKeyBytes, domainParams);
        byte[] aliceSharedSecret = ComputeSharedSecret(alicePrivateParams, bobPublicParams);

        // Bob用自己的私钥和Alice的公钥计算共享密钥
        BigInteger bobPrivKey = new BigInteger(1, bobPrivKeyBytes);
        ECPrivateKeyParameters bobPrivateParams = new ECPrivateKeyParameters(bobPrivKey, domainParams);
        ECPublicKeyParameters alicePublicParams = LoadPublicKeyFromBytes(alicePubKeyBytes, domainParams);
        byte[] bobSharedSecret = ComputeSharedSecret(bobPrivateParams, alicePublicParams);

        // 验证双方共享密钥一致
        Console.WriteLine("Alice计算的共享密钥(十六进制):");
        Console.WriteLine(ByteArrayToHexString(aliceSharedSecret));
        Console.WriteLine("\nBob计算的共享密钥(十六进制):");
        Console.WriteLine(ByteArrayToHexString(bobSharedSecret));
        Console.WriteLine("\n密钥一致性验证:" + (Convert.ToBase64String(aliceSharedSecret) == Convert.ToBase64String(bobSharedSecret)));
    }

    // 从原始公钥字节(04开头的未压缩格式)加载EC公钥参数
    static ECPublicKeyParameters LoadPublicKeyFromBytes(byte[] pubKeyBytes, ECDomainParameters domainParams)
    {
        // 未压缩公钥格式:04 + X(32字节) + Y(32字节)
        if (pubKeyBytes.Length != 65 || pubKeyBytes[0] != 0x04)
            throw new ArgumentException("仅支持未压缩格式的EC公钥(04开头,65字节)");

        BigInteger x = new BigInteger(1, pubKeyBytes, 1, 32);
        BigInteger y = new BigInteger(1, pubKeyBytes, 33, 32);
        ECPoint pubPoint = domainParams.Curve.CreatePoint(x, y);
        return new ECPublicKeyParameters(pubPoint, domainParams);
    }

    // 计算ECDH共享密钥
    static byte[] ComputeSharedSecret(ECPrivateKeyParameters privateParams, ECPublicKeyParameters publicParams)
    {
        IBasicAgreement agreement = AgreementUtilities.GetBasicAgreement("ECDH");
        agreement.Init(privateParams);
        BigInteger sharedBigInt = agreement.CalculateAgreement(publicParams);
        // 将BigInteger转换为32字节的大端字节数组(补前导零)
        return sharedBigInt.ToByteArrayUnsigned().PadLeft(32, 0);
    }

    // 十六进制字符串转字节数组
    static byte[] HexStringToByteArray(string hex)
    {
        hex = hex.Replace("-", "").Replace(" ", "");
        byte[] bytes = new byte[hex.Length / 2];
        for (int i = 0; i < bytes.Length; i++)
        {
            bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return bytes;
    }

    // 字节数组转十六进制字符串
    static string ByteArrayToHexString(byte[] bytes)
    {
        return BitConverter.ToString(bytes).Replace("-", "").ToLower();
    }
}

说明

  • 给定的密钥基于secp256r1(P-256)曲线,代码中明确指定了该曲线参数以匹配密钥长度
  • 直接从原始十六进制字节加载私钥和公钥,绕过了标准ANS.1/DER/PEM格式的解析限制
  • 双方计算出的共享密钥完全一致,符合ECDH密钥协商的要求
  • 实际应用中建议对共享密钥再进行一次KDF(密钥派生函数)处理,比如使用HKDF生成最终的会话密钥

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:17:51