title: ECDH between C# and javascript
body: <p>I'm building a web API and I need to implement ECDH to perform an end-to-end cryptography. At the server side I have a C# application and at the client side I have a Javascript application.</p>
  
  <p>I'm able to exchange the keys, generate the private keys and encrypt the messages, but I'm having problems decrypting it.</p>
  
  <p>I think the problem is in the exchange of the public keys. In javascript keys starts with a byte "4" and .NET keys starts with 8 bytes identifying the type and the size of the key, I need to change this bytes in order to import each key (Information that I've found <a href="https://stackoverflow.com/a/24255090/10297094">here</a>). Maybe this cause some inconsistencies.</p>
  
  <p>At the client side I'm using the Web Cryptography API to handle with the ECDH. I'm implementing as follows.</p>
  
  <p>Generating the keys</p>
  
  <pre><code>await window.crypto.subtle.generateKey(
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          false,
          ["deriveKey", "deriveBits"]
      );
  </code></pre>
  
  <p>Exporting the public key like this:</p>
  
  <pre><code>await window.crypto.subtle.exportKey(
          "raw",
          publicKey
      );
  </code></pre>
  
  <p>Importing the external public key</p>
  
  <pre><code>await window.crypto.subtle.importKey(
          "raw",
          {
              name: "ECDH",
              namedCurve: "P-256",
          },
          false,
          ["deriveKey", "deriveBits"]
      )
  </code></pre>
  
  <p>And finally deriving the key</p>
  
  <pre><code>await window.crypto.subtle.deriveKey(
          {
              name: "ECDH",
              namedCurve: "P-256",
              public: publicKey,
          },
          privateKey,
          {
              name: "AES-CBC",
              length: 256,
          },
          false,
          ["encrypt", "decrypt"]
      )
  </code></pre>
  
  <p>At the server side I'm implementing the same steps as follow.
  Generating Public Key</p>
  
  <pre><code>private static ECDiffieHellmanCng ecdh = new ECDiffieHellmanCng(256);
  
  public static void GeneratePublicKey()
  {
      ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
      ecdh.HashAlgorithm = CngAlgorithm.Sha256;
      publicKey = ecdh.PublicKey.ToByteArray();
  }
  </code></pre>
  
  <p>Exporting public key. Note that I change the first bytes</p>
  
  <pre><code>public static byte[] GetPublicKey()
      {
          var auxKey = publicKey.Skip(7).ToArray();
          auxKey[0] = 4;
  
          return auxKey;
      }
  </code></pre>
  
  <p>Importing public key and deriving private key. Note that I change the first bytes</p>
  
  <pre><code>public static void GerarChavePrivada(byte[] bobPublicKey)
  {
      byte[] aux = new byte[bobPublicKey.Length + 7];
  
      aux[0] = 0x45;
      aux[1] = 0x43;
      aux[2] = 0x4B;
      aux[3] = 0x31;
      aux[4] = 0x20;
      aux[5] = 0x00;
      aux[6] = 0x00;
      aux[7] = 0x00;
  
      for (int i = 1; i &lt; bobPublicKey.Length; i++)
      {
          aux[7 + i] = bobPublicKey[i];
      }
  
      var importedKey = CngKey.Import(aux, CngKeyBlobFormat.EccPublicBlob);
      privateKey = ecdh.DeriveKeyMaterial(importedKey);
  }
  </code></pre>
  
  <p>I belive the problem is about those keys. Any way these are the encrypt and decrypt codes:</p>
  
  <p>Javascript</p>
  
  <pre><code>async function encrypt2(iv, key, data){
      var mensagemCriptografada;
  
      await window.crypto.subtle.encrypt(
          {
              name: "AES-CBC",
              iv: iv,
          },
          key,
          str2ab(data) //Data is a string and I'm converting using str2ab method.
      )
  
      .then(function(encrypted){
          mensagemCriptografada = encrypted;
      })
      .catch(function(err){
          console.error(err);
      });
  
      return mensagemCriptografada;
  }
  
  function str2ab (str) {
      var array = new Uint8Array(str.length);     
      for(var i = 0; i &lt; str.length; i++) {
          array[i] = str.charCodeAt(i);
      }
      return array.buffer
  }
  </code></pre>
  
  <p>C#</p>
  
  <pre><code>string decMessage = "";
  
          using (Aes aes = new AesCryptoServiceProvider())
          {
              aes.Key = privateKey;
              aes.IV = iv; //IV is the same used by the javascript code
              aes.Mode = CipherMode.CBC;
              aes.Padding = PaddingMode.None;
  
              var dec = aes.CreateDecryptor(privateKey, iv);
  
              var plain = dec.TransformFinalBlock(message, 0, message.Length);
  
              //I've tried every possible enconding.
              decMessage = Encoding.UTF8.GetString(plain); 
          }
  
          return decMessage;
  </code></pre>
  
  <p>I'm really don't have any idea how to resolve this problem.</p>