Secure random numbers in javascript?

JavascriptCryptography

Javascript Problem Overview


How do I generate cryptographically secure random numbers in javascript?

Javascript Solutions


Solution 1 - Javascript

There's been discussion at WHATWG on adding this to the window.crypto object. You can read the discussion and check out the proposed API and webkit bug (22049).

Just tested the following code in Chrome to get a random byte:

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();

Solution 2 - Javascript

In order, I think your best bets are:

  1. window.crypto.getRandomValues or window.msCrypto.getRandomValues
  2. The sjcl library's randomWords function (http://crypto.stanford.edu/sjcl/)
  3. The isaac library's random number generator (which is seeded by Math.random, so not really cryptographically secure) (https://github.com/rubycon/isaac.js)

window.crypto.getRandomValues has been implemented in Chrome for a while now, and relatively recently in Firefox as well. Unfortunately, Internet Explorer 10 and before do not implement the function. IE 11 has window.msCrypto, which accomplishes the same thing. sjcl has a great random number generator seeded from mouse movements, but there's always a chance that either the mouse won't have moved sufficiently to seed the generator, or that the user is on a mobile device where there is no mouse movement whatsoever. Thus, I recommend having a fallback case where you can still get a non-secure random number if there is no choice. Here's how I've handled this:

function GetRandomWords (wordCount) {
    var randomWords;
    
    // First we're going to try to use a built-in CSPRNG
    if (window.crypto && window.crypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.crypto.getRandomValues(randomWords);
    }
    // Because of course IE calls it msCrypto instead of being standard
    else if (window.msCrypto && window.msCrypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.msCrypto.getRandomValues(randomWords);
    }
    // So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
    // sjcl might help us out here
    else if (sjcl.random.isReady()) {
        randomWords = sjcl.random.randomWords(wordCount);
    }
    // Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
    // so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
    // have to make to crack the password.
    else {
        randomWords = [];
        for (var i = 0; i < wordCount; i++) {
            randomWords.push(isaac.rand());
        }
    }
    
    return randomWords;
};

You'll need to include sjcl.js and isaac.js for that implementation, and be sure to start the sjcl entropy collector as soon as your page is loaded:

sjcl.random.startCollectors();

sjcl is dual-licensed BSD and GPL, while isaac.js is MIT, so it's perfectly safe to use either of those in any project. As mentioned in another answer, clipperz is another option, however for whatever bizarre reason, it is licensed under the AGPL. I have yet to see anyone who seems to understand what implications that has for a JavaScript library, but I'd universally avoid it.

One way to improve the code I've posted might be to store the state of the isaac random number generator in localStorage, so it isn't reseeded every time the page is loaded. Isaac will generate a random sequence, but for cryptography purposes, the seed is all-important. Seeding with Math.random is bad, but at least a little less bad if it isn't necessarily on every page load.

Solution 3 - Javascript

You can for instance use mouse movement as seed for random numbers, read out time and mouse position whenever the onmousemove event happens, feed that data to a whitening function and you will have some first class random at hand. Though do make sure that user has moved the mouse sufficiently before you use the data.

Edit: I have myself played a bit with the concept by making a password generator, I wouldn't guarantee that my whitening function is flawless, but being constantly reseeded I'm pretty sure that it's plenty for the job: ebusiness.hopto.org/generator.htm

Edit2: It now sort of works with smartphones, but only by disabling touch functionality while the entropy is gathered. Android won't work properly any other way.

Solution 4 - Javascript

Use window.crypto.getRandomValues, like this:

var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);

This is supported in all modern browsers and uses the operating system's random generator (e.g. /dev/urandom). If you need IE11 compatibility, you have to use their prefixed implementation viavar crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) though.

Note that the window.crypto API can also generate keys outright, which may be the better option.

Solution 5 - Javascript

Crypto-strong

to get cryptographic strong number from range [0, 1) (similar to Math.random()) use crypto:

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

console.log( random() );

Solution 6 - Javascript

You might want to try http://sourceforge.net/projects/clipperzlib/ It has an implementation of Fortuna which is a cryptographically secure random number generator. (Take a look at src/js/Clipperz/Crypto/PRNG.js). It appears to use the mouse as a source of randomness as well.

Solution 7 - Javascript

First of all, you need a source of entropy. For example, movement of the mouse, password, or any other. But all of these sources are very far from random, and guarantee you 20 bits of entropy, rarely more. The next step that you need to take is to use the mechanism like "Password-Based KDF" it will make computationally difficult to distinguish data from random.

Solution 8 - Javascript

Many years ago, you had to implement your own random number generator and seed it with entropy collected by mouse movement and timing information. This was the Phlogiston Era of JavaScript cryptography. These days we have window.crypto to work with.

If you need a random integer, random-number-csprng is a great choice. It securely generates a series of random bytes and then converts it into an unbiased random integer.

const randomInt = require("random-number-csprng");
(async function() {
    let random = randomInt(10, 30);
    console.log(`Your random number: ${random}`);
})();

If you need a random floating point number, you'll need to do a little more work. Generally, though, secure randomness is an integer problem, not a floating point problem.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKyleView Question on Stackoverflow
Solution 1 - JavascriptPaul VView Answer on Stackoverflow
Solution 2 - JavascriptZeroGView Answer on Stackoverflow
Solution 3 - JavascriptaaaaaaaaaaaaView Answer on Stackoverflow
Solution 4 - JavascriptphihagView Answer on Stackoverflow
Solution 5 - JavascriptKamil KiełczewskiView Answer on Stackoverflow
Solution 6 - JavascriptameerView Answer on Stackoverflow
Solution 7 - Javascriptuser2674414View Answer on Stackoverflow
Solution 8 - JavascriptScott ArciszewskiView Answer on Stackoverflow