提问者:小点点

NET中的ECDiffieHellmanCng是否具有实现NISTSP800-56A,第5.8.1节的密钥推导函数


我手头有一个任务,需要使用NISTSP800-56A第5.8.1节中描述的密钥推导函数推导密钥材料。我不是密码学专家,所以如果这个问题很天真,请原谅我。以下是我到目前为止所做的:

>

  • 我有对方的公钥和我的私钥
  • 现在我尝试使用ECDH1.3.132.1.12使用C#(.NET4)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方信息?

    编辑我愿意使用其他库,如充气城堡(前提是它们可以从NET调用)


  • 共1个答案

    匿名用户

    太长别读;我还没有找到一种方法来使用NISTSP800-56A,第5.8.1节中描述的KDF派生对称密钥。NET4.0中的内置类

    好消息(对我来说:-))是它是可能的。NET4.0使用可爱的BouncyCastle库(NuGet: Install-Package BouncyCastle-Ext-Version"1.7.0")。这里是如何:

    第一步:获取对方公钥

    根据您的场景,这可能会从证书中读取或作为包含加密数据的消息的一部分发送给您。获得Base64编码的公钥后,将其读入Org. BouncyCastle.Crypto.Parameters.ECPublicKeyParameters对象,如下所示:

    var publicKeyBytes = Convert.FromBase64String(base64PubKeyStr);
    ECPublicKeyParameters otherPartyPublicKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(publicKeyBytes);
    

    第2步:读取您的私钥

    这通常涉及从PFX/P12证书中读取私钥。运行代码的Windows帐户应该有权访问PFX/P12,此外,如果证书被导入证书存储,您需要通过所有任务授予权限-

    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。通过调用WrapperU的Org.BouncyCastle.Security. GetWrapper("AES//")获取IWrapper。例如"AES/CBC/PKCS7"。这也取决于两个通信方之间的协议。

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