summaryrefslogtreecommitdiff
path: root/alarm/node_modules/node-forge/js/prng.js
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-10-18 08:59:09 +0200
committerMinteck <contact@minteck.org>2022-10-18 08:59:09 +0200
commit2c4ae43e688a9873e86211ea0e7aeb9ba770dd77 (patch)
tree17848d95522dab25d3cdeb9c4a6450e2a234861f /alarm/node_modules/node-forge/js/prng.js
parent108525534c28013cfe1897c30e4565f9893f3766 (diff)
downloadpluralconnect-2c4ae43e688a9873e86211ea0e7aeb9ba770dd77.tar.gz
pluralconnect-2c4ae43e688a9873e86211ea0e7aeb9ba770dd77.tar.bz2
pluralconnect-2c4ae43e688a9873e86211ea0e7aeb9ba770dd77.zip
Update
Diffstat (limited to 'alarm/node_modules/node-forge/js/prng.js')
-rw-r--r--alarm/node_modules/node-forge/js/prng.js458
1 files changed, 458 insertions, 0 deletions
diff --git a/alarm/node_modules/node-forge/js/prng.js b/alarm/node_modules/node-forge/js/prng.js
new file mode 100644
index 0000000..72b4594
--- /dev/null
+++ b/alarm/node_modules/node-forge/js/prng.js
@@ -0,0 +1,458 @@
+/**
+ * A javascript implementation of a cryptographically-secure
+ * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed
+ * here though the use of SHA-256 is not enforced; when generating an
+ * a PRNG context, the hashing algorithm and block cipher used for
+ * the generator are specified via a plugin.
+ *
+ * @author Dave Longley
+ *
+ * Copyright (c) 2010-2014 Digital Bazaar, Inc.
+ */
+(function() {
+/* ########## Begin module implementation ########## */
+function initModule(forge) {
+
+var _nodejs = (
+ typeof process !== 'undefined' && process.versions && process.versions.node);
+var _crypto = null;
+if(!forge.disableNativeCode && _nodejs && !process.versions['node-webkit']) {
+ _crypto = require('crypto');
+}
+
+/* PRNG API */
+var prng = forge.prng = forge.prng || {};
+
+/**
+ * Creates a new PRNG context.
+ *
+ * A PRNG plugin must be passed in that will provide:
+ *
+ * 1. A function that initializes the key and seed of a PRNG context. It
+ * will be given a 16 byte key and a 16 byte seed. Any key expansion
+ * or transformation of the seed from a byte string into an array of
+ * integers (or similar) should be performed.
+ * 2. The cryptographic function used by the generator. It takes a key and
+ * a seed.
+ * 3. A seed increment function. It takes the seed and returns seed + 1.
+ * 4. An api to create a message digest.
+ *
+ * For an example, see random.js.
+ *
+ * @param plugin the PRNG plugin to use.
+ */
+prng.create = function(plugin) {
+ var ctx = {
+ plugin: plugin,
+ key: null,
+ seed: null,
+ time: null,
+ // number of reseeds so far
+ reseeds: 0,
+ // amount of data generated so far
+ generated: 0
+ };
+
+ // create 32 entropy pools (each is a message digest)
+ var md = plugin.md;
+ var pools = new Array(32);
+ for(var i = 0; i < 32; ++i) {
+ pools[i] = md.create();
+ }
+ ctx.pools = pools;
+
+ // entropy pools are written to cyclically, starting at index 0
+ ctx.pool = 0;
+
+ /**
+ * Generates random bytes. The bytes may be generated synchronously or
+ * asynchronously. Web workers must use the asynchronous interface or
+ * else the behavior is undefined.
+ *
+ * @param count the number of random bytes to generate.
+ * @param [callback(err, bytes)] called once the operation completes.
+ *
+ * @return count random bytes as a string.
+ */
+ ctx.generate = function(count, callback) {
+ // do synchronously
+ if(!callback) {
+ return ctx.generateSync(count);
+ }
+
+ // simple generator using counter-based CBC
+ 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();
+
+ // reset key for every request
+ ctx.key = null;
+
+ generate();
+
+ function generate(err) {
+ if(err) {
+ return callback(err);
+ }
+
+ // sufficient bytes generated
+ if(b.length() >= count) {
+ return callback(null, b.getBytes(count));
+ }
+
+ // if amount of data generated is greater than 1 MiB, trigger reseed
+ if(ctx.generated > 0xfffff) {
+ ctx.key = null;
+ }
+
+ if(ctx.key === null) {
+ // prevent stack overflow
+ return forge.util.nextTick(function() {
+ _reseed(generate);
+ });
+ }
+
+ // generate the random bytes
+ var bytes = cipher(ctx.key, ctx.seed);
+ ctx.generated += bytes.length;
+ b.putBytes(bytes);
+
+ // generate bytes for a new key and seed
+ ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
+ ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
+
+ forge.util.setImmediate(generate);
+ }
+ };
+
+ /**
+ * Generates random bytes synchronously.
+ *
+ * @param count the number of random bytes to generate.
+ *
+ * @return count random bytes as a string.
+ */
+ ctx.generateSync = function(count) {
+ // simple generator using counter-based CBC
+ var cipher = ctx.plugin.cipher;
+ var increment = ctx.plugin.increment;
+ var formatKey = ctx.plugin.formatKey;
+ var formatSeed = ctx.plugin.formatSeed;
+
+ // reset key for every request
+ ctx.key = null;
+
+ var b = forge.util.createBuffer();
+ while(b.length() < count) {
+ // if amount of data generated is greater than 1 MiB, trigger reseed
+ if(ctx.generated > 0xfffff) {
+ ctx.key = null;
+ }
+
+ if(ctx.key === null) {
+ _reseedSync();
+ }
+
+ // generate the random bytes
+ var bytes = cipher(ctx.key, ctx.seed);
+ ctx.generated += bytes.length;
+ b.putBytes(bytes);
+
+ // generate bytes for a new key and seed
+ ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
+ ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
+ }
+
+ return b.getBytes(count);
+ };
+
+ /**
+ * Private function that asynchronously reseeds a generator.
+ *
+ * @param callback(err) called once the operation completes.
+ */
+ function _reseed(callback) {
+ if(ctx.pools[0].messageLength >= 32) {
+ _seed();
+ return callback();
+ }
+ // not enough seed data...
+ var needed = (32 - ctx.pools[0].messageLength) << 5;
+ ctx.seedFile(needed, function(err, bytes) {
+ if(err) {
+ return callback(err);
+ }
+ ctx.collect(bytes);
+ _seed();
+ callback();
+ });
+ }
+
+ /**
+ * Private function that synchronously reseeds a generator.
+ */
+ function _reseedSync() {
+ if(ctx.pools[0].messageLength >= 32) {
+ return _seed();
+ }
+ // not enough seed data...
+ var needed = (32 - ctx.pools[0].messageLength) << 5;
+ ctx.collect(ctx.seedFileSync(needed));
+ _seed();
+ }
+
+ /**
+ * Private function that seeds a generator once enough bytes are available.
+ */
+ function _seed() {
+ // create a plugin-based message digest
+ var md = ctx.plugin.md.create();
+
+ // digest pool 0's entropy and restart it
+ md.update(ctx.pools[0].digest().getBytes());
+ ctx.pools[0].start();
+
+ // digest the entropy of other pools whose index k meet the
+ // condition '2^k mod n == 0' where n is the number of reseeds
+ var k = 1;
+ for(var i = 1; i < 32; ++i) {
+ // prevent signed numbers from being used
+ k = (k === 31) ? 0x80000000 : (k << 2);
+ if(k % ctx.reseeds === 0) {
+ md.update(ctx.pools[i].digest().getBytes());
+ ctx.pools[i].start();
+ }
+ }
+
+ // get digest for key bytes and iterate again for seed bytes
+ var keyBytes = md.digest().getBytes();
+ md.start();
+ md.update(keyBytes);
+ var seedBytes = md.digest().getBytes();
+
+ // update
+ ctx.key = ctx.plugin.formatKey(keyBytes);
+ ctx.seed = ctx.plugin.formatSeed(seedBytes);
+ ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1;
+ ctx.generated = 0;
+ }
+
+ /**
+ * The built-in default seedFile. This seedFile is used when entropy
+ * is needed immediately.
+ *
+ * @param needed the number of bytes that are needed.
+ *
+ * @return the random bytes.
+ */
+ function defaultSeedFile(needed) {
+ // use window.crypto.getRandomValues strong source of entropy if available
+ var getRandomValues = null;
+ if(typeof window !== 'undefined') {
+ var _crypto = window.crypto || window.msCrypto;
+ if(_crypto && _crypto.getRandomValues) {
+ getRandomValues = function(arr) {
+ return _crypto.getRandomValues(arr);
+ };
+ }
+ }
+
+ var b = forge.util.createBuffer();
+ if(getRandomValues) {
+ while(b.length() < needed) {
+ // max byte length is 65536 before QuotaExceededError is thrown
+ // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues
+ 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) {
+ /* only ignore QuotaExceededError */
+ if(!(typeof QuotaExceededError !== 'undefined' &&
+ e instanceof QuotaExceededError)) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ // be sad and add some weak random data
+ if(b.length() < needed) {
+ /* Draws from Park-Miller "minimal standard" 31 bit PRNG,
+ implemented with David G. Carta's optimization: with 32 bit math
+ and without division (Public Domain). */
+ 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;
+
+ // consume lower 3 bytes of seed
+ for(var i = 0; i < 3; ++i) {
+ // throw in more pseudo random
+ next = seed >>> (i << 3);
+ next ^= Math.floor(Math.random() * 0x0100);
+ b.putByte(String.fromCharCode(next & 0xFF));
+ }
+ }
+ }
+
+ return b.getBytes(needed);
+ }
+ // initialize seed file APIs
+ if(_crypto) {
+ // use nodejs async API
+ ctx.seedFile = function(needed, callback) {
+ _crypto.randomBytes(needed, function(err, bytes) {
+ if(err) {
+ return callback(err);
+ }
+ callback(null, bytes.toString());
+ });
+ };
+ // use nodejs sync API
+ 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;
+ }
+
+ /**
+ * Adds entropy to a prng ctx's accumulator.
+ *
+ * @param bytes the bytes of entropy as a string.
+ */
+ ctx.collect = function(bytes) {
+ // iterate over pools distributing entropy cyclically
+ 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;
+ }
+ };
+
+ /**
+ * Collects an integer of n bits.
+ *
+ * @param i the integer entropy.
+ * @param n the number of bits in the integer.
+ */
+ ctx.collectInt = function(i, n) {
+ var bytes = '';
+ for(var x = 0; x < n; x += 8) {
+ bytes += String.fromCharCode((i >> x) & 0xFF);
+ }
+ ctx.collect(bytes);
+ };
+
+ /**
+ * Registers a Web Worker to receive immediate entropy from the main thread.
+ * This method is required until Web Workers can access the native crypto
+ * API. This method should be called twice for each created worker, once in
+ * the main thread, and once in the worker itself.
+ *
+ * @param worker the worker to register.
+ */
+ ctx.registerWorker = function(worker) {
+ // worker receives random bytes
+ 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 {
+ // main thread sends random bytes upon request
+ 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}}});
+ });
+ }
+ };
+ // TODO: do we need to remove the event listener when the worker dies?
+ worker.addEventListener('message', listener);
+ }
+ };
+
+ return ctx;
+};
+
+} // end module implementation
+
+/* ########## Begin module wrapper ########## */
+var name = 'prng';
+if(typeof define !== 'function') {
+ // NodeJS -> AMD
+ if(typeof module === 'object' && module.exports) {
+ var nodeJS = true;
+ define = function(ids, factory) {
+ factory(require, module);
+ };
+ } else {
+ // <script>
+ if(typeof forge === 'undefined') {
+ forge = {};
+ }
+ return initModule(forge);
+ }
+}
+// AMD
+var deps;
+var defineFunc = function(require, module) {
+ module.exports = function(forge) {
+ var mods = deps.map(function(dep) {
+ return require(dep);
+ }).concat(initModule);
+ // handle circular dependencies
+ forge = forge || {};
+ forge.defined = forge.defined || {};
+ if(forge.defined[name]) {
+ return forge[name];
+ }
+ forge.defined[name] = true;
+ for(var i = 0; i < mods.length; ++i) {
+ mods[i](forge);
+ }
+ return forge[name];
+ };
+};
+var tmpDefine = define;
+define = function(ids, factory) {
+ deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
+ if(nodeJS) {
+ delete define;
+ return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
+ }
+ define = tmpDefine;
+ return define.apply(null, Array.prototype.slice.call(arguments, 0));
+};
+define(['require', 'module', './md', './util'], function() {
+ defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
+});
+
+})();