Rag*_*ghu 2 .net c# encryption cryptography elliptic-curve
我在用:
这是我所做的:
获得了使用 OpenSSL 的自签名 ECC 证书以及https://gist.github.com/sidshetye/4759690上的脚本中概述的步骤,并进行了修改:
a) 在 256 位素数字段上使用 NIST/P-256 曲线
b) 使用 SHA-256
将文件(在上一步中生成)中的证书加载到 X509Certificate2 对象中
将 PFX 文件导入 Windows 信任存储(用于测试)。这是成功的。
我被困在最后一步,因为所有使用 X509Certificate2 对象的示例主要仅使用 RSA 而我使用的是 ECC 证书。对于 RSA 证书,X509Certificate2 上有GetRSAPublicKey扩展方法,RSA 类有Encrypt方法。但是,ECC 证书没有这种方法。
接下来,我偶然发现了这篇文章(使用带有 ECC 公钥的 X509Certificate2 加载证书)并尝试遵循以下方法(即使 ECC 证书公钥被强制转换为 RSA 类型的原因看起来很奇怪):
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key
Run Code Online (Sandbox Code Playgroud)
我遇到以下异常:不支持证书密钥算法。
接下来我偶然发现了这篇文章(将基于 ECC 的证书从 Windows 证书存储导入 CngKey),它基本上试图创建 CNGKey 类型并用它实例化 ECDsaCng。但是,即使我可以用 ECDiffieHellmanCng 做到这一点,也没有 Encrypt 方法。
所以我不确定如何进一步使用 ECC X509 证书的公钥来加密数据。
非对称算法有三个不同的目的(我知道)
因为 RSA 加密空间有限,而且在 90 年代对计算机来说很难,所以 RSA 加密的主要用途是“密钥传输”,也就是说“加密消息”只是 DES/3DES (AES) 的对称加密密钥尚未发明)- https://tools.ietf.org/html/rfc2313#section-8。
密钥协商(或传输)方案总是必须与协议/方案结合以产生加密操作。此类计划包括
所以你可能想要的是ECIES。
目前(.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));
}
Run Code Online (Sandbox Code Playgroud)
(私钥可以做类似的事情,如果密钥是可导出的,否则需要复杂的东西,但你不应该需要它)
让我们继续划分接收者公共对象:
ECDiffieHellmanPublicKey recipientPublic = GetECDHFromCertificate(cert).PublicKey;
ECCurve curve = recipientPublic.ExportParameters().Curve;
Run Code Online (Sandbox Code Playgroud)
所以现在我们转向http://www.secg.org/sec1-v2.pdf第 5.1 节(椭圆曲线集成加密方案)
在正确的曲线上制作一个临时密钥。
ECDiffieHellman ephem = ECDiffieHellman.Create(curve);
Run Code Online (Sandbox Code Playgroud)我们决定不。
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);
Run Code Online (Sandbox Code Playgroud)不能直接这样做,继续。
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 });
Run Code Online (Sandbox Code Playgroud)加密东西。
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);
}
Run Code Online (Sandbox Code Playgroud)MAC它
byte[] d;
using (HMAC hmac = new HMACSHA256(mk))
{
d = hmac.ComputeHash(em);
}
Run Code Online (Sandbox Code Playgroud)结束
// Either
return Tuple.Create(rBar, em, d);
// Or
return rBar.Concat(em).Concat(d).ToArray();
Run Code Online (Sandbox Code Playgroud)留给读者作为练习。