jedisct1 / libsodium.js

libsodium compiled to Webassembly and pure JavaScript, with convenient wrappers.
Other
968 stars 138 forks source link

`crypto_kdf_derive_from_key` to support the full `uint64_t` space for subkey_id #329

Closed nikgraf closed 9 months ago

nikgraf commented 9 months ago

In libsodium the subkey_id is a uint64_t. In the JavaScript API of libsodium the subkey_id must be a unsigned integer of type number. But in JavaScript the unsigned integer space is limited to 2^53 - 1.

The check is here: https://github.com/jedisct1/libsodium.js/blob/d96986a6e69ef9da64d3eca0b62b736da5afc4d0/wrapper/macros/input_uint.js#L5

So in case a subkey_id was created directly with the C implementation and then you basically can't use this subkey_id in the JS implementation of Libsodium.

I can imagine that a breaking change is undesired so one way around it could be to also allow BigInt as input and then check that the value is lower than 2^64 - 1.

Currently this is happening:

const sodium = require("libsodium-wrappers");

const master_key = sodium.crypto_kdf_keygen();

const bigIntValue = BigInt(10);
const sub_key_4 = sodium.crypto_kdf_derive_from_key(32, bigIntValue, "context", master_key);
// Uncaught TypeError: subkey_id must be an unsigned integer
jedisct1 commented 9 months ago

To be honest, I had never imagined that the subkey ID would be used as a tweak. I expected this to be a simple counter for a small, comptime-known amount of subkeys.

Having used a 64-bit integer here may have been a bad design decision, as deriving more than 2^48 128-bit keys would be unsafe.

With subkeys that are 160 bits or more, this is fine, though. I guess I urgently need to document this footgun.

nikgraf commented 9 months ago

Thanks for the clarification!