title: ECDiffieHellman - mbedTLS vs C#
body: <p>I need to use elliptic curve Diffie Hellman between a ARM cortex M3 and the PC.
  On the ARM, I use <a href="https://tls.mbed.org/" rel="nofollow noreferrer">mbed TLS</a>. On the PC side I want to us C# and the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.ecdiffiehellmancng?view=netframework-4.7.2" rel="nofollow noreferrer">ECDiffieHellman(Cng)</a> class.</p>
  
  <p>I can do the ECDH on ARM vs ARM, but I do have trouble when I try to replace one side with the PC.</p>
  
  <ol>
  <li>Problem was the key exchange.
  I found out, that the key is exported by mbed TLS as <code>&lt;LEN&gt;&lt;0x04&gt;&lt;X&gt;&lt;Y&gt;</code>.</li>
  </ol>
  
  <p>Thus, In C# I am importing the public key using</p>
  
  <p>private static EC</p>
  
  <pre class="lang-cs prettyprint-override"><code>DiffieHellmanPublicKey ToPublicKey(byte[] publicKey)
  {
      var keyLength = 32;
  
      if (publicKey[0] != (2 + 2 * keyLength) - 1)
          throw new ArgumentException("Invalid key length", nameof(publicKey));
      if (publicKey[1] != 0x04)
          throw new ArgumentException("Invalid key format", nameof(publicKey));
  
      var parameters = new ECParameters()
      {
          Curve = ECCurve.NamedCurves.brainpoolP256r1,
          Q = new ECPoint()
          {
              X = publicKey.Skip(2).Take(keyLength).ToArray(),
              Y = publicKey.Skip(2 + keyLength).Take(keyLength).ToArray()
          }
      };
  
      using (var tmp = ECDiffieHellman.Create(parameters))
      {
          return tmp.PublicKey;
      }
  }
  </code></pre>
  
  <ol start="2">
  <li>To generate the key I tried</li>
  </ol>
  
  <pre class="lang-cs prettyprint-override"><code>var ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.brainpoolP256r1);
  ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Tls;
  ecdh.Seed = new byte[32];
  ecdh.Label = Encoding.ASCII.GetBytes("ECDiffieHellman");
  
  new RNGCryptoServiceProvider().GetBytes(ecdh.Seed);
  
  // ...
  
  var sharedSecret = ecdh.DeriveKeyMaterial(peersPublicKey);
  </code></pre>
  
  <p>My problem is that the generated shared secret is of different length compared to the one generated by mbed TLS and does not match.</p>
  
  <p>Did someone already solve this problem?</p>
  
  <p>Thanks!</p>
  
  <p><strong>EDIT 1:</strong></p>
  
  <p>I forgot to mention, that I use bare ECDH on ARM. So I don't think there is any key derivation function executing. Is it sufficient to hash (SHA256) the result to match the C# side (when configuring SHA256 as KDF there)?</p>