Generate shared secret key from Curve25519 (or X25519) asymmetric key pairs in node.js using crypto module

4.5k Views Asked by At

I am trying to create a shared secret key between Curve25519 (or X25519) asymmetric key pairs using key exchange algorithms just like Diffie Hellman key exchange. Diffie Hellman key exchange can be be done in node.js using crypto module in the following code:

const crypto = require('crypto');

// Generate Alice's keys...
const alice = crypto.createDiffieHellman(2048);
const aliceKey = alice.generateKeys(); // Returns public key

// Generate Bob's keys...
const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());
const bobKey = bob.generateKeys(); // Returns public key

// Exchange and generate the secret...
const aliceSecret = alice.computeSecret(bobKey);
const bobSecret = bob.computeSecret(aliceKey);

// Should be equal
console.log(aliceSecret === bobSecret)

X25519 asymmetric keys can be generated using the following code:

const crypto = require('crypto');
const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', {
  publicKeyEncoding: {
    type: 'spki',
    format: 'pem'
  },
  privateKeyEncoding: {
    type: 'pkcs8',
    format: 'pem',
  }
});

The keys are generated without any issue but I don't know how to generate a shared secret key. I tried converting X25519 keys to Diffie Hellman keys using the folowing code:

...
const dhKey= crypto.createDiffieHellman(2048);
// privateKey => Generated in the above code
dhKey.setPrivateKey(privateKey)
// publicKey => Generated in the above code
dhKey.setPublicKey(publicKey)
...

When using the above code when two dhKey are generated and key exchange is performed, it is giving the following error:

Error: Supplied key is too large

Is there any way the shared secret can be generated? Thanks in advance.

1

There are 1 best solutions below

1
On BEST ANSWER

The documentation for this sub API is unfortunately a little thin. I cobbled together an example but without better documentation I'm not sure it's useful.

const crypto = require('crypto');

const aliceKeyPair = crypto.generateKeyPairSync('x25519');

const alicePubExport = aliceKeyPair.publicKey.export(
    {type: 'spki', format: 'pem'}
    );

const bobKeyPair = crypto.generateKeyPairSync('x25519');

const bobPubExport = bobKeyPair.publicKey.export(
    {type: 'spki', format: 'pem'}
    );

const bobKeyAgree = crypto.diffieHellman({
    publicKey : crypto.createPublicKey(alicePubExport),
    privateKey: bobKeyPair.privateKey
});

const aliceKeyAgree = crypto.diffieHellman({
    publicKey : crypto.createPublicKey(bobPubExport),
    privateKey: aliceKeyPair.privateKey
});

console.log(bobKeyAgree.toString('hex'));
console.log(aliceKeyAgree.toString('hex'));

This is missing authentication and therefore is not secure without adding that piece.