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
			| 
								 
											2 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * 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);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								})();
							 |