.NET中的ECDiffieHellmanCng是否具有实现NIST SP 800-56A的密钥派生函数,第5.8.1节

我有一项任务需要使用NIST SP 800-56A第5.8.1节中描述的密钥导出函数来获取密钥材料。 我不是密码学方面的专家,所以如果问题是天真的,请原谅。 这是我到目前为止所做的:

  1. 我有另一方的公钥和我的私钥
  2. 现在我尝试使用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)