Spaces:
Configuration error
Configuration error
/** | |
* 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); | |
})(); | |