123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- var forge = require('./forge');
- require('./util');
- var _crypto = null;
- if(forge.util.isNodejs && !forge.options.usePureJavaScript &&
- !process.versions['node-webkit']) {
- _crypto = require('crypto');
- }
- var prng = module.exports = forge.prng = forge.prng || {};
- prng.create = function(plugin) {
- var ctx = {
- plugin: plugin,
- key: null,
- seed: null,
- time: null,
-
- reseeds: 0,
-
- generated: 0,
-
- keyBytes: ''
- };
-
- var md = plugin.md;
- var pools = new Array(32);
- for(var i = 0; i < 32; ++i) {
- pools[i] = md.create();
- }
- ctx.pools = pools;
-
- ctx.pool = 0;
-
- ctx.generate = function(count, callback) {
-
- if(!callback) {
- return ctx.generateSync(count);
- }
-
- var cipher = ctx.plugin.cipher;
- var increment = ctx.plugin.increment;
- var formatKey = ctx.plugin.formatKey;
- var formatSeed = ctx.plugin.formatSeed;
- var b = forge.util.createBuffer();
-
-
-
-
-
- ctx.key = null;
- generate();
- function generate(err) {
- if(err) {
- return callback(err);
- }
-
- if(b.length() >= count) {
- return callback(null, b.getBytes(count));
- }
-
- if(ctx.generated > 0xfffff) {
- ctx.key = null;
- }
- if(ctx.key === null) {
-
- return forge.util.nextTick(function() {
- _reseed(generate);
- });
- }
-
- var bytes = cipher(ctx.key, ctx.seed);
- ctx.generated += bytes.length;
- b.putBytes(bytes);
-
- ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
- ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
- forge.util.setImmediate(generate);
- }
- };
-
- ctx.generateSync = function(count) {
-
- var cipher = ctx.plugin.cipher;
- var increment = ctx.plugin.increment;
- var formatKey = ctx.plugin.formatKey;
- var formatSeed = ctx.plugin.formatSeed;
-
-
-
-
-
- ctx.key = null;
- var b = forge.util.createBuffer();
- while(b.length() < count) {
-
- if(ctx.generated > 0xfffff) {
- ctx.key = null;
- }
- if(ctx.key === null) {
- _reseedSync();
- }
-
- var bytes = cipher(ctx.key, ctx.seed);
- ctx.generated += bytes.length;
- b.putBytes(bytes);
-
- ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
- ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
- }
- return b.getBytes(count);
- };
-
- function _reseed(callback) {
- if(ctx.pools[0].messageLength >= 32) {
- _seed();
- return callback();
- }
-
- var needed = (32 - ctx.pools[0].messageLength) << 5;
- ctx.seedFile(needed, function(err, bytes) {
- if(err) {
- return callback(err);
- }
- ctx.collect(bytes);
- _seed();
- callback();
- });
- }
-
- function _reseedSync() {
- if(ctx.pools[0].messageLength >= 32) {
- return _seed();
- }
-
- var needed = (32 - ctx.pools[0].messageLength) << 5;
- ctx.collect(ctx.seedFileSync(needed));
- _seed();
- }
-
- function _seed() {
-
- ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1;
-
-
-
-
- var md = ctx.plugin.md.create();
-
- md.update(ctx.keyBytes);
-
-
- var _2powK = 1;
- for(var k = 0; k < 32; ++k) {
- if(ctx.reseeds % _2powK === 0) {
- md.update(ctx.pools[k].digest().getBytes());
- ctx.pools[k].start();
- }
- _2powK = _2powK << 1;
- }
-
- ctx.keyBytes = md.digest().getBytes();
-
-
-
-
- md.start();
- md.update(ctx.keyBytes);
- var seedBytes = md.digest().getBytes();
-
- ctx.key = ctx.plugin.formatKey(ctx.keyBytes);
- ctx.seed = ctx.plugin.formatSeed(seedBytes);
- ctx.generated = 0;
- }
-
- function defaultSeedFile(needed) {
-
- 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);
- };
- }
- var b = forge.util.createBuffer();
- if(getRandomValues) {
- while(b.length() < needed) {
-
-
- var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4);
- var entropy = new Uint32Array(Math.floor(count));
- try {
- getRandomValues(entropy);
- for(var i = 0; i < entropy.length; ++i) {
- b.putInt32(entropy[i]);
- }
- } catch(e) {
-
- if(!(typeof QuotaExceededError !== 'undefined' &&
- e instanceof QuotaExceededError)) {
- throw e;
- }
- }
- }
- }
-
- if(b.length() < needed) {
-
- var hi, lo, next;
- var seed = Math.floor(Math.random() * 0x010000);
- while(b.length() < needed) {
- lo = 16807 * (seed & 0xFFFF);
- hi = 16807 * (seed >> 16);
- lo += (hi & 0x7FFF) << 16;
- lo += hi >> 15;
- lo = (lo & 0x7FFFFFFF) + (lo >> 31);
- seed = lo & 0xFFFFFFFF;
-
- for(var i = 0; i < 3; ++i) {
-
- next = seed >>> (i << 3);
- next ^= Math.floor(Math.random() * 0x0100);
- b.putByte(String.fromCharCode(next & 0xFF));
- }
- }
- }
- return b.getBytes(needed);
- }
-
- if(_crypto) {
-
- ctx.seedFile = function(needed, callback) {
- _crypto.randomBytes(needed, function(err, bytes) {
- if(err) {
- return callback(err);
- }
- callback(null, bytes.toString());
- });
- };
-
- ctx.seedFileSync = function(needed) {
- return _crypto.randomBytes(needed).toString();
- };
- } else {
- ctx.seedFile = function(needed, callback) {
- try {
- callback(null, defaultSeedFile(needed));
- } catch(e) {
- callback(e);
- }
- };
- ctx.seedFileSync = defaultSeedFile;
- }
-
- ctx.collect = function(bytes) {
-
- var count = bytes.length;
- for(var i = 0; i < count; ++i) {
- ctx.pools[ctx.pool].update(bytes.substr(i, 1));
- ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1;
- }
- };
-
- ctx.collectInt = function(i, n) {
- var bytes = '';
- for(var x = 0; x < n; x += 8) {
- bytes += String.fromCharCode((i >> x) & 0xFF);
- }
- ctx.collect(bytes);
- };
-
- ctx.registerWorker = function(worker) {
-
- if(worker === self) {
- ctx.seedFile = function(needed, callback) {
- function listener(e) {
- var data = e.data;
- if(data.forge && data.forge.prng) {
- self.removeEventListener('message', listener);
- callback(data.forge.prng.err, data.forge.prng.bytes);
- }
- }
- self.addEventListener('message', listener);
- self.postMessage({forge: {prng: {needed: needed}}});
- };
- } else {
-
- var listener = function(e) {
- var data = e.data;
- if(data.forge && data.forge.prng) {
- ctx.seedFile(data.forge.prng.needed, function(err, bytes) {
- worker.postMessage({forge: {prng: {err: err, bytes: bytes}}});
- });
- }
- };
-
- worker.addEventListener('message', listener);
- }
- };
- return ctx;
- };
|