Node.js has an in-built crypto module and which can be used to run code using Javascript. This example implements the Elliptic Curve Diffie Hellman (ECDH) key exchange method.
Node.js Elliptic Curve Diffie Hellman |
Theory
We defined \(y^2=x^3+ax+b\) over \(\mathbb{F}_p\), and the parameters as \(T=(p;a;b;G;n;h)\). Curves include [ref]:
- 112-bit Elliptic curve: secp112r1. This has the strength of 56-bit symmetric key and 512-bit RSA. The parameters are p=0x2ABF62E35E668076BEA, a=0xDB7BEAD2088, b=0x659E11702B, G=0x04 09487239995A5EE76B55F9C2F098A89CE5AF8724C0A23E00FF77500, n=0x2ABF62E35E7628DFAC65
- 128-bit Elliptic curve: secp128r1. This has the strength of 64-bit symmetric key and 704-bit RSA. The parameters are p=0xFFFFFFDFFFFFFFFFFFFFFFFFFFFFFF, a=0xFFFFFDFFFFFFFFFFFFFFFFFFFF, b=0x1079F43DD824993C2CEE5ED3, G=0x04 161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13, n= FFFFFFFE0000000075A30D1B9038A115
Theory
Elliptic Curve Diffie Hellman (ECDH) is used to create a shared key. In this example we use secp256k1 (as used in Bitcoin) to generate points on the curve. Its format is:
\(y^2 = x^3+7\)
with a prime number (p) of 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F
and which is \( 2^{256} - 2^{32} - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 \)
All our operations will be (mod p)
Bob will generate a public key and a private key by taking a point on the curve. The private key is a random number (\(d_B\)) and the Bob's public key (\(Q_B\)) will be:
\(Q_B = d_B \times G\)
Alice will do the same and generate her public key (\(Q_A\)) from her private key (\(d_A\)):
\(Q_A = d_A \times G\)
They then exchange their public keys. Alice will then use Bob's public key and her private key to calculate:
SharekeyAlice\( = d_A \times Q_B\)
This will be the same as:
SharekeyAlice\( = d_A \times d_B \times G\)
Bob will then use Alice's public key and his private key to determine:
SharekeyBob \(= d_B \times Q_A\)
This will be the same as:
SharekeyBob\( = d_B \times d_A \times G\)
And the keys will thus match.
The following illustrates the process:
Sample run
A sample run is:
Type: Oakley-EC2N-3 Alice private key: 0175333ce581c19a1176ddb05944863762482d8b Alice public key: 04009a9bc6d177246b81daa7aa9ed7d30cb895cab505ce70d29fc751cf76f5b9d60470ff5232fd79ca Bob private key: a157eca010c9238e0efdee7f4c0eb94fb0ef7f Bob public key: 040247eb8c5a5412569a1ee982654bc8591a9f3f15007293d6f5dcabbff1abee894fbe9ff3e69058a3 Alice shared key: 0314fcad6adfe61f5f1a01e41a2143ebdb8eb2c3 Bob shared key: 0314fcad6adfe61f5f1a01e41a2143ebdb8eb2c3
In this case the public key has 768 bits (192 hex characters). The following is some sample code
const crypto = require('crypto'); const args = process.argv.slice(3); type = args[0]; console.log("Type:\t",type); // Generate Alice's keys... const alice = crypto.createECDH(type); const aliceKey = alice.generateKeys(); // Generate Bob's keys... const bob = crypto.createECDH(type); const bobKey = bob.generateKeys(); console.log("\nAlice private key:\t",alice.getPrivateKey().toString('hex')); console.log("Alice public key:\t",aliceKey.toString('hex')) console.log("\nBob private key:\t",bob.getPrivateKey().toString('hex')); console.log("Bob public key:\t",bobKey.toString('hex')); // Exchange and generate the secret... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); console.log("\nAlice shared key:\t",aliceSecret.toString('hex')) console.log("Bob shared key:\t\t",bobSecret.toString('hex'));