jcalfee314
jcalfee314

Reputation: 4850

Computing a ECDH Shared Secret in JavaScript

I'm needing to compute a shared secret in JavaScript using ECC keys an ECDH. I see two possible projects that may do this but I'm not sure which if any to pursue:.

  1. https://code.google.com/p/end-to-end
  2. https://github.com/bitwiseshiftleft/sjcl

1) Is a chrome extension so I assume that means it is not going to run in other browsers. 2) Someone had a problem with SJCL stating they thought this was using ECMQV instead of plain ECDH (Can't bridge Elliptic Curve Diffie-Hellman with javascript).

Can someone please recommend a good course of action for my implementation? And Option 3 (a preferred option): I have a hunch that is may be straight forward to include a shared secret implementation here: https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/ecdsa.js.

This is C++ code to create the shared secret on the server:

void * ecies_key_derivation(const void *input, size_t ilen, void *output, size_t *olen) 
    {
        *olen = SHA512_DIGEST_LENGTH;
        return (void*)SHA512((const unsigned char*)input, ilen, (unsigned char*)output);
    }
...
fc::sha512 shared_secret;
ECDH_compute_key( (unsigned char*)&shared_secret, sizeof(shared_secret), EC_KEY_get0_public_key(recipient.my->_key), my->_key, ecies_key_derivation );  

Upvotes: 2

Views: 3830

Answers (1)

jcalfee314
jcalfee314

Reputation: 4850

Obviously this needs to be consolidated but it is at least working!

Option 1 is chrome specific: https://bugzilla.mozilla.org/show_bug.cgi?id=1022106 "cursory glance at the code (git clone-able from git clone https://code.google.com/p/end-to-end/), and it seems to very much be designed to be a Chrome-only add-on"

Option 2 works as seen here using bitcore (bitcore uses sjcl behind the scenes):

    # npm install bitcore
    ECIES = require '../node_modules/bitcore/lib/ECIES'
    ot_pubkey = new Buffer(onetime_public_key, 'hex')
    my_privkey = new Buffer(d_receiver_hex, 'hex')
    ecies = new ECIES.encryptObj ot_pubkey, new Buffer(''), my_privkey
    S = ecies.getSfromPubkey()
    console.log 'bitcore sharedsecret\t',S.toString 'hex'
    S_kdf_buf = ECIES.kdf(S)

    console.log 'bitcore sharedsecret kdf\t',S_kdf_buf.toString 'hex'

Additionally elliptic.js worked which uses it own code including bn.js for big numbers (same author):

    # git clone https://github.com/indutny/elliptic.git
    elliptic = require('../elliptic/lib/elliptic.js')

    # npm install bn.js
    bn = require('bn.js')

    #Providing ecies_key_derivation https://github.com/indutny/elliptic/issues/9
    ec = new elliptic.ec('secp256k1')

    s0 = ec.keyPair(onetime_private_key, 'hex')

    # ../testnet/config/genesis_private_keys.txt

    s1 = ec.keyPair(d_receiver_hex, "hex")

    sh0 = s0.derive(s1.getPublic())
    sh1 = s1.derive(s0.getPublic())    
    assert.equal sh0.toString(16), sh1.toString(16), "shared secret did not match"

    shared_secret = "0"+sh0.toString(16) #### only works for this shared secret (bn.js::toString(16))

At this point, I got these libraries to produce the shared secrets correctly. For decryption I ended up using crypto-js.

    # https://code.google.com/p/crypto-js/#Custom_Key_and_IV
    # see wallet_records.cpp master_key::decrypt_key
    CryptoJS.AES.decrypt(
      ciphertext: cipher
      salt: null
    , @key,
      iv: @iv
    )

For decryption, I require a 256 bit IV (initialization vector) for the task so that leaves SJCL out until this is updated (https://github.com/bitwiseshiftleft/sjcl/issues/197). Also, I did not have much luck decrypting with elliptic.js either although I'm not sure if that was my error.

Upvotes: 4

Related Questions