You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							191 lines
						
					
					
						
							5.3 KiB
						
					
					
				
			
		
		
	
	
							191 lines
						
					
					
						
							5.3 KiB
						
					
					
				/** | 
						|
 * 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 defined | 
						|
if(forge.random && forge.random.getBytes) { | 
						|
  module.exports = forge.random; | 
						|
  return; | 
						|
} | 
						|
 | 
						|
(function(jQuery) { | 
						|
 | 
						|
// the default prng plugin, uses AES-128 | 
						|
var 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 context | 
						|
var _ctx = spawnPrng(); | 
						|
 | 
						|
// add other sources of entropy only if window.crypto.getRandomValues is not | 
						|
// available -- otherwise this source will be automatically used by the prng | 
						|
var 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 PRNG | 
						|
forge.random.createInstance = spawnPrng; | 
						|
 | 
						|
module.exports = forge.random; | 
						|
 | 
						|
})(typeof(jQuery) !== 'undefined' ? jQuery : null); | 
						|
 | 
						|
})();
 | 
						|
 |