我正在使用:
这是我做的:
使用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类具有加密方法。但是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证书的公钥来加密数据。
答案 0 :(得分:2)
非对称算法有三个不同的目的(我知道)
由于RSA加密是空间有限的,并且对于90年代的计算机来说很难,RSA加密的主要用途是" Key Transfer",也就是说& #34;加密消息"只是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));
}
(如果密钥是可导出的,可以对私钥进行类似的操作,否则需要复杂的东西,但你不应该需要它)
让我们继续关注收件人的公共对象:
ECDiffieHellmanPublicKey recipientPublic = GetECDHFromCertificate(cert).PublicKey;
ECCurve curve = recipientPublic.ExportParameters().Curve;
现在我们转向http://www.secg.org/sec1-v2.pdf第5.1节(椭圆曲线集成加密方案)
在右侧曲线上制作一个短暂的密钥。
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);
不能直接这样做,继续前进。
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 it
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();
留给读者练习。
答案 1 :(得分:0)
要从证书中获取ECDiffieHellman
私钥,请使用以下方法:
CngKey cngKey = certificate.GetCngPrivateKey();
(注意:.NET本身支持的扩展方法certificate.GetECDsaPrivateKey()
返回一个ECDsaCng
实例;没有扩展方法可以返回ECDiffieHellmanCng
。)cngKey
实例可用于创建ECDsaCng
或ECDiffieHellmanCng
实例:
var sa = new ECDsaCng(cngKey);
var sa = new ECDiffieHellmanCng(cngKey);