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

Does ECDiffieHellmanCng in .NET have a key derivation function that implements NIST SP 800-56A, section 5.8.1

我手头有一项任务需要使用 NIST SP 800-56A 第 5.8.1 节中描述的密钥派生函数来派生密钥 material。我不是密码学专家,所以如果问题很幼稚,请原谅。这是我到目前为止所做的:

  1. 我有对方的public密钥和我的私钥
  2. 现在我尝试使用 C# (.NET 4) ECDiffieHellmanCng class 使用 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:);

Where/how算法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 步:获取对方的 public 密钥

根据您的情况,这可能会从证书中读取或作为包含加密数据的消息的一部分发送给您。一旦你有了 Base64 编码的 public-key,将它读入一个 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 = "<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;
           }
       }
   }
}

第 3 步:计算共享密钥

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

第 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();

第 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//") 使用 Org.BouncyCastle.Security.WrapperUtilities 获取 IWrapper,例如"AES/CBC/PKCS7"。这也将取决于两个通信方之间的协议。

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