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

Sud*_*hra 11 c# cryptography elliptic-curve diffie-hellman ecdsa

我有一项任务,需要使用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
    
    Run Code Online (Sandbox Code Playgroud)

最后这样做:

ecDiffieHellmanCng.DeriveKeyMaterial(otherPartyPublicKey:);
Run Code Online (Sandbox Code Playgroud)

在哪里/如何设置其他参数算法ID,Party U Info,Party V Info?

编辑 我愿意使用像Bouncy Castle这样的其他库(只要它们可以从.NET调用)

Sud*_*hra 8

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);
Run Code Online (Sandbox Code Playgroud)

第2步:阅读您的私钥

这通常涉及从PFX/P12证书中读取私钥.运行代码的Windows帐户应该可以访问PFX/P12,此外,如果将证书导入证书存储区,则需要通过certmgr.msc中的"所有任务" - >"管理私钥"菜单授予权限.

using (StreamReader reader = new StreamReader(path))
{
    var fs = reader.BaseStream;
    string password = "<password for the PFX>";
    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;
           }
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

第3步:计算共享密钥

IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDH");
aKeyAgree.Init(privateKey);
BigInteger sharedSecret = aKeyAgree.CalculateAgreement(otherPartyPublicKey);
byte[] sharedSecretBytes = sharedSecret.ToByteArray();
Run Code Online (Sandbox Code Playgroud)

步骤4:准备计算对称密钥所需的信息:

byte[] algorithmId = Encoding.ASCII.GetBytes(("<prependString/Hex>" + "id-aes256-GCM"));
byte[] partyUInfo = Encoding.ASCII.GetBytes("<as-per-agreement>");
byte[] partyVInfo = <as-per-agreement>; 
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();
Run Code Online (Sandbox Code Playgroud)

步骤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);
Run Code Online (Sandbox Code Playgroud)

现在您已准备好对称密钥进行解密.要使用AES执行解密,可以使用BouncyCastle IWrapper.通过调用WrapperUtilities.GetWrapper("AES //"),例如"AES/CBC/PKCS7",使用Org.BouncyCastle.Security.WrapperUtilities获取IWrapper.这还取决于两个通信方之间的协议.

使用对称密钥和初始化向量(IV)初始化密码(IWrapper)并调用Unwrap方法以获取纯文本字节.最后,使用所使用的字符编码转换为字符串文字(例如UTF8/ASCII/Unicode)