Projekt

Obecné

Profil

Stáhnout (2.95 KB) Statistiky
| Větev: | Revize:
1
var aes = require('./aes')
2
var Buffer = require('safe-buffer').Buffer
3
var Transform = require('cipher-base')
4
var inherits = require('inherits')
5
var GHASH = require('./ghash')
6
var xor = require('buffer-xor')
7
var incr32 = require('./incr32')
8

    
9
function xorTest (a, b) {
10
  var out = 0
11
  if (a.length !== b.length) out++
12

    
13
  var len = Math.min(a.length, b.length)
14
  for (var i = 0; i < len; ++i) {
15
    out += (a[i] ^ b[i])
16
  }
17

    
18
  return out
19
}
20

    
21
function calcIv (self, iv, ck) {
22
  if (iv.length === 12) {
23
    self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])
24
    return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])
25
  }
26
  var ghash = new GHASH(ck)
27
  var len = iv.length
28
  var toPad = len % 16
29
  ghash.update(iv)
30
  if (toPad) {
31
    toPad = 16 - toPad
32
    ghash.update(Buffer.alloc(toPad, 0))
33
  }
34
  ghash.update(Buffer.alloc(8, 0))
35
  var ivBits = len * 8
36
  var tail = Buffer.alloc(8)
37
  tail.writeUIntBE(ivBits, 0, 8)
38
  ghash.update(tail)
39
  self._finID = ghash.state
40
  var out = Buffer.from(self._finID)
41
  incr32(out)
42
  return out
43
}
44
function StreamCipher (mode, key, iv, decrypt) {
45
  Transform.call(this)
46

    
47
  var h = Buffer.alloc(4, 0)
48

    
49
  this._cipher = new aes.AES(key)
50
  var ck = this._cipher.encryptBlock(h)
51
  this._ghash = new GHASH(ck)
52
  iv = calcIv(this, iv, ck)
53

    
54
  this._prev = Buffer.from(iv)
55
  this._cache = Buffer.allocUnsafe(0)
56
  this._secCache = Buffer.allocUnsafe(0)
57
  this._decrypt = decrypt
58
  this._alen = 0
59
  this._len = 0
60
  this._mode = mode
61

    
62
  this._authTag = null
63
  this._called = false
64
}
65

    
66
inherits(StreamCipher, Transform)
67

    
68
StreamCipher.prototype._update = function (chunk) {
69
  if (!this._called && this._alen) {
70
    var rump = 16 - (this._alen % 16)
71
    if (rump < 16) {
72
      rump = Buffer.alloc(rump, 0)
73
      this._ghash.update(rump)
74
    }
75
  }
76

    
77
  this._called = true
78
  var out = this._mode.encrypt(this, chunk)
79
  if (this._decrypt) {
80
    this._ghash.update(chunk)
81
  } else {
82
    this._ghash.update(out)
83
  }
84
  this._len += chunk.length
85
  return out
86
}
87

    
88
StreamCipher.prototype._final = function () {
89
  if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')
90

    
91
  var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))
92
  if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')
93

    
94
  this._authTag = tag
95
  this._cipher.scrub()
96
}
97

    
98
StreamCipher.prototype.getAuthTag = function getAuthTag () {
99
  if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')
100

    
101
  return this._authTag
102
}
103

    
104
StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {
105
  if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')
106

    
107
  this._authTag = tag
108
}
109

    
110
StreamCipher.prototype.setAAD = function setAAD (buf) {
111
  if (this._called) throw new Error('Attempting to set AAD in unsupported state')
112

    
113
  this._ghash.update(buf)
114
  this._alen += buf.length
115
}
116

    
117
module.exports = StreamCipher
(5-5/13)