-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.js
145 lines (111 loc) · 4.07 KB
/
index.js
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
var noise = require('noise-protocol')
var NoiseSymmetricState = require('noise-protocol/symmetric-state')
var NoiseHash = require('noise-protocol/hash')
var assert = require('nanoassert')
var EMPTY = Buffer.alloc(0)
function SimpleHandshake (isInitiator, opts) {
if (!(this instanceof SimpleHandshake)) return new SimpleHandshake(isInitiator, opts)
opts = opts || {}
var pattern = opts.pattern || 'NN'
var prolouge = opts.prolouge || EMPTY
this.handshakeHash = null
this.onstatickey = opts.onstatickey || function (_, cb) { cb() }
this.onephemeralkey = opts.onephemeralkey || function (_, cb) { cb() }
this.onhandshake = opts.onhandshake || function (_, cb) { cb() }
this.state = noise.initialize(
pattern,
isInitiator,
prolouge,
opts.staticKeyPair,
opts.ephemeralKeyPair,
opts.remoteStaticKey,
opts.remoteEphemeralKey
)
// initiators should send first message, so if initiator, waiting = false
// while servers should await any message, so if not initiator, waiting = true
this.waiting = isInitiator === false
this.finished = false
// Will hold the "split" for transport encryption after handshake
this.split = null
// ~64KiB is the max noise message length
this._tx = Buffer.alloc(65535)
this._rx = Buffer.alloc(65535)
}
SimpleHandshake.prototype.recv = function recv (data, cb) {
var self = this
assert(self.finished === false, 'Should not call recv if finished')
assert(data != null, 'must have data')
assert(data.byteLength <= self._rx.byteLength, 'too much data received')
assert(self.waiting === true, 'Wrong state, not ready to receive data')
assert(self.split == null, 'split should be null')
var hasREBefore = self.state.re != null
var hasRSBefore = self.state.rs != null
try {
self.split = noise.readMessage(self.state, data, self._rx)
} catch (ex) {
return self._finish(ex, null, cb)
}
self.waiting = false
var hasREAfter = self.state.re != null
var hasRSAfter = self.state.rs != null
// e and s may come in the same message, so we always have to check static
// after ephemeral. Assumption here (which holds for all official Noise handshakes)
// is that e always comes before s
if (hasREBefore === false && hasREAfter === true) {
return self.onephemeralkey(self.state.re, checkStatic)
}
return checkStatic()
function checkStatic (err) {
if (err) return ondone(err)
if (hasRSBefore === false && hasRSAfter === true) {
return self.onstatickey(self.state.rs, ondone)
}
return ondone()
}
function ondone (err) {
if (err) return self._finish(err, null, cb)
var msg = self._rx.subarray(0, noise.readMessage.bytes)
if (self.split) return self._finish(null, msg, cb)
cb(null, msg)
}
}
SimpleHandshake.prototype.send = function send (data, cb) {
assert(this.finished === false, 'Should not call send if finished')
assert(this.waiting === false, 'Wrong state, not ready to send data')
assert(this.split == null, 'split should be null')
data = data || EMPTY
try {
this.split = noise.writeMessage(this.state, data, this._tx)
} catch (ex) {
return this._finish(ex, null, cb)
}
this.waiting = true
var buf = this._tx.subarray(0, noise.writeMessage.bytes)
if (this.split != null) return this._finish(null, buf, cb)
return cb(null, buf)
}
SimpleHandshake.prototype.destroy = function () {
this._finish(null, null, function () {})
}
SimpleHandshake.prototype._finish = function _finish (err, msg, cb) {
assert(this.finished === false, 'Already finished')
const self = this
self.finished = true
self.waiting = false
if (self.split) {
self.handshakeHash = Buffer.alloc(NoiseHash.HASHLEN)
NoiseSymmetricState.getHandshakeHash(self.state.symmetricState, self.handshakeHash)
}
if (err) return ondone(err)
self.onhandshake(self.state, ondone)
function ondone (err) {
noise.destroy(self.state)
cb(err, msg, self.split)
// Should be sodium_memzero?
self._rx.fill(0)
self._tx.fill(0)
}
}
SimpleHandshake.keygen = noise.keygen
SimpleHandshake.seedKeygen = noise.seedKeygen
module.exports = SimpleHandshake