jedisct1 / libsodium

A modern, portable, easy to use crypto library.
https://libsodium.org
Other
12.06k stars 1.72k forks source link

Usage of `require` by `randombytes` does not work in ESM #1180

Closed jboillot closed 2 years ago

jboillot commented 2 years ago

Hello, As I was trying to use randombytes primitive into an ES module I encountered an error. Indeed, in src/libsodium/randombytes/randombytes.c:69 there is a var crypto = require('crypto'); and require is not defined in ESM. A solution would be to modify it to var crypto = await import('crypto'); (if require fails). It works but since the function is not async I had to modify it into:

import('crypto').then((crypto) => {
    var randomValueNodeJS = function() {
        var buf = crypto['randomBytes'](4);
        return (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) >>> 0;
    };
    randomValueNodeJS();
    Module.getRandomValue = randomValueNodeJS;
}).catch((e) => {
    throw 'No secure random number generator found';
});

However, the Module.getRandomValue is set asynchronously so I guess such a modification would not be accepted.

In conclusion, would you have any idea on how to make randombytes work both with CommonJS and ESM? By the way, this is the only require occurrence in the entire library.

Thanks for reading, Jérôme

jboillot commented 2 years ago

I found a workaround: add by myself the definition of Module.getRandomValue before calling randombytes_stir:

const crypto = await import('crypto');
const randomValueNodeJS = () => {
    const buf = crypto.randomBytes(4);
    return (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) >>> 0;
};
randomValueNodeJS();
Module.getRandomValue = randomValueNodeJS;

However I guess it would still be interesting to fix compatibility with ESM in the library.