114 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
var hash = require('hash.js');
 | 
						|
var utils = require('minimalistic-crypto-utils');
 | 
						|
var assert = require('minimalistic-assert');
 | 
						|
 | 
						|
function HmacDRBG(options) {
 | 
						|
  if (!(this instanceof HmacDRBG))
 | 
						|
    return new HmacDRBG(options);
 | 
						|
  this.hash = options.hash;
 | 
						|
  this.predResist = !!options.predResist;
 | 
						|
 | 
						|
  this.outLen = this.hash.outSize;
 | 
						|
  this.minEntropy = options.minEntropy || this.hash.hmacStrength;
 | 
						|
 | 
						|
  this._reseed = null;
 | 
						|
  this.reseedInterval = null;
 | 
						|
  this.K = null;
 | 
						|
  this.V = null;
 | 
						|
 | 
						|
  var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex');
 | 
						|
  var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex');
 | 
						|
  var pers = utils.toArray(options.pers, options.persEnc || 'hex');
 | 
						|
  assert(entropy.length >= (this.minEntropy / 8),
 | 
						|
         'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
 | 
						|
  this._init(entropy, nonce, pers);
 | 
						|
}
 | 
						|
module.exports = HmacDRBG;
 | 
						|
 | 
						|
HmacDRBG.prototype._init = function init(entropy, nonce, pers) {
 | 
						|
  var seed = entropy.concat(nonce).concat(pers);
 | 
						|
 | 
						|
  this.K = new Array(this.outLen / 8);
 | 
						|
  this.V = new Array(this.outLen / 8);
 | 
						|
  for (var i = 0; i < this.V.length; i++) {
 | 
						|
    this.K[i] = 0x00;
 | 
						|
    this.V[i] = 0x01;
 | 
						|
  }
 | 
						|
 | 
						|
  this._update(seed);
 | 
						|
  this._reseed = 1;
 | 
						|
  this.reseedInterval = 0x1000000000000;  // 2^48
 | 
						|
};
 | 
						|
 | 
						|
HmacDRBG.prototype._hmac = function hmac() {
 | 
						|
  return new hash.hmac(this.hash, this.K);
 | 
						|
};
 | 
						|
 | 
						|
HmacDRBG.prototype._update = function update(seed) {
 | 
						|
  var kmac = this._hmac()
 | 
						|
                 .update(this.V)
 | 
						|
                 .update([ 0x00 ]);
 | 
						|
  if (seed)
 | 
						|
    kmac = kmac.update(seed);
 | 
						|
  this.K = kmac.digest();
 | 
						|
  this.V = this._hmac().update(this.V).digest();
 | 
						|
  if (!seed)
 | 
						|
    return;
 | 
						|
 | 
						|
  this.K = this._hmac()
 | 
						|
               .update(this.V)
 | 
						|
               .update([ 0x01 ])
 | 
						|
               .update(seed)
 | 
						|
               .digest();
 | 
						|
  this.V = this._hmac().update(this.V).digest();
 | 
						|
};
 | 
						|
 | 
						|
HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) {
 | 
						|
  // Optional entropy enc
 | 
						|
  if (typeof entropyEnc !== 'string') {
 | 
						|
    addEnc = add;
 | 
						|
    add = entropyEnc;
 | 
						|
    entropyEnc = null;
 | 
						|
  }
 | 
						|
 | 
						|
  entropy = utils.toArray(entropy, entropyEnc);
 | 
						|
  add = utils.toArray(add, addEnc);
 | 
						|
 | 
						|
  assert(entropy.length >= (this.minEntropy / 8),
 | 
						|
         'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
 | 
						|
 | 
						|
  this._update(entropy.concat(add || []));
 | 
						|
  this._reseed = 1;
 | 
						|
};
 | 
						|
 | 
						|
HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) {
 | 
						|
  if (this._reseed > this.reseedInterval)
 | 
						|
    throw new Error('Reseed is required');
 | 
						|
 | 
						|
  // Optional encoding
 | 
						|
  if (typeof enc !== 'string') {
 | 
						|
    addEnc = add;
 | 
						|
    add = enc;
 | 
						|
    enc = null;
 | 
						|
  }
 | 
						|
 | 
						|
  // Optional additional data
 | 
						|
  if (add) {
 | 
						|
    add = utils.toArray(add, addEnc || 'hex');
 | 
						|
    this._update(add);
 | 
						|
  }
 | 
						|
 | 
						|
  var temp = [];
 | 
						|
  while (temp.length < len) {
 | 
						|
    this.V = this._hmac().update(this.V).digest();
 | 
						|
    temp = temp.concat(this.V);
 | 
						|
  }
 | 
						|
 | 
						|
  var res = temp.slice(0, len);
 | 
						|
  this._update(add);
 | 
						|
  this._reseed++;
 | 
						|
  return utils.encode(res, enc);
 | 
						|
};
 |