I have a very tiny node script to create a public/private key Is there any way to do it on the client side without having to browserify hole crypto module?
var crypto = require('crypto');
var userCurve = crypto.createECDH('prime256v1');
var userPublicKey = userCurve.generateKeys()
var userPrivateKey = userCurve.getPrivateKey();
I have tried this so far:
//
window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521"
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits"
)
.then(function(key){
//returns a keypair object
console.log(key);
console.log(key.publicKey);
console.log(key.privateKey);
})
.catch(function(err){
console.error(err);
});
But it looks nothing like the node version when i log it
I have a very tiny node script to create a public/private key Is there any way to do it on the client side without having to browserify hole crypto module?
var crypto = require('crypto');
var userCurve = crypto.createECDH('prime256v1');
var userPublicKey = userCurve.generateKeys()
var userPrivateKey = userCurve.getPrivateKey();
I have tried this so far:
// https://github.com/diafygi/webcrypto-examples#ecdh---generatekey
window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521"
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["deriveKey", "deriveBits"] //can be any combination of "deriveKey" and "deriveBits"
)
.then(function(key){
//returns a keypair object
console.log(key);
console.log(key.publicKey);
console.log(key.privateKey);
})
.catch(function(err){
console.error(err);
});
But it looks nothing like the node version when i log it
Share Improve this question edited Apr 13, 2016 at 18:30 Artjom B. 61.9k25 gold badges134 silver badges229 bronze badges asked Apr 13, 2016 at 12:37 EndlessEndless 37.8k13 gold badges116 silver badges137 bronze badges1 Answer
Reset to default 23Let's do a complete elliptic curve Diffie-Hellman (ECDH) exchange to establish a shared secret between two parties. Alice uses Node.js and Bob sits at his browser (a recent version of Chrome or Firefox). (No need to browserify anything.)
(1) Alice generates a private and public key.
const crypto = require('crypto');
const alice = crypto.createECDH('prime256v1');
alice.generateKeys()
const alicePublicKey = alice.getPublicKey('hex')
const alicePrivateKey = alice.getPrivateKey('hex')
console.log(`publicKey: ${alicePublicKey}`)
console.log(`privateKey: ${alicePrivateKey}`)
Example output:
publicKey: 043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5
privateKey: 03ce9cb317c8761699f174943dc9b2d2b7991515b48216a4c677fcf5ee879f2c
(2) Alice sends her public key to Bob (043a3770...
). Bob has written some helpers to convert hex strings to Uint8Arrays
and buffers to hex strings.
const hex2Arr = str => {
if (!str) {
return new Uint8Array()
}
const arr = []
for (let i = 0, len = str.length; i < len; i+=2) {
arr.push(parseInt(str.substr(i, 2), 16))
}
return new Uint8Array(arr)
}
const buf2Hex = buf => {
return Array.from(new Uint8Array(buf))
.map(x => ('00' + x.toString(16)).slice(-2))
.join('')
}
(3) Bob receives Alices's key and computes the shared secret
- He generates his own private and public key
- He exports his public key and sends it to Alice
- He imports Alice's public key
He computes the shared secret using his private and Alice's public key
// Alice's public key (received over an [insecure] connection) const alicePublicKeyHex = '043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5' const alicePublicKey = hex2Arr(alicePublicKeyHex) console.log(`Alice's publicKey: ${alicePublicKeyHex}`) let bob = null // generate Bob's private and public key window.crypto.subtle.generateKey( { name: 'ECDH', namedCurve: 'P-256' }, false, // no need to make Bob's private key exportable ['deriveKey', 'deriveBits']) .then(bobKey => { bob = bobKey // export Bob's public key return window.crypto.subtle.exportKey( 'raw', bobKey.publicKey ) }) .then(bobPublicKeyExported => { const bobPublicKeyHex = buf2Hex(bobPublicKeyExported) // display and send Bob's public key to Alice console.log(`Bob's publicKey: ${bobPublicKeyHex}`) // import Alice's public key return window.crypto.subtle.importKey( 'raw', alicePublicKey, { name: 'ECDH', namedCurve: 'P-256' }, true, []) }) .then(aliceKeyImported => { // use Alice's imported public key and // Bob's private key to compute the shared secret return window.crypto.subtle.deriveBits( { name: 'ECDH', namedCurve: 'P-256', public: aliceKeyImported }, bob.privateKey, 256) }) .then(sharedSecret => { const sharedSecretHex = buf2Hex(sharedSecret) console.log(`sharedSecret: ${sharedSecretHex}`) }) .catch(err => { console.log(err) })
Example output:
Alice's publicKey: 043a3770a8068738ded16c9409e1a6fbf6dde2360ac5b3fd3e5bb8d9fd6adaed6ea83ff5153f58ae13098e86da89df1beb14ef46388d3df76e8fe2ee0ff9e926d5
Bob's publicKey: 04aeceba6ae783c9b705833c2fa8822281f47f6f36bc867e4d398fa7a744d4fc63a010cbce1e6c9ac8858ad376a24ee8551615560f01c8bb63c86335c046b18962
sharedSecret: c26c9f370f001a947d7fec4dc9282d3e9ea718e1de487eb4f6fa7d6f0a311b97
(4) Alice receives Bob's public key (04aece...
). She computes the shared secret as well.
const crypto = require('crypto')
const alice = crypto.createECDH('prime256v1')
// Alice's privateKey (generated previously)
const alicePrivateKey = '937cdd11062b612ff3cb3e4a3c183254b9728b4c8c3a64de799ed196b672734b'
// Bob's publicKey transmitted to Alice
const bobPublicKey = '04aeceba6ae783c9b705833c2fa8822281f47f6f36bc867e4d398fa7a744d4fc63a010cbce1e6c9ac8858ad376a24ee8551615560f01c8bb63c86335c046b18962'
// set Alice's private key (not needed if continuing from (1))
alice.setPrivateKey(alicePrivateKey, 'hex')
const sharedSecret = alice.computeSecret(bobPublicKey, 'hex', 'hex')
console.log(`sharedSecret: ${sharedSecret}`)
Examle output:
sharedSecret: c26c9f370f001a947d7fec4dc9282d3e9ea718e1de487eb4f6fa7d6f0a311b97
The secret is shared (the same).
(5) The shared secret is typically used to derive a symmetric key for encrypting messages between Alice and Bob (and they communicated happily ever after).
Remarks:
Usually there is no need to display or export the private key. Alice would typically continue the computation of the shared secret from step (1) (and omit
alice.setPrivateKey(alicePrivateKey, 'hex')
).As the shared secret is most often used to derive a symmetric key, there is
window.crypto.subtle.deriveKey
andderiveBits
can be ommitted.deriveBits
was used here to illustrate that Alice and Bob indeed agreed on a shared secret.