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

前端 未结 1 650
礼貌的吻别
礼貌的吻别 2020-12-06 11:33

I have a task at hand that requires deriving key material using the key derivation function described in NIST SP 800-56A, section 5.8.1. I\'m not an expert in Cryptography s

相关标签:
1条回答
  • 2020-12-06 11:56

    TL;DR; I haven't found a way to derive the symmetric key using KDF described in NIST SP 800-56A, section 5.8.1 using built-in classes in .NET 4.0 alone

    The good news (for me :-)) is that it IS possible in .NET 4.0 using the lovely BouncyCastle library (NuGet: Install-Package BouncyCastle-Ext -Version "1.7.0"). Here's how:

    STEP 1: Get other party's public key

    Depending on your scenario, this may be read from a certificate or come to you as part of the message containing the encrypted data. Once you have the Base64 encoded public-key, read it into a Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters object like so:

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

    STEP 2: Read your private-key

    This would most-commonly involve reading the private key from a PFX/P12 certificate. The windows account running the code should have access to the PFX/P12 and additionally, if the certificate is imported into a certificate store, you'll need to grant permissions via the All Tasks -> manage private key menu in 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;
               }
           }
       }
    }
    

    STEP 3: Compute the shared secret

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

    STEP 4: Prepare information required to compute symmetric key:

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

    STEP 5: Derive the symmetric key

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

    Now you have the symmetric key ready to do the decryption. To perform decryption using AES, BouncyCastle IWrapper can be used. Obtain an IWrapper using Org.BouncyCastle.Security.WrapperUtilities by calling WrapperUtilities.GetWrapper("AES//") e.g. "AES/CBC/PKCS7". This will also depend on the agreement between the two communicating parties.

    Initialize the cipher (IWrapper) with symmetric key and initialization vector (IV) and call the Unwrap method to get plain-text bytes. Finally, convert to string literal using the character encoding used (e.g. UTF8/ASCII/Unicode)

    0 讨论(0)
提交回复
热议问题