0

I am trying to implement diffie hellman using libsodium but I am getting a different shared secret key when doing an exchange.

async function handleSharedSecret() {
 await _sodium.ready;
 const sodium = _sodium;
 const secretKey = sodium.crypto_kx_client_session_keys(
      sodium.crypto_scalarmult_base(
        sodium.from_base64(privateKeyRef.current.value)
      ),
      sodium.from_base64(privateKeyRef.current.value),
      sodium.from_base64(publicKeyRef.current.value)
    );
   
    setSharedSecretKey(sodium.to_base64(secretKey.sharedRx));
}

The output generated is this

Bob's Public Key: _nGMQavOQuMf7FUyUYfaqvfBcj9hAFJPcc-Bo0JHEEw

Alice's Private Key: vrzVDcdX7PyN1BGo00CzJ_vdvWuOnK_sUeHGQbDAZHQ

Shared Secret Key: 8oVOLsEnxq7XLX6ZXuV3wGgjtyGO7bN8SOvFK1BaB0o




Alice's Public Key: SaKUG5MX0m5XP7Tbf8-LjHzhWdxn9Qn6ndRVBP1YeRI

Bob's Private Key: hzFTBbnif8I37ySoDi5eqtEUechU_dBE7n-oFYNENh0

Shared Secret Key: XnwyWbm2kZFddqx67-QAC1K3Sn7trh5Suk15zl4NmcA

The shared secrets keys don't match. Please help me resolve this.

Maverick 2000
  • 15
  • 1
  • 4

2 Answers2

1

The correct way to do so using libsodium would be this code:

async function diffieHellmanKeyExchange() {
  await sodium.ready;

  const serverKeyPair = sodium.crypto_kx_keypair();
  const clientKeyPair = sodium.crypto_kx_keypair();

  const serverSharedSecret = sodium.crypto_kx_server_session_keys(
    serverKeyPair.publicKey,
    serverKeyPair.privateKey,
    clientKeyPair.publicKey
  );

  const clientSharedSecret = sodium.crypto_kx_client_session_keys(
    clientKeyPair.publicKey,
    clientKeyPair.privateKey,
    serverKeyPair.publicKey
  );

  const serverSharedSecretHex = sodium.to_hex(serverSharedSecret.sharedRx);
  const clientSharedSecretHex = sodium.to_hex(clientSharedSecret.sharedTx);

  console.log('Match:', serverSharedSecretHex === clientSharedSecretHex);
}

diffieHellmanKeyExchange();

Read more at Official Documentation For libsodium.

If you need to , instead of calling sodium.crypto_kx_keypair(), you can use a custom object like following:

const clientKeyPair  = {
    publicKey: sodium.from_hex(publicKey),
    privateKey: sodium.from_hex(privateKey)
};
  • Thanks for the quick response but I am trying to get the public and private keys as user input. How can i convert them back to keypair objects? – Maverick 2000 Jun 22 '23 at 11:57
  • @Maverick2000 I edited my answer and I hope it is helpful. You can use the custom object to get what you need from user input. In this case, it would be publicKey and privateKey. Also, you could use spread syntax to change only the keys to what you want. – Mohsen Robatjazi Jun 22 '23 at 15:57
  • I tried to do that but it still generates different shared secret keys, My logic is that Bob generates a pair of keys and Alice generates a pair of keys. If bob wants to encrypt a file he inputs Alice's public key and his private key, Bob's public key is derived from his private key using crypto_scalarmult_base(). Hence providing 3 keys to crypto_kx_client_session_keys() – Maverick 2000 Jun 22 '23 at 17:07
  • Is it because I'm passing them as strings? – Maverick 2000 Jun 22 '23 at 18:29
0

I got it working. Basically you need to define two separate functions, to generate the same shared secret key. If someone has more expertise in this please do explain why.

 async function handleGetEncryptionKey(alicePublicKey, bobPrivateKey) {
    try {
      await _sodium.ready;
      const sodium = _sodium;
      const serverSharedSecret = sodium.crypto_kx_server_session_keys(
        sodium.crypto_scalarmult_base(sodium.from_hex(bobPrivateKey)),
        sodium.from_hex(bobPrivateKey),
        sodium.from_hex(alicePublicKey)
      );
      console.log(
        "Encryption Key: ",
        sodium.to_hex(serverSharedSecret.sharedRx)
      );
      setSharedSecretKey(sodium.to_hex(serverSharedSecret.sharedRx));
    } catch (error) {
      setVariant("danger");
      setSyslog(error.message);
    }
  }
 async function handleGetDecryptionKey(bobPublicKey, alicePrivateKey) {
    try {
      await _sodium.ready;
      const sodium = _sodium;
      const clientSharedSecret = sodium.crypto_kx_client_session_keys(
        sodium.crypto_scalarmult_base(sodium.from_hex(alicePrivateKey)),
        sodium.from_hex(alicePrivateKey),
        sodium.from_hex(bobPublicKey)
      );
      console.log(
        "Decryption Key: ",
        sodium.to_hex(clientSharedSecret.sharedTx)
      );
      setSharedSecretKey(sodium.to_hex(clientSharedSecret.sharedTx));
    } catch (error) {
      setVariant("danger");
      setSyslog(error.message);
    }
  }

This will generate the proper shared secret key for encryption and decryption

For Encryption:
Bob Private Key: c09e3e89a590d449c1dfe6ad82b44438bfe59d146fe4c7e407690c6b84e22077
Alice Public Key: 20f40d0d267f00d67651375ed172a1e7f16e1b085afb09c6c487feaa300e8d31

Shared Secret: bdf9835b9f6c758278c090b4af9539f7843030285cdeafdcfcf6d34c0fbc29b3

For Decryption:
Alice Private Key: 20ff8ef237f2e421b21e33d82fdb0ee8a57e67d572d502be7d4f9916fdcd1e9e
Bob Public Key: a9e7e836a3fd987f93fc332d21a8c8200aa4962ac35e3c8da02135c358df9b19

Shared Secret: bdf9835b9f6c758278c090b4af9539f7843030285cdeafdcfcf6d34c0fbc29b3

As you can see we have the same shared secret key by calling separate functions.

Maverick 2000
  • 15
  • 1
  • 4