title: How to import/export Java EC keys to/from X9.63 encoding with Java 8
body: <p>I am looking into writing a Java 8 program to do a ECDH exchange with another piece of software using a library (wolfSSL/wolfCrypt) that can only export/import ECC public keys in X9.63 format (their <code>wc_ecc_export_x963()</code> function).  I would greatly prefer to do this using the providers that come with Java.</p>
  
  <p>Therefore, I need to find out how to get Java to create a <code>PublicKey</code> object out of the X9.63 encoding of one and create the X9.63 encoded bytes of a <code>PublicKey</code> object.</p>
  
  <p>I've written some test code to try to figure out what format Java is using:</p>
  
  <pre><code>    // Make a key
      ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
      KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
      keyGen.initialize(ecSpec);
      KeyPair pair = keyGen.generateKeyPair();
  
      // Let's see what Java thinks the encoding is
      System.out.println("Pubkey format: " + pair.getPublic().getFormat());
      System.out.println("Privkey format: " + pair.getPrivate().getFormat());
  
      // And write out the encoded forms to files so we can poke at them
      // with openssl, etc.
      try (FileOutputStream pubOut = new FileOutputStream("ecpub.der");
           FileOutputStream privOut = new FileOutputStream("ecpriv.der")) {
          pubOut.write(pair.getPublic().getEncoded());
          privOut.write(pair.getPrivate().getEncoded());
      }
  </code></pre>
  
  <p>This yields the output:</p>
  
  <pre><code>Pubkey format: X.509
  Privkey format: PKCS#8
  </code></pre>
  
  <p>I can then do use openssl to investigate the public key structure:</p>
  
  <pre><code>$ openssl asn1parse -i -in ecpub.der -inform DER
      0:d=0  hl=2 l=  89 cons: SEQUENCE
      2:d=1  hl=2 l=  19 cons:  SEQUENCE
      4:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
     13:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
     23:d=1  hl=2 l=  66 prim:  BIT STRING
  </code></pre>
  
  <p>but that is opaque to me (I don't know ASN.1) and I have no idea what encoding format that is or even how to find out what encoding format it is.</p>
  
  <p>And here's a hexdump of that Java representation:</p>
  
  <pre><code>$ hexdump -C ecpub.der
  00000000  30 59 30 13 06 07 2a 86  48 ce 3d 02 01 06 08 2a  |0Y0...*.H.=....*|
  00000010  86 48 ce 3d 03 01 07 03  42 00 04 a3 c4 5c 5d aa  |.H.=....B....\].|
  00000020  93 70 8b 65 47 9b f9 83  17 01 37 23 30 d2 0c 6a  |.p.eG.....7#0..j|
  00000030  c7 93 6e d4 70 b1 5b bf  8e 65 4f 96 70 7e e8 97  |..n.p.[..eO.p~..|
  00000040  30 a2 6e e4 1f 50 bb 21  4f a6 7a 01 bd 96 a4 2f  |0.n..P.!O.z..../|
  00000050  8b cd 0d d0 d2 4a 63 d1  68 d0 7b                 |.....Jc.h.{|
  0000005b
  </code></pre>
  
  <hr>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Here's the hexdump of what I get out of <code>wc_ecc_export_x963()</code>.  I'll include the C source code to my test program as well.  <code>openssl asn1parse</code> chokes on the file, FWIW.</p>
  
  <pre><code>$ hexdump -C wolf.x963
  00000000  04 f1 55 1b 03 d5 91 ed  03 d5 44 f9 09 b2 1e 59  |..U.......D....Y|
  00000010  c7 4d ef 1a e9 de 51 16  4e b9 4d 8c 1d 10 73 d4  |.M....Q.N.M...s.|
  00000020  9e 09 24 78 5a 03 c4 45  bf 0c 83 22 69 d8 52 ed  |..$xZ..E..."i.R.|
  00000030  90 04 00 0c ea 38 95 a9  e5 da 96 d2 ae c4 5c 3a  |.....8........\:|
  00000040  c8                                                |.|
  00000041
  </code></pre>
  
  <p>And for reference, here's the program that produced that <code>wolf.x963</code> file  (note -- I haven't programmed in C in many years):</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;wolfssl/options.h&gt;
  #include &lt;wolfssl/wolfcrypt/error-crypt.h&gt;
  #include &lt;wolfssl/wolfcrypt/settings.h&gt;
  #include &lt;wolfssl/wolfcrypt/random.h&gt;
  #include &lt;wolfssl/wolfcrypt/ecc.h&gt;
  
  int main() {
    // Make a key object ready for use.
    ecc_key key;
    wc_ecc_init(&amp;key);
  
    // Make a random number generator object ready for use
    RNG rng;
    wc_InitRng(&amp;rng);
  
    // Make a "32-byte" key.  According to wolfSSL,
    // this will use the SECP256R1 curve since that's
    // what they map to a request for a 32-byte key.
    wc_ecc_make_key(&amp;rng, 32, &amp;key);
  
    byte encoded[1024];
    word32 encodedLen = 0;
    int error;
  
    // According to the API docs, on entry encodedLen should
    // be a number equal to or larger than what the output
    // will be.  If it is not, the function will return BUFFER_E
    // and set encodedLen to how many bytes will be needed to
    // hold the exported data.
    error = wc_ecc_export_x963(&amp;key, encoded, &amp;encodedLen);
    printf("Error code = %d\n", error);
    if (error == BUFFER_E) {
      error = wc_ecc_export_x963(&amp;key, encoded, &amp;encodedLen);
      printf("Error code again = %d\n", error);
    }
  
    // Print out the byte values so that I can make sure
    // that I didn't somehow corrupt the data writing it
    // out as I am very rusty at C.
    //int i;
    //for (i = 0; i &lt; encodedLen; i++) {
    //  printf("enc[%d] = %x\n", i, encoded[i]);
    //}
  
    FILE *outFile;
    outFile = fopen("wolf.x963", "wb");
    fwrite(encoded, encodedLen, 1, outFile);
    fclose(outFile);
  
    wc_ecc_free(&amp;key);
    wc_FreeRng(&amp;rng);
  
    return 0;
  }
  </code></pre>
  
  <p>And its output:</p>
  
  <pre><code> ./SaveEccKey
  Error code = -132
  Error code again = 0
  </code></pre>