PageSourceSearch

https://e-licitatie.ro/scripts/forge-master/js/prng.js

js e-licitatie.ro collected 2026-09-24 18:17:40 UTC 13,165 bytes, 458 lines download raw bytes

1/**
2 * A javascript implementation of a cryptographically-secure
3 * Pseudo Random Number Generator (PRNG). The Fortuna algorithm is followed
4 * here though the use of SHA-256 is not enforced; when generating an
5 * a PRNG context, the hashing algorithm and block cipher used for
6 * the generator are specified via a plugin.
7 *
8 * @author Dave Longley
9 *
10 * Copyright (c) 2010-2014 Digital Bazaar, Inc.
11 */
12(function() {
13/* ########## Begin module implementation ########## */
14function initModule(forge) {
15
16var _nodejs = (
17  typeof process !== 'undefined' && process.versions && process.versions.node);
18var _crypto = null;
19if(!forge.disableNativeCode && _nodejs && !process.versions['node-webkit']) {
20  _crypto = require('crypto');
21}
22
23/* PRNG API */
24var prng = forge.prng = forge.prng || {};
25
26/**
27 * Creates a new PRNG context.
28 *
29 * A PRNG plugin must be passed in that will provide:
30 *
31 * 1. A function that initializes the key and seed of a PRNG context. It
32 *   will be given a 16 byte key and a 16 byte seed. Any key expansion
33 *   or transformation of the seed from a byte string into an array of
34 *   integers (or similar) should be performed.
35 * 2. The cryptographic function used by the generator. It takes a key and
36 *   a seed.
37 * 3. A seed increment function. It takes the seed and returns seed + 1.
38 * 4. An api to create a message digest.
39 *
40 * For an example, see random.js.
41 *
42 * @param plugin the PRNG plugin to use.
43 */
44prng.create = function(plugin) {
45  var ctx = {
46    plugin: plugin,
47    key: null,
48    seed: null,
49    time: null,
50    // number of reseeds so far
51    reseeds: 0,
52    // amount of data generated so far
53    generated: 0
54  };
55
56  // create 32 entropy pools (each is a message digest)
57  var md = plugin.md;
58  var pools = new Array(32);
59  for(var i = 0; i < 32; ++i) {
60    pools[i] = md.create();
61  }
62  ctx.pools = pools;
63
64  // entropy pools are written to cyclically, starting at index 0
65  ctx.pool = 0;
66
67  /**
68   * Generates random bytes. The bytes may be generated synchronously or
69   * asynchronously. Web workers must use the asynchronous interface or
70   * else the behavior is undefined.
71   *
72   * @param count the number of random bytes to generate.
73   * @param [callback(err, bytes)] called once the operation completes.
74   *
75   * @return count random bytes as a string.
76   */
77  ctx.generate = function(count, callback) {
78    // do synchronously
79    if(!callback) {
80      return ctx.generateSync(count);
81    }
82
83    // simple generator using counter-based CBC
84    var cipher = ctx.plugin.cipher;
85    var increment = ctx.plugin.increment;
86    var formatKey = ctx.plugin.formatKey;
87    var formatSeed = ctx.plugin.formatSeed;
88    var b = forge.util.createBuffer();
89
90    // reset key for every request
91    ctx.key = null;
92
93    generate();
94
95    function generate(err) {
96      if(err) {
97        return callback(err);
98      }
99
100      // sufficient bytes generated
101      if(b.length() >= count) {
102        return callback(null, b.getBytes(count));
103      }
104
105      // if amount of data generated is greater than 1 MiB, trigger reseed
106      if(ctx.generated > 0xfffff) {
107        ctx.key = null;
108      }
109
110      if(ctx.key === null) {
111        // prevent stack overflow
112        return forge.util.nextTick(function() {
113          _reseed(generate);
114        });
115      }
116
117      // generate the random bytes
118      var bytes = cipher(ctx.key, ctx.seed);
119      ctx.generated += bytes.length;
120      b.putBytes(bytes);
121
122      // generate bytes for a new key and seed
123      ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
124      ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
125
126      forge.util.setImmediate(generate);
127    }
128  };
129
130  /**
131   * Generates random bytes synchronously.
132   *
133   * @param count the number of random bytes to generate.
134   *
135   * @return count random bytes as a string.
136   */
137  ctx.generateSync = function(count) {
138    // simple generator using counter-based CBC
139    var cipher = ctx.plugin.cipher;
140    var increment = ctx.plugin.increment;
141    var formatKey = ctx.plugin.formatKey;
142    var formatSeed = ctx.plugin.formatSeed;
143
144    // reset key for every request
145    ctx.key = null;
146
147    var b = forge.util.createBuffer();
148    while(b.length() < count) {
149      // if amount of data generated is greater than 1 MiB, trigger reseed
150      if(ctx.generated > 0xfffff) {
151        ctx.key = null;
152      }
153
154      if(ctx.key === null) {
155        _reseedSync();
156      }
157
158      // generate the random bytes
159      var bytes = cipher(ctx.key, ctx.seed);
160      ctx.generated += bytes.length;
161      b.putBytes(bytes);
162
163      // generate bytes for a new key and seed
164      ctx.key = formatKey(cipher(ctx.key, increment(ctx.seed)));
165      ctx.seed = formatSeed(cipher(ctx.key, ctx.seed));
166    }
167
168    return b.getBytes(count);
169  };
170
171  /**
172   * Private function that asynchronously reseeds a generator.
173   *
174   * @param callback(err) called once the operation completes.
175   */
176  function _reseed(callback) {
177    if(ctx.pools[0].messageLength >= 32) {
178      _seed();
179      return callback();
180    }
181    // not enough seed data...
182    var needed = (32 - ctx.pools[0].messageLength) << 5;
183    ctx.seedFile(needed, function(err, bytes) {
184      if(err) {
185        return callback(err);
186      }
187      ctx.collect(bytes);
188      _seed();
189      callback();
190    });
191  }
192
193  /**
194   * Private function that synchronously reseeds a generator.
195   */
196  function _reseedSync() {
197    if(ctx.pools[0].messageLength >= 32) {
198      return _seed();
199    }
200    // not enough seed data...
201    var needed = (32 - ctx.pools[0].messageLength) << 5;
202    ctx.collect(ctx.seedFileSync(needed));
203    _seed();
204  }
205
206  /**
207   * Private function that seeds a generator once enough bytes are available.
208   */
209  function _seed() {
210    // create a plugin-based message digest
211    var md = ctx.plugin.md.create();
212
213    // digest pool 0's entropy and restart it
214    md.update(ctx.pools[0].digest().getBytes());
215    ctx.pools[0].start();
216
217    // digest the entropy of other pools whose index k meet the
218    // condition '2^k mod n == 0' where n is the number of reseeds
219    var k = 1;
220    for(var i = 1; i < 32; ++i) {
221      // prevent signed numbers from being used
222      k = (k === 31) ? 0x80000000 : (k << 2);
223      if(k % ctx.reseeds === 0) {
224        md.update(ctx.pools[i].digest().getBytes());
225        ctx.pools[i].start();
226      }
227    }
228
229    // get digest for key bytes and iterate again for seed bytes
230    var keyBytes = md.digest().getBytes();
231    md.start();
232    md.update(keyBytes);
233    var seedBytes = md.digest().getBytes();
234
235    // update
236    ctx.key = ctx.plugin.formatKey(keyBytes);
237    ctx.seed = ctx.plugin.formatSeed(seedBytes);
238    ctx.reseeds = (ctx.reseeds === 0xffffffff) ? 0 : ctx.reseeds + 1;
239    ctx.generated = 0;
240  }
241
242  /**
243   * The built-in default seedFile. This seedFile is used when entropy
244   * is needed immediately.
245   *
246   * @param needed the number of bytes that are needed.
247   *
248   * @return the random bytes.
249   */
250  function defaultSeedFile(needed) {
251    // use window.crypto.getRandomValues strong source of entropy if available
252    var getRandomValues = null;
253    if(typeof window !== 'undefined') {
254      var _crypto = window.crypto || window.msCrypto;
255      if(_crypto && _crypto.getRandomValues) {
256        getRandomValues = function(arr) {
257          return _crypto.getRandomValues(arr);
258        };
259      }
260    }
261
262    var b = forge.util.createBuffer();
263    if(getRandomValues) {
264      while(b.length() < needed) {
265        // max byte length is 65536 before QuotaExceededError is thrown
266        // http://www.w3.org/TR/WebCryptoAPI/#RandomSource-method-getRandomValues
267        var count = Math.max(1, Math.min(needed - b.length(), 65536) / 4);
268        var entropy = new Uint32Array(Math.floor(count));
269        try {
270          getRandomValues(entropy);
271          for(var i = 0; i < entropy.length; ++i) {
272            b.putInt32(entropy[i]);
273          }
274        } catch(e) {
275          /* only ignore QuotaExceededError */
276          if(!(typeof QuotaExceededError !== 'undefined' &&
277            e instanceof QuotaExceededError)) {
278            throw e;
279          }
280        }
281      }
282    }
283
284    // be sad and add some weak random data
285    if(b.length() < needed) {
286      /* Draws from Park-Miller "minimal standard" 31 bit PRNG,
287      implemented with David G. Carta's optimization: with 32 bit math
288      and without division (Public Domain). */
289      var hi, lo, next;
290      var seed = Math.floor(Math.random() * 0x010000);
291      while(b.length() < needed) {
292        lo = 16807 * (seed & 0xFFFF);
293        hi = 16807 * (seed >> 16);
294        lo += (hi & 0x7FFF) << 16;
295        lo += hi >> 15;
296        lo = (lo & 0x7FFFFFFF) + (lo >> 31);
297        seed = lo & 0xFFFFFFFF;
298
299        // consume lower 3 bytes of seed
300        for(var i = 0; i < 3; ++i) {
301          // throw in more pseudo random
302          next = seed >>> (i << 3);
303          next ^= Math.floor(Math.random() * 0x0100);
304          b.putByte(String.fromCharCode(next & 0xFF));
305        }
306      }
307    }
308
309    return b.getBytes(needed);
310  }
311  // initialize seed file APIs
312  if(_crypto) {
313    // use nodejs async API
314    ctx.seedFile = function(needed, callback) {
315      _crypto.randomBytes(needed, function(err, bytes) {
316        if(err) {
317          return callback(err);
318        }
319        callback(null, bytes.toString());
320      });
321    };
322    // use nodejs sync API
323    ctx.seedFileSync = function(needed) {
324      return _crypto.randomBytes(needed).toString();
325    };
326  } else {
327    ctx.seedFile = function(needed, callback) {
328      try {
329        callback(null, defaultSeedFile(needed));
330      } catch(e) {
331        callback(e);
332      }
333    };
334    ctx.seedFileSync = defaultSeedFile;
335  }
336
337  /**
338   * Adds entropy to a prng ctx's accumulator.
339   *
340   * @param bytes the bytes of entropy as a string.
341   */
342  ctx.collect = function(bytes) {
343    // iterate over pools distributing entropy cyclically
344    var count = bytes.length;
345    for(var i = 0; i < count; ++i) {
346      ctx.pools[ctx.pool].update(bytes.substr(i, 1));
347      ctx.pool = (ctx.pool === 31) ? 0 : ctx.pool + 1;
348    }
349  };
350
351  /**
352   * Collects an integer of n bits.
353   *
354   * @param i the integer entropy.
355   * @param n the number of bits in the integer.
356   */
357  ctx.collectInt = function(i, n) {
358    var bytes = '';
359    for(var x = 0; x < n; x += 8) {
360      bytes += String.fromCharCode((i >> x) & 0xFF);
361    }
362    ctx.collect(bytes);
363  };
364
365  /**
366   * Registers a Web Worker to receive immediate entropy from the main thread.
367   * This method is required until Web Workers can access the native crypto
368   * API. This method should be called twice for each created worker, once in
369   * the main thread, and once in the worker itself.
370   *
371   * @param worker the worker to register.
372   */
373  ctx.registerWorker = function(worker) {
374    // worker receives random bytes
375    if(worker === self) {
376      ctx.seedFile = function(needed, callback) {
377        function listener(e) {
378          var data = e.data;
379          if(data.forge && data.forge.prng) {
380            self.removeEventListener('message', listener);
381            callback(data.forge.prng.err, data.forge.prng.bytes);
382          }
383        }
384        self.addEventListener('message', listener);
385        self.postMessage({forge: {prng: {needed: needed}}});
386      };
387    } else {
388      // main thread sends random bytes upon request
389      var listener = function(e) {
390        var data = e.data;
391        if(data.forge && data.forge.prng) {
392          ctx.seedFile(data.forge.prng.needed, function(err, bytes) {
393            worker.postMessage({forge: {prng: {err: err, bytes: bytes}}});
394          });
395        }
396      };
397      // TODO: do we need to remove the event listener when the worker dies?
398      worker.addEventListener('message', listener);
399    }
400  };
401
402  return ctx;
403};
404
405} // end module implementation
406
407/* ########## Begin module wrapper ########## */
408var name = 'prng';
409if(typeof define !== 'function') {
410  // NodeJS -> AMD
411  if(typeof module === 'object' && module.exports) {
412    var nodeJS = true;
413    define = function(ids, factory) {
414      factory(require, module);
415    };
416  } else {
417    // <script>
418    if(typeof forge === 'undefined') {
419      forge = {};
420    }
421    return initModule(forge);
422  }
423}
424// AMD
425var deps;
426var defineFunc = function(require, module) {
427  module.exports = function(forge) {
428    var mods = deps.map(function(dep) {
429      return require(dep);
430    }).concat(initModule);
431    // handle circular dependencies
432    forge = forge || {};
433    forge.defined = forge.defined || {};
434    if(forge.defined[name]) {
435      return forge[name];
436    }
437    forge.defined[name] = true;
438    for(var i = 0; i < mods.length; ++i) {
439      mods[i](forge);
440    }
441    return forge[name];
442  };
443};
444var tmpDefine = define;
445define = function(ids, factory) {
446  deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
447  if(nodeJS) {
448    delete define;
449    return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
450  }
451  define = tmpDefine;
452  return define.apply(null, Array.prototype.slice.call(arguments, 0));
453};
454define(['require', 'module', './md', './util'], function() {
455  defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
456});
457
458})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.