在ECC加密过程中,我(作为发件人)假设我会做以下事情:
Q1:上述程序是否有任何问题?
在.net framework 4.7中,这是我的第一次尝试:
var curve = ECCurve.NamedCurves.nistP256;
var ecdhSender = ECDiffieHellman.Create(curve);
X509Certificate2 otherPartyPublicCert = null; //TODO: Get some how from other party and populate this variable
byte[] otherPartyPublicKey = otherPartyPublicCert.GetPublicKey();
ECDiffieHellmanPublicKey otherPartyECDHPublicKey = ECDiffieHellmanCngPublicKey.FromByteArray(otherPartyPublicKey, CngKeyBlobFormat.GenericPublicBlob);
//The DeriveKeyMaterial seem to generate secret agreement, generate key and throw away the secrete agreement
var symmetricKey = ecdhSender.DeriveKeyMaterial(otherPartyECDHPublicKey);
// Or
//The DeriveKeyFromHash seem to generate same key as above because SHA256 was probably implicit in above call
var symmetricKey2 = ecdhSender.DeriveKeyFromHash(otherPartyECDHPublicKey, HashAlgorithmName.SHA256);
//TODO: Perform encryption with above key (either symmetricKey or symmetricKey2, depending on which call we choose) using AES etc.
Q2:上面的代码流程是否正确(包括我在代码中的评论)?
问题3:使用DeriveKeyMaterial还是DeriveKeyFromHash有区别吗? (注意:当我比较symmetricKey和symmetricKey2时,它们是相同的)
问题4:要正确实现NIST单步KDF(调用kdf(Z,OtherInput),其中Z是秘密协议,OtherInput由keydatalen和OtherInfo组成),应该使用具有secretPrepend的DeriveKeyFromHash方法secretAppend bytes signature但只填充secreteAppend bytes?
Q5:如果对Q4的回答是肯定的,并且如果OtherInfo包括说信息" AlgorithmIDStuff"," PartyUInfoStuff"," PartyVInfoStuff" (如果我选择实现连接格式),我应该在secretAppend参数中使用字节序列后面的后续值(即位串)(DeriveKeyFromHash方法使用的Z字节值):
答案 0 :(得分:1)
如您所知,由于您对它们进行了编号,因此这里有多个问题。理想情况下,每个问题都有一个问题,但我同意他们是相关的,所以我会尝试一次性回答这些问题。
Q1:上述程序是否有任何问题?
您所描述的内容实际上是ECIES(椭圆曲线Integrated Encryption Scheme)(http://www.secg.org/sec1-v2.pdf),尽管您缺少计算MAC密钥。如果您不能使用经过身份验证的加密模式,则可能只想关注ECIES。
如果你正在使用SP-800-56A,你也会使用稍微不同的KDF,但这是一个很好的KDF。
Q2:上面的代码流程是否正确(包括我在代码中的注释)?
流程很好,但有些特定代码并不正确。
byte[] otherPartyPublicKey = otherPartyPublicCert.GetPublicKey();
ECDiffieHellmanPublicKey otherPartyECDHPublicKey =
ECDiffieHellmanCngPublicKey.FromByteArray(
otherPartyPublicKey,
CngKeyBlobFormat.GenericPublicBlob);
" GenericPublicBlob"不是任何通用的公共blob"而是来自CNG的一种blob。 GetPublicKey()
方法返回公钥字节,这是一个特定于算法的数据blob。对于ECC密钥,它是编码的公共密钥点Q。
除非密钥的发送者讨厌你,否则它将是一个奇数长的数组,以0x04
开头。如果是这样,您可以通过.NET 4.7 API导入公钥:
private static ECDiffieHellmanPublicKey GetECDHPublicKey(X509Certificate2 cert)
{
byte[] pubKey = cert.GetPublicKey();
if (pubKey.Length % 2 == 1 && pubKey[0] == 0x04)
{
byte[] qx = new byte[pubKey.Length / 2];
byte[] qy = new byte[qx.Length];
Buffer.BlockCopy(pubKey, 1, qx, 0, qx.Length);
Buffer.BlockCopy(pubKey, 1 + qx.Length, qy, 0, qy.Length);
ECParameters ecParameters = new ECParameters
{
Curve = ECCurve.NamedCurves.nistP256,
Q =
{
X = qx,
Y = qy,
}
};
using (var otherEcdh = ECDiffieHellman.Create(ecParameters))
{
return otherEcdh.PublicKey;
}
}
throw new NotSupportedException();
}
如果您没有提前知道预期的曲线可能会略有不同:
using (ECDsa ecdsa = cert.GetECDsaPublicKey())
using (ECDiffieHellman ecdh = ECDiffieHellman.Create(ecdsa.ExportParameters(false))
{
// This one takes care of the curve.
return ecdh.PublicKey;
}
当然,您可以通过类似ECDiffieHellman.Create(otherPublic.ExportParameters().Curve)
问题3:使用DeriveKeyMaterial还是DeriveKeyFromHash有区别吗? (注意:当我比较symmetricKey和symmetricKey2时,它们是相同的)
DeriveKeyMaterial
来自.NET 3.5并使用一堆属性来控制它。默认情况下,它使用SHA-256进行哈希派生。
DeriveKeyFromHash
,以便更清楚地了解正在执行的操作以及操作中涉及的属性(现在的参数)。
我认为没有人应该再次使用DeriveKeyMaterial
(相反,使用新方法),但那只是我。
问题4:要正确实现NIST单步KDF(调用kdf(Z,OtherInput),其中Z是秘密协议,OtherInput由keydatalen和OtherInfo组成),应使用具有secretPrepend和secretAppend字节签名的DeriveKeyFromHash方法但只填充secreteAppend字节?
没有。 OtherInfo
进入secretAppend
,但是大端32位计数器进入secretPrepend
(参见5.8.1.1,流程,步骤3,4,5.1,5.2)。
问题5:如果对Q4的答案是肯定的,并且如果OtherInfo包括说信息" AlgorithmIDStuff"," PartyUInfoStuff"," PartyVInfoStuff" (如果我选择实现连接格式),我应该在secretAppend参数中的字节序列(即位串)(DeriveKeyFromHash方法使用的Z字节值)之后使用以下值:
没有。 " AlgorithmIDStuff"不符合AlgorithmID
值的定义(第5.8.1.2节);和PartyU / PartyV信息类似。