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

11

我手头有一个任务,需要使用NIST SP 800-56A第5.8.1节中描述的密钥派生函数来推导密钥材料。我不是密码学专家,如果问题比较简单请见谅。目前我已经做了以下工作:

  1. 我拥有另一方的公钥和我的私钥。
  2. 现在我尝试使用ECDH 1.3.132.1.12通过C# (.NET 4) ECDiffieHellmanCng类生成共享密钥,就像这样:

// 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、方U信息、方V信息?

编辑 我愿意使用其他库,比如Bouncy Castle(如果可以从.NET调用)

1个回答

9
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 = "<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;
           }
       }
   }
}

第三步:计算共享密钥

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

第四步:准备计算对称密钥所需的信息:

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

步骤五:推导对称密钥

// 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")来获取一个IWrapper,这取决于两个通信方之间的协议。
使用对称密钥和初始化向量(IV)初始化密码(IWrapper),然后调用Unwrap方法获取明文字节。最后,使用所使用的字符编码(例如UTF8/ASCII/Unicode)转换为字符串文字。

在加密方面,BouncyCastle有ConcatenationKDFGenerator类 https://github.com/bcgit/bc-csharp/blob/0801c1543f0cafc79c44b225e53c973bdd1b0a0f/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs - Sentinel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接