| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 | /** * An API for getting cryptographically-secure random bytes. The bytes are * generated using the Fortuna algorithm devised by Bruce Schneier and * Niels Ferguson. * * Getting strong random bytes is not yet easy to do in javascript. The only * truish random entropy that can be collected is from the mouse, keyboard, or * from timing with respect to page loads, etc. This generator makes a poor * attempt at providing random bytes when those sources haven't yet provided * enough entropy to initially seed or to reseed the PRNG. * * @author Dave Longley * * Copyright (c) 2009-2014 Digital Bazaar, Inc. */var forge = require('./forge');require('./aes');require('./sha256');require('./prng');require('./util');(function() {// forge.random already definedif(forge.random && forge.random.getBytes) {  module.exports = forge.random;  return;}(function(jQuery) {// the default prng plugin, uses AES-128var prng_aes = {};var _prng_aes_output = new Array(4);var _prng_aes_buffer = forge.util.createBuffer();prng_aes.formatKey = function(key) {  // convert the key into 32-bit integers  var tmp = forge.util.createBuffer(key);  key = new Array(4);  key[0] = tmp.getInt32();  key[1] = tmp.getInt32();  key[2] = tmp.getInt32();  key[3] = tmp.getInt32();  // return the expanded key  return forge.aes._expandKey(key, false);};prng_aes.formatSeed = function(seed) {  // convert seed into 32-bit integers  var tmp = forge.util.createBuffer(seed);  seed = new Array(4);  seed[0] = tmp.getInt32();  seed[1] = tmp.getInt32();  seed[2] = tmp.getInt32();  seed[3] = tmp.getInt32();  return seed;};prng_aes.cipher = function(key, seed) {  forge.aes._updateBlock(key, seed, _prng_aes_output, false);  _prng_aes_buffer.putInt32(_prng_aes_output[0]);  _prng_aes_buffer.putInt32(_prng_aes_output[1]);  _prng_aes_buffer.putInt32(_prng_aes_output[2]);  _prng_aes_buffer.putInt32(_prng_aes_output[3]);  return _prng_aes_buffer.getBytes();};prng_aes.increment = function(seed) {  // FIXME: do we care about carry or signed issues?  ++seed[3];  return seed;};prng_aes.md = forge.md.sha256;/** * Creates a new PRNG. */function spawnPrng() {  var ctx = forge.prng.create(prng_aes);  /**   * Gets random bytes. If a native secure crypto API is unavailable, this   * method tries to make the bytes more unpredictable by drawing from data that   * can be collected from the user of the browser, eg: mouse movement.   *   * If a callback is given, this method will be called asynchronously.   *   * @param count the number of random bytes to get.   * @param [callback(err, bytes)] called once the operation completes.   *   * @return the random bytes in a string.   */  ctx.getBytes = function(count, callback) {    return ctx.generate(count, callback);  };  /**   * Gets random bytes asynchronously. If a native secure crypto API is   * unavailable, this method tries to make the bytes more unpredictable by   * drawing from data that can be collected from the user of the browser,   * eg: mouse movement.   *   * @param count the number of random bytes to get.   *   * @return the random bytes in a string.   */  ctx.getBytesSync = function(count) {    return ctx.generate(count);  };  return ctx;}// create default prng contextvar _ctx = spawnPrng();// add other sources of entropy only if window.crypto.getRandomValues is not// available -- otherwise this source will be automatically used by the prngvar getRandomValues = null;var globalScope = forge.util.globalScope;var _crypto = globalScope.crypto || globalScope.msCrypto;if(_crypto && _crypto.getRandomValues) {  getRandomValues = function(arr) {    return _crypto.getRandomValues(arr);  };}if(forge.options.usePureJavaScript ||  (!forge.util.isNodejs && !getRandomValues)) {  // if this is a web worker, do not use weak entropy, instead register to  // receive strong entropy asynchronously from the main thread  if(typeof window === 'undefined' || window.document === undefined) {    // FIXME:  }  // get load time entropy  _ctx.collectInt(+new Date(), 32);  // add some entropy from navigator object  if(typeof(navigator) !== 'undefined') {    var _navBytes = '';    for(var key in navigator) {      try {        if(typeof(navigator[key]) == 'string') {          _navBytes += navigator[key];        }      } catch(e) {        /* Some navigator keys might not be accessible, e.g. the geolocation          attribute throws an exception if touched in Mozilla chrome://          context.          Silently ignore this and just don't use this as a source of          entropy. */      }    }    _ctx.collect(_navBytes);    _navBytes = null;  }  // add mouse and keyboard collectors if jquery is available  if(jQuery) {    // set up mouse entropy capture    jQuery().mousemove(function(e) {      // add mouse coords      _ctx.collectInt(e.clientX, 16);      _ctx.collectInt(e.clientY, 16);    });    // set up keyboard entropy capture    jQuery().keypress(function(e) {      _ctx.collectInt(e.charCode, 8);    });  }}/* Random API */if(!forge.random) {  forge.random = _ctx;} else {  // extend forge.random with _ctx  for(var key in _ctx) {    forge.random[key] = _ctx[key];  }}// expose spawn PRNGforge.random.createInstance = spawnPrng;module.exports = forge.random;})(typeof(jQuery) !== 'undefined' ? jQuery : null);})();
 |