Search code examples
c#c++cryptographytpmecdh

How to get matching Z from Tpm2.EcdhZGen() and NCrypt.DeriveKeyMaterialHash()


I have a project where one application ("Alice") sends AES encrypted messages to another ("Bob"). Both parties have the public key of the other party - let's assume no ephemeral public keys are needed. The parties must use ECDH to derive the same AES key.

Alice is using System.Security.Cryptography. The documentation says that it doesn't return the "raw" value of the ECDH computation. Instead, ECDiffieHellmanCng.DeriveKeyMaterial() calls NCrypt.DeriveKeyMaterialHash() that results in a byte[] that has already been through HASH(prepend || Z || append). Bob is using TSS because his private key is known only to his TPM. Tpm2.EcdhZGen() returns an EccPoint.

I can't find any samples or documentation to show how a byte[] key can be derived from EccPoint that is consistent with other implementations. I could easily hash the point myself for Bob, but Alice can't get at the raw Z point. Of course I can do my own hash, but it's not clear what Z should be in that byte array. I would guess it's X followed by Y, but experiments don't give positive results.

Any insight into how to get these two frameworks to give the same answer?


Solution

  • Ok, I figured this out after going back to the ECDH article on Wikipedia.

    Most standardized protocols based on ECDH derive a symmetric key from xk using some hash-based key derivation function.

    When I changed my code taking the point z from the TPM's EcdhZGen to HASH(prepend || xz || append), my results finally matched up with the NCrypt integrated operation. Maybe obvious in retrospect, but this question is already one of the top search engine hits for many of the search terms.

    I remember reading that only the sign of yQ is needed for a public key, so I guess the theory says that the x coordinate has all the entropy you need.