.NET中的ECDiffieHellmanCng是否具有实现NIST SP 800-56A的密钥派生函数,第5.8.1节
我有一项任务需要使用NIST SP 800-56A第5.8.1节中描述的密钥导出函数来获取密钥材料。 我不是密码学方面的专家,所以如果问题是天真的,请原谅。 这是我到目前为止所做的:
- 我有另一方的公钥和我的私钥
-
现在我尝试使用C#(。NET 4)ECDiffieHellmanCng类使用ECDH 1.3.132.1.12生成共享密钥,如下所示:
// The GetCngKey method reads the private key from a certificate in my Personal certificate store CngKey cngPrivateKey = GetCngKey(); ECDiffieHellmanCng ecDiffieHellmanCng = new ECDiffieHellmanCng(cngPrivateKey); ecDiffieHellmanCng.HashAlgorithm = CngAlgorithm.ECDiffieHellmanP256; ecDiffieHellmanCng.KeyDerivationFunction = ?? // What do I set here
最后这样做:
ecDiffieHellmanCng.DeriveKeyMaterial(otherPartyPublicKey:);
在哪里/如何设置其他参数算法ID,Party U Info,Party V Info?
编辑我愿意使用像Bouncy Castle这样的其他库(前提是它们可以从.NET调用)
TL; DR; 我没有找到使用NIST SP 800-56A,第5.8.1节中描述的KDF导出对称密钥的方法,仅使用.NET 4.0中的内置类
好消息(对我来说:-))是可以在.NET 4.0中使用可爱的BouncyCastle库(NuGet:Install-Package BouncyCastle-Ext -Version“1.7.0”)。 这是如何做:
第1步:获取其他方的公钥
根据您的情况,可以从证书中读取,也可以将其作为包含加密数据的消息的一部分来找您。 获得Base64编码的公钥后,将其读入Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters对象,如下所示:
var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr); ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
第2步:阅读您的私钥
这通常涉及从PFX / P12证书中读取私钥。 运行代码的Windows帐户应该可以访问PFX / P12,此外,如果将证书导入证书存储区,则需要通过certmgr.msc中的“所有任务” – >“管理私钥”菜单授予权限。
using (StreamReader reader = new StreamReader(path)) { var fs = reader.BaseStream; string password = ""; Pkcs12Store store = new Pkcs12Store(fs, passWord.ToCharArray()); foreach (string n in store.Aliases) { if (store.IsKeyEntry(n)) { AsymmetricKeyEntry asymmetricKey = store.GetKey(n); if (asymmetricKey.Key.IsPrivate) { ECPrivateKeyParameters privateKey = asymmetricKey.Key as ECPrivateKeyParameters; } } } }
第3步:计算共享密钥
IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH"); aKeyAgree.Init(privateKey); BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey); byte[] sharedSecretBytes = sharedSecret.ToByteArray();
第4步:准备计算对称密钥所需的信息:
byte[] algorithmId = Encoding.ASCII.GetBytes(("" + "id-aes256-GCM")); byte[] partyUInfo = Encoding.ASCII.GetBytes(""); byte[] partyVInfo = ; MemoryStream stream = new MemoryStream(algorithmId.Length + partyUInfo.Length + partyVInfo.Length); var sr = new BinaryWriter(stream); sr.Write(algorithmId); sr.Flush(); sr.Write(partyUInfo); sr.Flush(); sr.Write(partyVInfo); sr.Flush(); stream.Position = 0; byte[] keyCalculationInfo = stream.GetBuffer();
步骤5:导出对称密钥
// NOTE: Use the digest/Hash function as per your agreement with the other party IDigest digest = new Sha256Digest(); byte[] symmetricKey = new byte[digest.GetDigestSize()]; digest.Update((byte)(1 >> 24)); digest.Update((byte)(1 >> 16)); digest.Update((byte)(1 >> 8)); digest.Update((byte)1); digest.BlockUpdate(sharedSecret, 0, sharedSecret.Length); digest.BlockUpdate(keyCalculationInfo, 0, keyCalculationInfo.Length); digest.DoFinal(symmetricKey, 0);
现在您已准备好对称密钥进行解密。 要使用AES执行解密,可以使用BouncyCastle IWrapper。 通过调用WrapperUtilities.GetWrapper(“AES //”),例如“AES / CBC / PKCS7”,使用Org.BouncyCastle.Security.WrapperUtilities获取IWrapper。 这还取决于两个通信方之间的协议。
使用对称密钥和初始化向量(IV)初始化密码(IWrapper)并调用Unwrap方法以获取纯文本字节。 最后,使用所使用的字符编码转换为字符串文字(例如UTF8 / ASCII / Unicode)