如何使用Windows上.net框架中的ECC X509证书的公钥加密数据?

时间:2017-11-04 23:21:36

标签: c# .net encryption cryptography elliptic-curve

我正在使用:

  • Windows 10(版本1709,OS Build 17025.1000)
  • .net framework 4.7
  • VS 2017(版本:15.3.5)

这是我做的:

  1. 使用OpenSSL获得自签名ECC证书,并在https://gist.github.com/sidshetye/4759690脚本中修改了步骤并进行了修改:

    a)在256位素数域上使用NIST / P-256曲线

    b)使用SHA-256

  2. 将证书从文件(在上一步中生成)加载到X509Certificate2对象

  3. 将PFX文件导入Windows信任存储区(用于测试)。这很成功。

  4. 检查导入的证书会将公钥字段显示为“ECC(256位)'和公共关键参数为' ECDSA_P256'。
  5. 接下来试图找出如何使用此证书进行加密。
  6. 我陷入了最后一步,因为使用X509Certificate2对象的所有示例主要仅使用RSA而我使用的是ECC证书。对于RSA证书,X509Certificate2上有 GetRSAPublicKey 扩展方法,RSA类具有加密方法。但是ECC证书没有这种方法。

    接下来,我偶然发现了这篇文章(Load a Certificate Using X509Certificate2 with ECC Public Key)并尝试了以下内容(尽管为什么ECC证书公钥被强制转换为RSA类型似乎很奇怪):

    RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key
    

    我遇到以下异常:不支持证书密钥算法。

    接下来,我偶然发现了这篇帖子(Importing ECC-based certificate from the Windows Certificate Store into CngKey),它基本上试图创建CNGKey类型并用它实例化ECDsaCng。但是,即使我可以使用ECDiffieHellmanCng,也没有加密方法。

    所以我不确定如何进一步使用ECC X509证书的公钥来加密数据。

2 个答案:

答案 0 :(得分:2)

背景

非对称算法有三个不同的目的(我知道)

  1. 加密
    • RSA是唯一的"标准"可以直接执行此操作的算法。
  2. 签名
    • RSA
    • DSA
    • ECDSA
    • ElGamal Signature
  3. 重要协议
    • Diffie-Hellman(DH)
    • ECDH
    • ElGamal加密(非对称启动阶段)
    • MQV
    • ECMQV
  4. 由于RSA加密是空间有限的,并且对于90年代的计算机来说很难,RSA加密的主要用途是" Key Transfer",也就是说& #34;加密消息"只是DES / 3DES的对称加密密钥(AES尚未发明) - https://tools.ietf.org/html/rfc2313#section-8

    密钥协商(或转移)方案必须始终与协议/方案相结合,以产生加密操作。这些计划包括

    • TLS(即SSL)
    • CMS或S / MIME encrypted-data
    • IES(综合加密方案)
    • ECIES(椭圆曲线集成加密方案)
    • ElGamal加密(整体)
    • PGP加密

    所以你可能想要的是ECIES。

    ECIES.Net

    目前(.NET Framework 4.7.1,.NET Core 2.0),不支持从.NET中的证书中获取ECDiffieHellman对象。

    游戏结束了,对吗?好吧,可能不是。除非携带ECDH密钥的证书明确使用id-ecDH算法标识符(相对于更标准的id-ecc密钥),否则它可以作为ECDSA打开。然后,你可以强迫该对象成为ECDH:

    using (ECDsa ecdsa = cert.GetECDsaPublicKey())
    {
        return ECDiffieHellman.Create(ecdsa.ExportParameters(false));
    }
    

    (如果密钥是可导出的,可以对私钥进行类似的操作,否则需要复杂的东西,但你不应该需要它)

    让我们继续关注收件人的公共对象:

    ECDiffieHellmanPublicKey recipientPublic = GetECDHFromCertificate(cert).PublicKey;
    ECCurve curve = recipientPublic.ExportParameters().Curve;
    

    现在我们转向http://www.secg.org/sec1-v2.pdf第5.1节(椭圆曲线集成加密方案)

    设置

    1. 选择ANSI-X9.63-KDF,SHA-2-256作为哈希函数。
    2. 选择HMAC-SHA-256-256。
    3. 在CBC模式下选择AES-256。
    4. 选择Elliptic Curve Diffie-Hellman Primitive。
    5. 您已选择secp256r1。
    6. 硬编码。完成。
    7. 点压缩令人讨厌,选择不使用它。
    8. 我省略了SharedInfo。这可能让我成为一个坏人。
    9. 不使用XOR,N / A.
    10. 加密

      1. 在右侧曲线上制作一个短暂的密钥。

        ECDiffieHellman ephem = ECDiffieHellman.Create(curve);
        
      2. 我们决定不。

        ECParameters ephemPublicParams = ephem.ExportParameters(false);
        int pointLen = ephemPublicParams.Q.X.Length;
        byte[] rBar = new byte[pointLen * 2 + 1];
        rBar[0] = 0x04;
        Buffer.BlockCopy(ephemPublicParams.Q.X, 0, rBar, 1, pointLen);
        Buffer.BlockCopy(ephemPublicParams.Q.Y, 0, rBar, 1 + pointLen, pointLen);
        
      3. 不能直接这样做,继续前进。

      4. 不能直接这样做,继续前进。
      5. 由于我们在这里控制,我们只做3,4,5和6作为一件事。
      6. KDF时间。

        // This is why we picked AES 256, HMAC-SHA-2-256(-256) and SHA-2-256,
        // the KDF is dead simple.
        byte[] ek = ephem.DeriveKeyFromHash(
            recipientPublic,
            HashAlgorithmName.SHA256,
            null,
            new byte[] { 0, 0, 0, 1 });
        
        byte[] mk = ephem.DeriveKeyFromHash(
            recipientPublic,
            HashAlgorithmName.SHA256,
            null,
            new byte[] { 0, 0, 0, 2 });
        
      7. 加密内容。

        byte[] em;
        
        // ECIES uses AES with the all zero IV. Since the key is never reused,
        // there's not risk in that.
        using (Aes aes = Aes.Create())
        using (ICryptoTransform encryptor = aes.CreateEncryptor(ek, new byte[16]))
        {
            if (!encryptor.CanTransformMultipleBlocks)
            {
                throw new InvalidOperationException();
            }
        
            em = encryptor.TransformFinalBlock(message, 0, message.Length);
        }
        
      8. MAC it

        byte[] d;
        
        using (HMAC hmac = new HMACSHA256(mk))
        {
            d = hmac.ComputeHash(em);
        }
        
      9. 完成

        // Either
        return Tuple.Create(rBar, em, d);
        // Or
        return rBar.Concat(em).Concat(d).ToArray();
        
      10. 解密

        留给读者练习。

答案 1 :(得分:0)

要从证书中获取ECDiffieHellman私钥,请使用以下方法:

  • 安装NuGet软件包Security.Cryptography(CLR安全性)。 (该软件包位于MIT license下。)
  • 使用以下扩展方法获取CngKey实例: CngKey cngKey = certificate.GetCngPrivateKey(); (注意:.NET本身支持的扩展方法certificate.GetECDsaPrivateKey()返回一个ECDsaCng实例;没有扩展方法可以返回ECDiffieHellmanCng。)
  • cngKey实例可用于创建ECDsaCngECDiffieHellmanCng实例: var sa = new ECDsaCng(cngKey); var sa = new ECDiffieHellmanCng(cngKey);