| '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); | 
| }; |