我正在使用:
- Windows 10(版本 1709,操作系统内部版本 17025.1000)
- .net 框架 4.7
- VS 2017(版本:15.3.5)
这是我做的:
使用 OpenSSL 和在 https://gist.github.com/sidshetye/4759690 的脚本中概述的步骤获得自签名 ECC 证书修改后:
a) 在 256 位素数域上使用 NIST/P-256 曲线
b) 使用 SHA-256
将证书从文件(在上一步中生成)加载到 X509Certificate2 对象中
将 PFX 文件导入 Windows 信任库(用于测试)。这是成功的。
- 检查导入的证书显示公钥字段为“ECC(256 位)”,公钥参数为“ECDSA_P256”。
- 接下来尝试弄清楚如何使用此证书进行加密。
我卡在了最后一步,因为所有使用 X509Certificate2 对象的示例主要只使用 RSA,而我使用的是 ECC 证书。对于RSA证书,X509Certificate2上有一个GetRSAPublicKey扩展方法,RSA类有Encrypt方法。但是ECC证书没有这样的方法。
接下来,我无意中发现了这篇文章 ( Load a Certificate Using X509Certificate2 with ECC Public Key ) 并尝试了以下内容(尽管为什么 ECC 证书公钥被强制转换为 RSA 类型看起来很奇怪):
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key
我遇到以下异常:不支持证书 key 算法。
接下来我无意中发现了这篇文章 ( Importing ECC-based certificate from the Windows Certificate Store into CngKey ),它基本上试图创建 CNGKey 类型并用它实例化 ECDsaCng。然而,即使我可以使用 ECDiffieHellmanCng 做到这一点,它也没有加密方法。
所以我不太确定如何才能进一步使用 ECC X509 证书的公钥来加密数据。
最佳答案
###背景
非对称算法具有三种不同的目的(据我所知)
- 加密
- RSA 是唯一可以直接执行此操作的“标准”算法。
- 签名
- 自适应搜索
- 动态搜索广告
- ECDSA
- ElGamal 签名
- key 协议(protocol)
- 迪菲-赫尔曼 (DH)
- ECDH
- ElGamal 加密(非对称启动阶段)
- MQV
- ECMQV
由于RSA加密是有空间限制的,90年代的计算机很难用,所以RSA加密主要用在“Key Transfer”,也就是说“加密信息”只是DES/的对称加密 key 3DES(AES 尚未发明)- https://www.rfc-editor.org/rfc/rfc2313#section-8 .
key 协议(protocol)(或传输)方案始终必须与协议(protocol)/方案结合才能进行加密操作。这些方案包括
- TLS(旧称 SSL)
- CMS 或 S/MIME 加密数据
- IES(集成加密方案)
- ECIES(椭圆曲线综合加密方案)
- ElGamal 加密(整体)
- PGP 加密
所以您可能想要的是 ECIES。
ECIES.Net
目前(.NET Framework 4.7.1、.NET Core 2.0)不支持从 .NET 中的证书获取 ECDiffieHellman 对象。
游戏结束了吧?好吧,可能不是。除非带有 ECDH key 的证书明确使用 id-ecDH 算法标识符(相对于更标准的 id-ecc 标识符),否则它可以作为 ECDSA 打开。然后,您可以将该对象强制转换为 ECDH:
using (ECDsa ecdsa = cert.GetECDsaPublicKey())
{
return ECDiffieHellman.Create(ecdsa.ExportParameters(false));
}
(如果私钥是可导出的,可以对私钥做类似的事情,否则需要复杂的东西,但你不应该需要它)
让我们继续分割接收者公共(public)对象:
ECDiffieHellmanPublicKey recipientPublic = GetECDHFromCertificate(cert).PublicKey;
ECCurve curve = recipientPublic.ExportParameters().Curve;
现在我们转向http://www.secg.org/sec1-v2.pdf 5.1节(椭圆曲线综合加密方案)
###设置
- 选择 ANSI-X9.63-KDF 和 SHA-2-256 作为哈希函数。
- 选择 HMAC–SHA-256–256。
- 在 CBC 模式下选择 AES–256。
- 选择椭圆曲线 Diffie-Hellman 原语。
- 您已经选择了 secp256r1。
- 硬编码。完成。
- 点压缩很烦人,选择不使用它。
- 我省略了 SharedInfo。这可能使我成为一个坏人。
- 不使用 XOR,N/A。
###加密
在右曲线上制作一个临时 key 。
ECDiffieHellman ephem = ECDiffieHellman.Create(curve);
我们决定不。
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 和 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 });
加密内容。
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); }
MAC它
byte[] d; using (HMAC hmac = new HMACSHA256(mk)) { d = hmac.ComputeHash(em); }
完成
// Either return Tuple.Create(rBar, em, d); // Or return rBar.Concat(em).Concat(d).ToArray();
###解密 作为练习留给读者。
关于c# - 如何在 Windows 上的 .net 框架中使用来自 ECC X509 证书的公钥加密数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47116611/