Projekt

Obecné

Profil

Stáhnout (2.92 KB) Statistiky
| Větev: | Revize:
1
'use strict';
2

    
3
var hash = require('hash.js');
4
var utils = require('minimalistic-crypto-utils');
5
var assert = require('minimalistic-assert');
6

    
7
function HmacDRBG(options) {
8
  if (!(this instanceof HmacDRBG))
9
    return new HmacDRBG(options);
10
  this.hash = options.hash;
11
  this.predResist = !!options.predResist;
12

    
13
  this.outLen = this.hash.outSize;
14
  this.minEntropy = options.minEntropy || this.hash.hmacStrength;
15

    
16
  this._reseed = null;
17
  this.reseedInterval = null;
18
  this.K = null;
19
  this.V = null;
20

    
21
  var entropy = utils.toArray(options.entropy, options.entropyEnc || 'hex');
22
  var nonce = utils.toArray(options.nonce, options.nonceEnc || 'hex');
23
  var pers = utils.toArray(options.pers, options.persEnc || 'hex');
24
  assert(entropy.length >= (this.minEntropy / 8),
25
         'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
26
  this._init(entropy, nonce, pers);
27
}
28
module.exports = HmacDRBG;
29

    
30
HmacDRBG.prototype._init = function init(entropy, nonce, pers) {
31
  var seed = entropy.concat(nonce).concat(pers);
32

    
33
  this.K = new Array(this.outLen / 8);
34
  this.V = new Array(this.outLen / 8);
35
  for (var i = 0; i < this.V.length; i++) {
36
    this.K[i] = 0x00;
37
    this.V[i] = 0x01;
38
  }
39

    
40
  this._update(seed);
41
  this._reseed = 1;
42
  this.reseedInterval = 0x1000000000000;  // 2^48
43
};
44

    
45
HmacDRBG.prototype._hmac = function hmac() {
46
  return new hash.hmac(this.hash, this.K);
47
};
48

    
49
HmacDRBG.prototype._update = function update(seed) {
50
  var kmac = this._hmac()
51
                 .update(this.V)
52
                 .update([ 0x00 ]);
53
  if (seed)
54
    kmac = kmac.update(seed);
55
  this.K = kmac.digest();
56
  this.V = this._hmac().update(this.V).digest();
57
  if (!seed)
58
    return;
59

    
60
  this.K = this._hmac()
61
               .update(this.V)
62
               .update([ 0x01 ])
63
               .update(seed)
64
               .digest();
65
  this.V = this._hmac().update(this.V).digest();
66
};
67

    
68
HmacDRBG.prototype.reseed = function reseed(entropy, entropyEnc, add, addEnc) {
69
  // Optional entropy enc
70
  if (typeof entropyEnc !== 'string') {
71
    addEnc = add;
72
    add = entropyEnc;
73
    entropyEnc = null;
74
  }
75

    
76
  entropy = utils.toArray(entropy, entropyEnc);
77
  add = utils.toArray(add, addEnc);
78

    
79
  assert(entropy.length >= (this.minEntropy / 8),
80
         'Not enough entropy. Minimum is: ' + this.minEntropy + ' bits');
81

    
82
  this._update(entropy.concat(add || []));
83
  this._reseed = 1;
84
};
85

    
86
HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) {
87
  if (this._reseed > this.reseedInterval)
88
    throw new Error('Reseed is required');
89

    
90
  // Optional encoding
91
  if (typeof enc !== 'string') {
92
    addEnc = add;
93
    add = enc;
94
    enc = null;
95
  }
96

    
97
  // Optional additional data
98
  if (add) {
99
    add = utils.toArray(add, addEnc || 'hex');
100
    this._update(add);
101
  }
102

    
103
  var temp = [];
104
  while (temp.length < len) {
105
    this.V = this._hmac().update(this.V).digest();
106
    temp = temp.concat(this.V);
107
  }
108

    
109
  var res = temp.slice(0, len);
110
  this._update(add);
111
  this._reseed++;
112
  return utils.encode(res, enc);
113
};
    (1-1/1)