2

I have following code:

        var curve = ECCurve.NamedCurves.nistP256;
        var ecdhSender = ECDiffieHellman.Create(curve);
        var ecdhReceiver = ECDiffieHellman.Create(curve);

My understanding is that I should be able to compute secret agreement either from using ecdhSender object using ecdhReceiver.PublicKey or using ecdhReceiver object with ecdhSender.PublicKey and that both secret agreement values should be same. If this is a wrong assumption, please let me know.

Since the ECDiffieHellman.Create returns ECDiffieHellman type, I wrote following code to get the secret agreement:

        string receiverHexString = null;
        using (SafeNCryptSecretHandle secretAgreement = (ecdhReceiver as ECDiffieHellmanCng).DeriveSecretAgreementHandle(ecdhSender.PublicKey))
        {
            byte[] secretAgreementBytes = new byte[32];
            IntPtr pointer = secretAgreement.DangerousGetHandle();
            Marshal.Copy(pointer, secretAgreementBytes, 0, secretAgreementBytes.Length);
            receiverHexString = BitConverter.ToString(secretAgreementBytes).Replace("-", string.Empty).ToLower();
            Console.WriteLine($"receiver secretAgreement: 0x{receiverHexString}");
        }

        string senderHexString = null;
        using (SafeNCryptSecretHandle secretAgreement = (ecdhSender as ECDiffieHellmanCng).DeriveSecretAgreementHandle(ecdhReceiver.PublicKey))
        {
            byte[] secretAgreementBytes = new byte[32];
            IntPtr pointer = secretAgreement.DangerousGetHandle();
            Marshal.Copy(pointer, secretAgreementBytes, 0, secretAgreementBytes.Length);
            senderHexString = BitConverter.ToString(secretAgreementBytes).Replace("-", string.Empty).ToLower();
            Console.WriteLine($"sender secretAgreement: 0x{senderHexString}");
        }

        Assert.AreEqual(receiverHexString, senderHexString);

My assertion is failing. Obviously I am doing some thing wrong (if the secret agreements are supposed to be same).

Is it how I am extracting the bytes out of handle? Or something else?

Raghu
  • 2,859
  • 4
  • 33
  • 65
  • What are you trying to accomplish? The NCRYPT_SECRET_HANDLE structure is opaque, you shouldn't be reading its memory. – bartonjs Oct 16 '17 at 14:37
  • Trying to validate the results from a partner with detailed steps. Can u please comment if my assumption is correct or wrong in the first part of my question? – Raghu Oct 16 '17 at 14:50

1 Answers1

4

As of the last time I checked there is no documented way to get the raw secret agreement value from CNG, which is why .NET doesn't expose it.

The expected use of ECDH in .NET is

ECCurve curve = ECCurve.NamedCurves.nistP256;

// Usually you'll only have one private key (yours), so this isn't representative of
// real code.  An `ECDiffieHellman` object doesn't necessarily have a private key,
// but an `ECDiffieHellmanPublicKey` object definitely doesn't.
using (ECDiffieHellman bobPrivate = ECDiffieHellman.Create(curve))
using (ECDiffieHellman alicePrivate = ECDiffieHellman.Create(curve))
using (ECDiffieHellmanPublicKey bobPublic = bobPrivate.PublicKey)
using (ECDiffieHellmanPublicKey alicePublic = alicePrivate.PublicKey)
{
    byte[] ba = bobPrivate.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA256);
    byte[] ab = alicePrivate.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA256);

    // ba and ab have the same contents.
}

There's also

  • DeriveKeyFromHash(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend)
  • DeriveKeyFromHmac(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] hmacKey)
  • DeriveKeyFromHmac(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend)
  • DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)

If bobPrivate and alicePublic (or, conversely, alicePrivate and bobPublic) are unchanged then providing the same inputs will yield the same outputs.

Note: You should avoid talking about ECDiffieHellmanCng specifically, if you can. When ECDH eventually makes it into .NET Standard, the ECDHCng class won't. As of .NET 4.6.2 everything can be done on the base class (except opening persisted keys); and .NET Core tends to not return public types from its Create() factory-methods.

bartonjs
  • 30,352
  • 2
  • 71
  • 111
  • Can you please explain why 'ba' and 'ab' equals? In the DH algorithm ther's usually only one public key shared between the two parties; here we have two different public keys not related one on each other. The protocol should start on a common shared key on which the two parties applies his own proper secret [wiki link](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange); I can't figure out where this happen in your snippet. – gio Oct 27 '21 at 12:20
  • 1
    @gio They’re the same because that’s how ECDH works. Each party has a private key, and a public key which is just private*G (the curve generator). `a*b*G` == `b*a*G` because multiplication (even in EC) is commutative. The belief that only one public key is involved is just wrong, sorry, look at the first picture in that article. `DH(myPriv, yourPub)` == `DH(yourPriv, myPub)` – bartonjs Oct 27 '21 at 14:44
  • Ok now I really got it. Thanks for the clarification. – gio Oct 27 '21 at 14:58