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.
		
		
		
		
		
			
		
			
				
					
					
						
							192 lines
						
					
					
						
							5.3 KiB
						
					
					
				
			
		
		
	
	
							192 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);
 | 
						|
 | 
						|
})();
 |