Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SecureRandom in JavaScript?

Is there a SecureRandom.hex()-like (ruby) function in JavaScript which generates a random hash for me?

like image 870
trnc Avatar asked May 09 '11 06:05

trnc


2 Answers

There is no such helper function in JS. You can generates a fairly random hash using:

function hex(n){
 n = n || 16;
 var result = '';
 while (n--){
  result += Math.floor(Math.random()*16).toString(16).toUpperCase();
 }
 return result;
}

You can modify it to form a guid:

function generateGuid(){
 var result = '', n=0;
 while (n<32){
  result += (~[8,12,16,20].indexOf(n++) ? '-': '') +    
            Math.floor(Math.random()*16).toString(16).toUpperCase();
 }
 return result;
}
like image 189
KooiInc Avatar answered Oct 18 '22 00:10

KooiInc


I was led to this question as a top search engine result using the following keywords:

  • securerandom range js
  • securerandom js

As such, I thought it would be good to update this post with a working answer available today (2019):

The snippet below employs Crypto.getRandomValues() for sourcing random values said to be,

... cryptographically strong ... using a pseudo-random number generator seeded with a value with enough entropy ... suitable for cryptographic usages.

Thus, we have:

var N = 32;
var rng = window.crypto || window.msCrypto;
var rawBytes = Array
              .from(rng.getRandomValues(new Uint8Array(N)))
              .map(c => String.fromCharCode(c))
              .join([]);

Now, below is a fun little hex-encoder I cooked up as a one-liner using some Array functions for looping:

function hexEncode(s) {
  return s.split('').map(c => (c < String.fromCharCode(16) ? '0' : '') + c.charCodeAt(0).toString(16)).join([]);
}

Finally, if you want to combine the two above for generating random hashes, you can just swap out and adapt the .map() function accordingly and package it up like so:

function secureRandomHash(N) {
  N = N || 32; // Coalesce if size parameter N is left undefined

  // TODO: Consider refactoring with lazy-loaded function
  // to set preferred RNG provider, else throw an error here
  // to generate noise that no secure RNG is available for
  // this application.
  var rng = window.crypto || window.msCrypto;

  return Array
           .from(rng.getRandomValues(new Uint8Array(N)))
           .map(c => (c < 16 ? '0' : '') + c.toString(16)).join([]);
}

Happy coding!

Edit: Turns out I ended up needing this in my own project which also implements the suggested TODO in the previous example (lazy-loading) so here we go:

Math.secureRandom = function() {
  var rng = window.crypto || window.msCrypto;
  if (rng === undefined)
    throw 'No suitable RNG found';

  // Lazy-load this if- branch
  Math.secureRandom = function() {
    // More secure implementation of Math.random (https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#Examples)
    return rng.getRandomValues(new Uint32Array(1))[0] / 4294967296;
  };

  return Math.secureRandom();
}

Or if you're feeling really adventurous...

// Auto-upgrade Math.random with a more secure implementation only if crypto is available
(function() {
  var rng = window.crypto || window.msCrypto;
  if (rng === undefined)
    return;

  // Source: https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#Examples
  Math.random = function() {
    return rng.getRandomValues(new Uint32Array(1))[0] / 4294967296;
  };
})();

console.log(Math.random());

Whether extending Math or overwriting Math.random() for a drop-in replacement is appropriate for your application or target audience is left purely as an academic exercise to the implementor. Be sure to check with your architect first! License MIT here of course :)

like image 33
Matt Borja Avatar answered Oct 18 '22 02:10

Matt Borja