randombytes
randombytes copied to clipboard
Implement browser getRandomValues without depending on crypto
This is based on this discussion
TL;DR: I propose having an implementation of getRandomValues that does not depend on a native implementation of crypto.
I am having an issue with bundling my code and running it in a non-browser environment, using modules that depend on crypto, which depends on randombytes' implementation of getRandomValues. If I bundle my code in "browser" mode, I get the error 'Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11'.
If I don't bundle it in browser mode but force browser fallback for crypto-browserify (which is necessary in my use-case, the javascript VM I'm using does not implement crypto), then I get a circular dependency and getRandomBytes is never implemented.
Is it possible to implement it in this package? If not is there any particular reason? And can I help in some way?
@aki-cat, I support your request for improvement. I faced the same problem. Thanks for your knowledgeable description of the issue 👍
You need a random entropy source, and your VM may not be capable if it doesn't have native crypto
The code below solves my problem with polyfills (like crypto, stream, process) and errors using components from Node.js modules. I used the usual low-level Web Crypto API. Maybe it will be useful for someone.
/**
* Information about Webpack 5 Breaking Changes...
* Webpack 5 introduced breaking changes related to polyfills, especially for Node.js core modules like 'crypto'.
* Previously, Webpack automatically provided polyfills for Node.js core modules, allowing developers to use them in browser environments seamlessly.
* However, starting from Webpack 5, this behavior changed, and Webpack no longer includes polyfills for Node.js core modules by default.
* This change requires developers to find alternative solutions for using Node.js core modules in web environments,
* such as directly utilizing browser-native functionalities or third-party libraries.
* In this utility file, the logic has been refactored to utilize the Web Crypto API directly instead of relying on the 'crypto' module.
* The Web Crypto API provides cryptographic operations in web applications, allowing for secure cryptographic functionalities without the need for polyfills.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto | Web Crypto API – SubtleCrypto}
* @see {@link https://github.com/webpack/changelog-v5?tab=readme-ov-file#automatic-nodejs-polyfills-removed | Webpack 5 – Automatic Node.js Polyfills Removed}
* @see {@link https://stackoverflow.com/questions/67065644/nodejs-crypto-module-not-working-in-browser-after-bundling-with-webpack | NodeJS crypto module not working in browser after bundling with webpack}
*/
import { Buffer } from "buffer";
/**
* Generates cryptographically strong random bytes using the Web Crypto API.
* @param {number} size – The number of random bytes to generate.
* @returns {Promise<Buffer>} A promise that resolves to a buffer containing random bytes.
*/
export async function randomBytes(size: number): Promise<Buffer> {
const array = new Uint8Array(size);
window.crypto.getRandomValues(array);
return Buffer.from(array.buffer);
}
/**
* Creates a hash of the provided data using the Web Crypto API.
* @param {string} data – The data to hash.
* @param {string} algorithm – The hash algorithm to use, e.g., 'SHA-256'.
* @returns {Promise<Buffer>} A promise that resolves to the hash of the data as a buffer.
*/
export async function createHash(data: string, algorithm: string): Promise<Buffer> {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const hashBuffer = await window.crypto.subtle.digest(algorithm, dataBuffer);
return Buffer.from(hashBuffer);
}