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

替换ToByteArray为ExportSubjectPublicKeyInfo后CngKey.Import报错如何修复?

修复ECDiffieHellman公钥导出导入的参数错误问题

你遇到的错误核心是公钥格式不匹配:

  • ExportSubjectPublicKeyInfo()导出的是标准X.509 SubjectPublicKeyInfo(SPKI)格式的公钥,属于跨平台通用格式。
  • 而CngKey.Import指定的CngKeyBlobFormat.EccPublicBlob是Windows CNG框架特有的公钥BLOB格式,两者结构完全不同,因此导入时会触发参数错误。

以下是两种可行的修复方案:

方案一:直接使用ECDH标准导入方法(推荐,跨平台)

无需借助CngKey,直接用ECDiffieHellmanCng.ImportSubjectPublicKeyInfo导入SPKI格式公钥,再派生共享密钥。修改后代码如下:

public static void Main()
{
    var client = new ECDiffieHellmanCng();
    client.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
    client.HashAlgorithm = CngAlgorithm.Sha256;

    var clientPublicKey = client.PublicKey.ExportSubjectPublicKeyInfo();

    var server = new ECDiffieHellmanCng();
    server.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
    server.HashAlgorithm = CngAlgorithm.Sha256;

    var serverPublicKey = server.PublicKey.ExportSubjectPublicKeyInfo();

    var enc = Encrypt(client, serverPublicKey, "Hello");
    Console.WriteLine(Convert.ToBase64String(enc.Item1));

    var dec = Decrypt(server, clientPublicKey, enc.Item2, enc.Item1);
    Console.WriteLine(Encoding.UTF8.GetString(dec));
}

public static (byte[], byte[]) Encrypt(ECDiffieHellmanCng client, byte[] serverPublicKey, string plainText)
{
    // 直接导入SPKI格式公钥
    using var serverEc = ECDiffieHellmanCng.ImportSubjectPublicKeyInfo(serverPublicKey, out _);
    var sharedSecret = client.DeriveKeyMaterial(serverEc.PublicKey);

    using var aes = Aes.Create();
    aes.Key = sharedSecret;
    aes.GenerateIV();
    aes.Padding = PaddingMode.PKCS7;
    var plainBytes = Encoding.UTF8.GetBytes(plainText);
    using var encryptor = aes.CreateEncryptor();
    var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

    return (cipherBytes, aes.IV);
}

public static byte[] Decrypt(ECDiffieHellmanCng server, byte[] clientPublicKey, byte[] iv, byte[] cipher)
{
    // 直接导入SPKI格式公钥
    using var clientEc = ECDiffieHellmanCng.ImportSubjectPublicKeyInfo(clientPublicKey, out _);
    var sharedSecret = server.DeriveKeyMaterial(clientEc.PublicKey);

    using var aes = Aes.Create();
    aes.Padding = PaddingMode.PKCS7;
    aes.IV = iv;
    aes.Key = sharedSecret;

    using var decryptor = aes.CreateDecryptor();
    var plain = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);

    return plain;
}

方案二:将SPKI格式转换为CNG BLOB格式(仅Windows适用)

如果必须保留CngKey.Import的逻辑,可以先把SPKI格式公钥导入临时ECDH对象,再导出为CNG的EccPublicBlob格式后再导入:

public static (byte[], byte[]) Encrypt(ECDiffieHellmanCng client, byte[] serverPublicKey, string plainText)
{
    // 先导入SPKI,再导出为CNG BLOB格式
    using var tempEc = ECDiffieHellmanCng.ImportSubjectPublicKeyInfo(serverPublicKey, out _);
    byte[] cngBlob = tempEc.PublicKey.ExportECDHPublicKey();
    
    var cngKey = CngKey.Import(cngBlob, CngKeyBlobFormat.EccPublicBlob);
    var sharedSecret = client.DeriveKeyMaterial(cngKey);

    // AES加密逻辑不变
    using var aes = Aes.Create();
    aes.Key = sharedSecret;
    aes.GenerateIV();
    aes.Padding = PaddingMode.PKCS7;
    var plainBytes = Encoding.UTF8.GetBytes(plainText);
    using var encryptor = aes.CreateEncryptor();
    var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

    return (cipherBytes, aes.IV);
}

// Decrypt方法做同样修改
public static byte[] Decrypt(ECDiffieHellmanCng server, byte[] clientPublicKey, byte[] iv, byte[] cipher)
{
    using var tempEc = ECDiffieHellmanCng.ImportSubjectPublicKeyInfo(clientPublicKey, out _);
    byte[] cngBlob = tempEc.PublicKey.ExportECDHPublicKey();
    
    var cngKey = CngKey.Import(cngBlob, CngKeyBlobFormat.EccPublicBlob);
    var sharedSecret = server.DeriveKeyMaterial(cngKey);

    // AES解密逻辑不变
    using var aes = Aes.Create();
    aes.Padding = PaddingMode.PKCS7;
    aes.IV = iv;
    aes.Key = sharedSecret;

    using var decryptor = aes.CreateDecryptor();
    var plain = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);

    return plain;
}

方案说明

  • 方案一符合微软跨平台建议,代码简洁且兼容性更强,优先推荐。
  • 方案二仅适用于Windows环境,适合必须依赖CngKey的特定场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:32:18