Blame view

node_modules/browserify-aes/authCipher.js 2.95 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  var aes = require('./aes')
  var Buffer = require('safe-buffer').Buffer
  var Transform = require('cipher-base')
  var inherits = require('inherits')
  var GHASH = require('./ghash')
  var xor = require('buffer-xor')
  var incr32 = require('./incr32')
  
  function xorTest (a, b) {
    var out = 0
    if (a.length !== b.length) out++
  
    var len = Math.min(a.length, b.length)
    for (var i = 0; i < len; ++i) {
      out += (a[i] ^ b[i])
    }
  
    return out
  }
  
  function calcIv (self, iv, ck) {
    if (iv.length === 12) {
      self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])
      return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])
    }
    var ghash = new GHASH(ck)
    var len = iv.length
    var toPad = len % 16
    ghash.update(iv)
    if (toPad) {
      toPad = 16 - toPad
      ghash.update(Buffer.alloc(toPad, 0))
    }
    ghash.update(Buffer.alloc(8, 0))
    var ivBits = len * 8
    var tail = Buffer.alloc(8)
    tail.writeUIntBE(ivBits, 0, 8)
    ghash.update(tail)
    self._finID = ghash.state
    var out = Buffer.from(self._finID)
    incr32(out)
    return out
  }
  function StreamCipher (mode, key, iv, decrypt) {
    Transform.call(this)
  
    var h = Buffer.alloc(4, 0)
  
    this._cipher = new aes.AES(key)
    var ck = this._cipher.encryptBlock(h)
    this._ghash = new GHASH(ck)
    iv = calcIv(this, iv, ck)
  
    this._prev = Buffer.from(iv)
    this._cache = Buffer.allocUnsafe(0)
    this._secCache = Buffer.allocUnsafe(0)
    this._decrypt = decrypt
    this._alen = 0
    this._len = 0
    this._mode = mode
  
    this._authTag = null
    this._called = false
  }
  
  inherits(StreamCipher, Transform)
  
  StreamCipher.prototype._update = function (chunk) {
    if (!this._called && this._alen) {
      var rump = 16 - (this._alen % 16)
      if (rump < 16) {
        rump = Buffer.alloc(rump, 0)
        this._ghash.update(rump)
      }
    }
  
    this._called = true
    var out = this._mode.encrypt(this, chunk)
    if (this._decrypt) {
      this._ghash.update(chunk)
    } else {
      this._ghash.update(out)
    }
    this._len += chunk.length
    return out
  }
  
  StreamCipher.prototype._final = function () {
    if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')
  
    var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))
    if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')
  
    this._authTag = tag
    this._cipher.scrub()
  }
  
  StreamCipher.prototype.getAuthTag = function getAuthTag () {
    if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')
  
    return this._authTag
  }
  
  StreamCipher.prototype.setAuthTag = function setAuthTag (tag) {
    if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')
  
    this._authTag = tag
  }
  
  StreamCipher.prototype.setAAD = function setAAD (buf) {
    if (this._called) throw new Error('Attempting to set AAD in unsupported state')
  
    this._ghash.update(buf)
    this._alen += buf.length
  }
  
  module.exports = StreamCipher