@electerm/ssh2 0.8.11 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/install.js +20 -0
- package/lib/Channel.js +236 -450
- package/lib/agent.js +1080 -376
- package/lib/client.js +1698 -1258
- package/lib/http-agents.js +72 -51
- package/lib/index.js +43 -0
- package/lib/protocol/Protocol.js +2077 -0
- package/lib/protocol/SFTP.js +3778 -0
- package/lib/protocol/constants.js +342 -0
- package/lib/protocol/crypto/binding.gyp +14 -0
- package/lib/protocol/crypto/poly1305.js +43 -0
- package/lib/protocol/crypto/src/binding.cc +2003 -0
- package/lib/protocol/crypto.js +1602 -0
- package/lib/protocol/handlers.js +16 -0
- package/lib/protocol/handlers.misc.js +1214 -0
- package/lib/protocol/kex.js +1831 -0
- package/lib/protocol/keyParser.js +1481 -0
- package/lib/protocol/node-fs-compat.js +115 -0
- package/lib/protocol/utils.js +356 -0
- package/lib/protocol/zlib.js +255 -0
- package/lib/server.js +1226 -1019
- package/lib/utils.js +336 -0
- package/package.json +42 -9
- package/lib/SFTPWrapper.js +0 -145
- package/lib/buffer-helpers.js +0 -22
- package/lib/keepalivemgr.js +0 -80
|
@@ -0,0 +1,2003 @@
|
|
|
1
|
+
// TODO: switch from obsolete EVP_* APIs in CCP
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include <assert.h>
|
|
5
|
+
|
|
6
|
+
#include <node.h>
|
|
7
|
+
#include <node_buffer.h>
|
|
8
|
+
#include <nan.h>
|
|
9
|
+
|
|
10
|
+
#include <openssl/err.h>
|
|
11
|
+
#include <openssl/evp.h>
|
|
12
|
+
#include <openssl/hmac.h>
|
|
13
|
+
|
|
14
|
+
using namespace node;
|
|
15
|
+
using namespace v8;
|
|
16
|
+
using namespace std;
|
|
17
|
+
|
|
18
|
+
struct MarkPopErrorOnReturn {
|
|
19
|
+
MarkPopErrorOnReturn() { ERR_set_mark(); }
|
|
20
|
+
~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
enum ErrorType {
|
|
24
|
+
kErrNone,
|
|
25
|
+
kErrOpenSSL,
|
|
26
|
+
kErrBadIVLen,
|
|
27
|
+
kErrBadKeyLen,
|
|
28
|
+
kErrAADFailure,
|
|
29
|
+
kErrTagFailure,
|
|
30
|
+
kErrPartialEncrypt,
|
|
31
|
+
kErrBadCipherName,
|
|
32
|
+
kErrBadHMACName,
|
|
33
|
+
kErrBadHMACLen,
|
|
34
|
+
kErrBadInit,
|
|
35
|
+
kErrPartialDecrypt,
|
|
36
|
+
kErrInvalidMAC,
|
|
37
|
+
kErrBadBlockLen
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
#define MAX_MAC_LEN 64
|
|
41
|
+
|
|
42
|
+
#define POLY1305_KEYLEN 32
|
|
43
|
+
#define POLY1305_TAGLEN 16
|
|
44
|
+
class ChaChaPolyCipher : public ObjectWrap {
|
|
45
|
+
public:
|
|
46
|
+
static NAN_MODULE_INIT(Init) {
|
|
47
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
48
|
+
tpl->SetClassName(Nan::New("ChaChaPolyCipher").ToLocalChecked());
|
|
49
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
50
|
+
|
|
51
|
+
SetPrototypeMethod(tpl, "encrypt", Encrypt);
|
|
52
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
53
|
+
|
|
54
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
55
|
+
|
|
56
|
+
Nan::Set(target,
|
|
57
|
+
Nan::New("ChaChaPolyCipher").ToLocalChecked(),
|
|
58
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private:
|
|
62
|
+
explicit ChaChaPolyCipher()
|
|
63
|
+
: ctx_main_(nullptr),
|
|
64
|
+
ctx_pktlen_(nullptr),
|
|
65
|
+
md_ctx_(nullptr),
|
|
66
|
+
polykey_(nullptr) {}
|
|
67
|
+
|
|
68
|
+
~ChaChaPolyCipher() {
|
|
69
|
+
clear();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void clear() {
|
|
73
|
+
if (ctx_pktlen_) {
|
|
74
|
+
EVP_CIPHER_CTX_cleanup(ctx_pktlen_);
|
|
75
|
+
EVP_CIPHER_CTX_free(ctx_pktlen_);
|
|
76
|
+
ctx_pktlen_ = nullptr;
|
|
77
|
+
}
|
|
78
|
+
if (ctx_main_) {
|
|
79
|
+
EVP_CIPHER_CTX_cleanup(ctx_main_);
|
|
80
|
+
EVP_CIPHER_CTX_free(ctx_main_);
|
|
81
|
+
ctx_main_ = nullptr;
|
|
82
|
+
}
|
|
83
|
+
if (polykey_) {
|
|
84
|
+
EVP_PKEY_free(polykey_);
|
|
85
|
+
polykey_ = nullptr;
|
|
86
|
+
}
|
|
87
|
+
if (md_ctx_) {
|
|
88
|
+
EVP_MD_CTX_free(md_ctx_);
|
|
89
|
+
md_ctx_ = nullptr;
|
|
90
|
+
}
|
|
91
|
+
// `polykey_ctx_` is not explicitly freed as it is freed implicitly when
|
|
92
|
+
// `md_ctx_` is freed
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
ErrorType init(unsigned char* keys, size_t keys_len) {
|
|
96
|
+
ErrorType r = kErrNone;
|
|
97
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname("chacha20");
|
|
98
|
+
|
|
99
|
+
if (keys_len != 64) {
|
|
100
|
+
r = kErrBadKeyLen;
|
|
101
|
+
goto out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (cipher == nullptr) {
|
|
105
|
+
r = kErrOpenSSL;
|
|
106
|
+
goto out;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
110
|
+
|| (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
111
|
+
|| (md_ctx_ = EVP_MD_CTX_new()) == nullptr
|
|
112
|
+
|| EVP_EncryptInit_ex(ctx_pktlen_,
|
|
113
|
+
cipher,
|
|
114
|
+
nullptr,
|
|
115
|
+
keys + 32,
|
|
116
|
+
nullptr) != 1
|
|
117
|
+
|| EVP_EncryptInit_ex(ctx_main_,
|
|
118
|
+
cipher,
|
|
119
|
+
nullptr,
|
|
120
|
+
keys,
|
|
121
|
+
nullptr) != 1) {
|
|
122
|
+
r = kErrOpenSSL;
|
|
123
|
+
goto out;
|
|
124
|
+
}
|
|
125
|
+
if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
|
|
126
|
+
r = kErrBadIVLen;
|
|
127
|
+
goto out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
out:
|
|
131
|
+
return r;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
ErrorType encrypt(unsigned char* packet,
|
|
135
|
+
uint32_t packet_len,
|
|
136
|
+
uint32_t seqno) {
|
|
137
|
+
ErrorType r = kErrNone;
|
|
138
|
+
size_t sig_len = 16;
|
|
139
|
+
int outlen = 0;
|
|
140
|
+
|
|
141
|
+
// `packet` layout:
|
|
142
|
+
// <packet length> <padding length> <payload> <padding> <poly1305 mac>
|
|
143
|
+
uint32_t data_len = packet_len - POLY1305_TAGLEN;
|
|
144
|
+
|
|
145
|
+
unsigned char polykey[POLY1305_KEYLEN] = {0};
|
|
146
|
+
|
|
147
|
+
uint8_t seqbuf[16] = {0};
|
|
148
|
+
((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff;
|
|
149
|
+
((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff;
|
|
150
|
+
((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff;
|
|
151
|
+
((uint8_t*)(seqbuf))[15] = seqno & 0xff;
|
|
152
|
+
|
|
153
|
+
// Generate Poly1305 key
|
|
154
|
+
if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
|
|
155
|
+
r = kErrOpenSSL;
|
|
156
|
+
goto out;
|
|
157
|
+
}
|
|
158
|
+
if (EVP_EncryptUpdate(ctx_main_,
|
|
159
|
+
polykey,
|
|
160
|
+
&outlen,
|
|
161
|
+
polykey,
|
|
162
|
+
sizeof(polykey)) != 1) {
|
|
163
|
+
r = kErrOpenSSL;
|
|
164
|
+
goto out;
|
|
165
|
+
}
|
|
166
|
+
if (static_cast<size_t>(outlen) != sizeof(polykey)) {
|
|
167
|
+
r = kErrPartialEncrypt;
|
|
168
|
+
goto out;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Encrypt packet length
|
|
172
|
+
if (EVP_EncryptInit_ex(ctx_pktlen_,
|
|
173
|
+
nullptr,
|
|
174
|
+
nullptr,
|
|
175
|
+
nullptr,
|
|
176
|
+
seqbuf) != 1) {
|
|
177
|
+
r = kErrOpenSSL;
|
|
178
|
+
goto out;
|
|
179
|
+
}
|
|
180
|
+
if (EVP_EncryptUpdate(ctx_pktlen_, packet, &outlen, packet, 4) != 1) {
|
|
181
|
+
r = kErrOpenSSL;
|
|
182
|
+
goto out;
|
|
183
|
+
}
|
|
184
|
+
if (static_cast<size_t>(outlen) != 4) {
|
|
185
|
+
r = kErrPartialEncrypt;
|
|
186
|
+
goto out;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Encrypt rest of packet
|
|
190
|
+
seqbuf[0] = 1;
|
|
191
|
+
if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
|
|
192
|
+
r = kErrOpenSSL;
|
|
193
|
+
goto out;
|
|
194
|
+
}
|
|
195
|
+
if (EVP_EncryptUpdate(ctx_main_,
|
|
196
|
+
packet + 4,
|
|
197
|
+
&outlen,
|
|
198
|
+
packet + 4,
|
|
199
|
+
data_len - 4) != 1) {
|
|
200
|
+
r = kErrOpenSSL;
|
|
201
|
+
goto out;
|
|
202
|
+
}
|
|
203
|
+
if (static_cast<size_t>(outlen) != data_len - 4) {
|
|
204
|
+
r = kErrPartialEncrypt;
|
|
205
|
+
goto out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Poly1305 over ciphertext
|
|
209
|
+
if (polykey_) {
|
|
210
|
+
if (EVP_PKEY_CTX_ctrl(polykey_ctx_,
|
|
211
|
+
-1,
|
|
212
|
+
EVP_PKEY_OP_SIGNCTX,
|
|
213
|
+
EVP_PKEY_CTRL_SET_MAC_KEY,
|
|
214
|
+
sizeof(polykey),
|
|
215
|
+
(void*)polykey) <= 0) {
|
|
216
|
+
r = kErrOpenSSL;
|
|
217
|
+
goto out;
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
polykey_ = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305,
|
|
221
|
+
nullptr,
|
|
222
|
+
polykey,
|
|
223
|
+
sizeof(polykey));
|
|
224
|
+
if (polykey_ == nullptr) {
|
|
225
|
+
r = kErrOpenSSL;
|
|
226
|
+
goto out;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!EVP_DigestSignInit(md_ctx_,
|
|
230
|
+
&polykey_ctx_,
|
|
231
|
+
nullptr,
|
|
232
|
+
nullptr,
|
|
233
|
+
polykey_)) {
|
|
234
|
+
r = kErrOpenSSL;
|
|
235
|
+
goto out;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Generate and write Poly1305 tag
|
|
240
|
+
if (EVP_DigestSign(md_ctx_,
|
|
241
|
+
packet + data_len,
|
|
242
|
+
&sig_len,
|
|
243
|
+
packet,
|
|
244
|
+
data_len) != 1) {
|
|
245
|
+
r = kErrOpenSSL;
|
|
246
|
+
goto out;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
out:
|
|
250
|
+
return r;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static NAN_METHOD(New) {
|
|
254
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
255
|
+
|
|
256
|
+
if (!Buffer::HasInstance(info[0]))
|
|
257
|
+
return Nan::ThrowTypeError("Missing/Invalid keys");
|
|
258
|
+
|
|
259
|
+
ChaChaPolyCipher* obj = new ChaChaPolyCipher();
|
|
260
|
+
ErrorType r = obj->init(
|
|
261
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
262
|
+
Buffer::Length(info[0])
|
|
263
|
+
);
|
|
264
|
+
if (r != kErrNone) {
|
|
265
|
+
if (r == kErrOpenSSL) {
|
|
266
|
+
char msg_buf[128] = {0};
|
|
267
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
268
|
+
ERR_clear_error();
|
|
269
|
+
obj->clear();
|
|
270
|
+
delete obj;
|
|
271
|
+
return Nan::ThrowError(msg_buf);
|
|
272
|
+
}
|
|
273
|
+
obj->clear();
|
|
274
|
+
delete obj;
|
|
275
|
+
switch (r) {
|
|
276
|
+
case kErrBadKeyLen:
|
|
277
|
+
return Nan::ThrowError("Invalid keys length");
|
|
278
|
+
case kErrBadIVLen:
|
|
279
|
+
return Nan::ThrowError("Invalid IV length");
|
|
280
|
+
default:
|
|
281
|
+
return Nan::ThrowError("Unknown init failure");
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
obj->Wrap(info.This());
|
|
286
|
+
info.GetReturnValue().Set(info.This());
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
static NAN_METHOD(Encrypt) {
|
|
290
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
291
|
+
|
|
292
|
+
ChaChaPolyCipher* obj = ObjectWrap::Unwrap<ChaChaPolyCipher>(info.Holder());
|
|
293
|
+
|
|
294
|
+
if (!Buffer::HasInstance(info[0]))
|
|
295
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
296
|
+
|
|
297
|
+
if (!info[1]->IsUint32())
|
|
298
|
+
return Nan::ThrowTypeError("Missing/Invalid sequence number");
|
|
299
|
+
|
|
300
|
+
ErrorType r = obj->encrypt(
|
|
301
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
302
|
+
Buffer::Length(info[0]),
|
|
303
|
+
Nan::To<uint32_t>(info[1]).FromJust()
|
|
304
|
+
);
|
|
305
|
+
switch (r) {
|
|
306
|
+
case kErrNone:
|
|
307
|
+
return;
|
|
308
|
+
case kErrOpenSSL: {
|
|
309
|
+
char msg_buf[128] = {0};
|
|
310
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
311
|
+
ERR_clear_error();
|
|
312
|
+
return Nan::ThrowError(msg_buf);
|
|
313
|
+
}
|
|
314
|
+
default:
|
|
315
|
+
return Nan::ThrowError("Unknown encrypt failure");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
static NAN_METHOD(Free) {
|
|
320
|
+
ChaChaPolyCipher* obj = ObjectWrap::Unwrap<ChaChaPolyCipher>(info.Holder());
|
|
321
|
+
obj->clear();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
325
|
+
static Nan::Persistent<Function> my_constructor;
|
|
326
|
+
return my_constructor;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
EVP_CIPHER_CTX* ctx_main_;
|
|
330
|
+
EVP_CIPHER_CTX* ctx_pktlen_;
|
|
331
|
+
EVP_MD_CTX* md_ctx_;
|
|
332
|
+
EVP_PKEY* polykey_;
|
|
333
|
+
EVP_PKEY_CTX* polykey_ctx_;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
class AESGCMCipher : public ObjectWrap {
|
|
337
|
+
public:
|
|
338
|
+
static NAN_MODULE_INIT(Init) {
|
|
339
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
340
|
+
tpl->SetClassName(Nan::New("AESGCMCipher").ToLocalChecked());
|
|
341
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
342
|
+
|
|
343
|
+
SetPrototypeMethod(tpl, "encrypt", Encrypt);
|
|
344
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
345
|
+
|
|
346
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
347
|
+
|
|
348
|
+
Nan::Set(target,
|
|
349
|
+
Nan::New("AESGCMCipher").ToLocalChecked(),
|
|
350
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private:
|
|
354
|
+
explicit AESGCMCipher() : ctx_(nullptr) {}
|
|
355
|
+
|
|
356
|
+
~AESGCMCipher() {
|
|
357
|
+
clear();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
void clear() {
|
|
361
|
+
if (ctx_) {
|
|
362
|
+
EVP_CIPHER_CTX_cleanup(ctx_);
|
|
363
|
+
EVP_CIPHER_CTX_free(ctx_);
|
|
364
|
+
ctx_ = nullptr;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
ErrorType init(const char* name,
|
|
369
|
+
unsigned char* key,
|
|
370
|
+
size_t key_len,
|
|
371
|
+
unsigned char* iv,
|
|
372
|
+
size_t iv_len) {
|
|
373
|
+
ErrorType r = kErrNone;
|
|
374
|
+
|
|
375
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
|
|
376
|
+
if (cipher == nullptr) {
|
|
377
|
+
r = kErrOpenSSL;
|
|
378
|
+
goto out;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (cipher != EVP_aes_128_gcm() && cipher != EVP_aes_256_gcm()) {
|
|
382
|
+
r = kErrBadCipherName;
|
|
383
|
+
goto out;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
387
|
+
|| EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
|
|
388
|
+
r = kErrOpenSSL;
|
|
389
|
+
goto out;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr)) {
|
|
393
|
+
r = kErrOpenSSL;
|
|
394
|
+
goto out;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
//~ if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
|
|
398
|
+
//~ r = kErrBadIVLen;
|
|
399
|
+
//~ goto out;
|
|
400
|
+
//~ }
|
|
401
|
+
|
|
402
|
+
if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
|
|
403
|
+
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
|
404
|
+
r = kErrBadKeyLen;
|
|
405
|
+
goto out;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Set key and IV
|
|
410
|
+
if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
|
|
411
|
+
r = kErrOpenSSL;
|
|
412
|
+
goto out;
|
|
413
|
+
}
|
|
414
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) {
|
|
415
|
+
r = kErrOpenSSL;
|
|
416
|
+
goto out;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Disable padding
|
|
420
|
+
EVP_CIPHER_CTX_set_padding(ctx_, 0);
|
|
421
|
+
|
|
422
|
+
out:
|
|
423
|
+
return r;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
ErrorType encrypt(unsigned char* packet, uint32_t packet_len) {
|
|
427
|
+
ErrorType r = kErrNone;
|
|
428
|
+
|
|
429
|
+
// `packet` layout:
|
|
430
|
+
// <packet length> <padding length> <payload> <padding> <mac>
|
|
431
|
+
uint32_t data_len = packet_len - 16;
|
|
432
|
+
|
|
433
|
+
int outlen = 0;
|
|
434
|
+
|
|
435
|
+
// Increment IV
|
|
436
|
+
unsigned char lastiv[1];
|
|
437
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_IV_GEN, 1, lastiv)) {
|
|
438
|
+
r = kErrOpenSSL;
|
|
439
|
+
goto out;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Set AAD (the packet length)
|
|
443
|
+
if (!EVP_EncryptUpdate(ctx_, nullptr, &outlen, packet, 4)) {
|
|
444
|
+
r = kErrOpenSSL;
|
|
445
|
+
goto out;
|
|
446
|
+
}
|
|
447
|
+
if (outlen != 4) {
|
|
448
|
+
r = kErrAADFailure;
|
|
449
|
+
goto out;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Encrypt everything but the packet length
|
|
453
|
+
if (EVP_EncryptUpdate(ctx_,
|
|
454
|
+
packet + 4,
|
|
455
|
+
&outlen,
|
|
456
|
+
packet + 4,
|
|
457
|
+
data_len - 4) != 1) {
|
|
458
|
+
r = kErrOpenSSL;
|
|
459
|
+
goto out;
|
|
460
|
+
}
|
|
461
|
+
if (static_cast<size_t>(outlen) != data_len - 4) {
|
|
462
|
+
r = kErrPartialEncrypt;
|
|
463
|
+
goto out;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Generate authentication tag
|
|
467
|
+
if (!EVP_EncryptFinal_ex(ctx_, nullptr, &outlen)) {
|
|
468
|
+
r = kErrOpenSSL;
|
|
469
|
+
goto out;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Write authentication tag
|
|
473
|
+
if (EVP_CIPHER_CTX_ctrl(ctx_,
|
|
474
|
+
EVP_CTRL_AEAD_GET_TAG,
|
|
475
|
+
16,
|
|
476
|
+
packet + data_len) != 1) {
|
|
477
|
+
r = kErrOpenSSL;
|
|
478
|
+
goto out;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
out:
|
|
482
|
+
return r;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
static NAN_METHOD(New) {
|
|
486
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
487
|
+
|
|
488
|
+
if (!info[0]->IsString())
|
|
489
|
+
return Nan::ThrowTypeError("Missing/Invalid OpenSSL cipher name");
|
|
490
|
+
|
|
491
|
+
if (!Buffer::HasInstance(info[1]))
|
|
492
|
+
return Nan::ThrowTypeError("Missing/Invalid key");
|
|
493
|
+
|
|
494
|
+
if (!Buffer::HasInstance(info[2]))
|
|
495
|
+
return Nan::ThrowTypeError("Missing/Invalid iv");
|
|
496
|
+
|
|
497
|
+
const Nan::Utf8String cipher_name(info[0]);
|
|
498
|
+
|
|
499
|
+
AESGCMCipher* obj = new AESGCMCipher();
|
|
500
|
+
ErrorType r = obj->init(
|
|
501
|
+
*cipher_name,
|
|
502
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[1])),
|
|
503
|
+
Buffer::Length(info[1]),
|
|
504
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2])),
|
|
505
|
+
Buffer::Length(info[2])
|
|
506
|
+
);
|
|
507
|
+
if (r != kErrNone) {
|
|
508
|
+
if (r == kErrOpenSSL) {
|
|
509
|
+
char msg_buf[128] = {0};
|
|
510
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
511
|
+
ERR_clear_error();
|
|
512
|
+
obj->clear();
|
|
513
|
+
delete obj;
|
|
514
|
+
return Nan::ThrowError(msg_buf);
|
|
515
|
+
}
|
|
516
|
+
obj->clear();
|
|
517
|
+
delete obj;
|
|
518
|
+
switch (r) {
|
|
519
|
+
case kErrBadKeyLen:
|
|
520
|
+
return Nan::ThrowError("Invalid keys length");
|
|
521
|
+
case kErrBadIVLen:
|
|
522
|
+
return Nan::ThrowError("Invalid IV length");
|
|
523
|
+
case kErrBadCipherName:
|
|
524
|
+
return Nan::ThrowError("Invalid AES GCM cipher name");
|
|
525
|
+
default:
|
|
526
|
+
return Nan::ThrowError("Unknown init failure");
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
obj->Wrap(info.This());
|
|
531
|
+
info.GetReturnValue().Set(info.This());
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static NAN_METHOD(Encrypt) {
|
|
535
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
536
|
+
|
|
537
|
+
AESGCMCipher* obj = ObjectWrap::Unwrap<AESGCMCipher>(info.Holder());
|
|
538
|
+
|
|
539
|
+
if (!Buffer::HasInstance(info[0]))
|
|
540
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
541
|
+
|
|
542
|
+
ErrorType r = obj->encrypt(
|
|
543
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
544
|
+
Buffer::Length(info[0])
|
|
545
|
+
);
|
|
546
|
+
switch (r) {
|
|
547
|
+
case kErrNone:
|
|
548
|
+
return;
|
|
549
|
+
case kErrAADFailure:
|
|
550
|
+
return Nan::ThrowError("Error setting AAD");
|
|
551
|
+
case kErrPartialEncrypt:
|
|
552
|
+
return Nan::ThrowError("Failed to completely encrypt packet");
|
|
553
|
+
case kErrTagFailure:
|
|
554
|
+
return Nan::ThrowError("Error generating authentication tag");
|
|
555
|
+
case kErrOpenSSL: {
|
|
556
|
+
char msg_buf[128] = {0};
|
|
557
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
558
|
+
ERR_clear_error();
|
|
559
|
+
return Nan::ThrowError(msg_buf);
|
|
560
|
+
}
|
|
561
|
+
default:
|
|
562
|
+
return Nan::ThrowError("Unknown encrypt failure");
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static NAN_METHOD(Free) {
|
|
567
|
+
AESGCMCipher* obj = ObjectWrap::Unwrap<AESGCMCipher>(info.Holder());
|
|
568
|
+
obj->clear();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
572
|
+
static Nan::Persistent<Function> my_constructor;
|
|
573
|
+
return my_constructor;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
EVP_CIPHER_CTX* ctx_;
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
class GenericCipher : public ObjectWrap {
|
|
580
|
+
public:
|
|
581
|
+
static NAN_MODULE_INIT(Init) {
|
|
582
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
583
|
+
tpl->SetClassName(Nan::New("GenericCipher").ToLocalChecked());
|
|
584
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
585
|
+
|
|
586
|
+
SetPrototypeMethod(tpl, "encrypt", Encrypt);
|
|
587
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
588
|
+
|
|
589
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
590
|
+
|
|
591
|
+
Nan::Set(target,
|
|
592
|
+
Nan::New("GenericCipher").ToLocalChecked(),
|
|
593
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
private:
|
|
597
|
+
explicit GenericCipher()
|
|
598
|
+
: ctx_(nullptr),
|
|
599
|
+
ctx_hmac_(nullptr),
|
|
600
|
+
hmac_len_(0),
|
|
601
|
+
is_etm_(0) {}
|
|
602
|
+
|
|
603
|
+
~GenericCipher() {
|
|
604
|
+
clear();
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
void clear() {
|
|
608
|
+
if (ctx_) {
|
|
609
|
+
EVP_CIPHER_CTX_cleanup(ctx_);
|
|
610
|
+
EVP_CIPHER_CTX_free(ctx_);
|
|
611
|
+
ctx_ = nullptr;
|
|
612
|
+
}
|
|
613
|
+
if (ctx_hmac_) {
|
|
614
|
+
HMAC_CTX_free(ctx_hmac_);
|
|
615
|
+
ctx_hmac_ = nullptr;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
ErrorType init(const char* name,
|
|
620
|
+
unsigned char* key,
|
|
621
|
+
size_t key_len,
|
|
622
|
+
unsigned char* iv,
|
|
623
|
+
size_t iv_len,
|
|
624
|
+
const char* hmac_name,
|
|
625
|
+
unsigned char* hmac_key,
|
|
626
|
+
size_t hmac_key_len,
|
|
627
|
+
int is_etm) {
|
|
628
|
+
ErrorType r = kErrNone;
|
|
629
|
+
|
|
630
|
+
const EVP_MD* md;
|
|
631
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
|
|
632
|
+
if (cipher == nullptr) {
|
|
633
|
+
r = kErrOpenSSL;
|
|
634
|
+
goto out;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
638
|
+
|| EVP_EncryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
|
|
639
|
+
r = kErrOpenSSL;
|
|
640
|
+
goto out;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
|
|
644
|
+
r = kErrBadIVLen;
|
|
645
|
+
goto out;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
|
|
649
|
+
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
|
650
|
+
r = kErrBadKeyLen;
|
|
651
|
+
goto out;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Set key and IV
|
|
656
|
+
if (EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
|
|
657
|
+
r = kErrOpenSSL;
|
|
658
|
+
goto out;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Disable padding
|
|
662
|
+
EVP_CIPHER_CTX_set_padding(ctx_, 0);
|
|
663
|
+
|
|
664
|
+
if (cipher == EVP_rc4()) {
|
|
665
|
+
/* The "arcfour128" algorithm is the RC4 cipher, as described in
|
|
666
|
+
[SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
|
|
667
|
+
generated by the cipher MUST be discarded, and the first byte of the
|
|
668
|
+
first encrypted packet MUST be encrypted using the 1537th byte of
|
|
669
|
+
keystream.
|
|
670
|
+
|
|
671
|
+
-- http://tools.ietf.org/html/rfc4345#section-4 */
|
|
672
|
+
unsigned char zeros[1536] = {0};
|
|
673
|
+
int outlen = sizeof(zeros);
|
|
674
|
+
if (EVP_EncryptUpdate(ctx_,
|
|
675
|
+
zeros,
|
|
676
|
+
&outlen,
|
|
677
|
+
zeros,
|
|
678
|
+
sizeof(zeros)) != 1) {
|
|
679
|
+
r = kErrOpenSSL;
|
|
680
|
+
goto out;
|
|
681
|
+
}
|
|
682
|
+
if (static_cast<size_t>(outlen) != sizeof(zeros)) {
|
|
683
|
+
r = kErrBadInit;
|
|
684
|
+
goto out;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
md = EVP_get_digestbyname(hmac_name);
|
|
689
|
+
if (md == nullptr) {
|
|
690
|
+
r = kErrBadHMACName;
|
|
691
|
+
goto out;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr
|
|
695
|
+
|| HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) {
|
|
696
|
+
r = kErrOpenSSL;
|
|
697
|
+
goto out;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
hmac_len_ = HMAC_size(ctx_hmac_);
|
|
701
|
+
is_etm_ = is_etm;
|
|
702
|
+
|
|
703
|
+
out:
|
|
704
|
+
return r;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
ErrorType encrypt(unsigned char* packet,
|
|
708
|
+
uint32_t packet_len,
|
|
709
|
+
uint32_t seqno) {
|
|
710
|
+
ErrorType r = kErrNone;
|
|
711
|
+
|
|
712
|
+
// `packet` layout:
|
|
713
|
+
// <packet length> <padding length> <payload> <padding> <mac>
|
|
714
|
+
uint32_t data_len = packet_len - hmac_len_;
|
|
715
|
+
|
|
716
|
+
int outlen;
|
|
717
|
+
|
|
718
|
+
uint8_t seqbuf[4] = {0};
|
|
719
|
+
((uint8_t*)(seqbuf))[0] = (seqno >> 24) & 0xff;
|
|
720
|
+
((uint8_t*)(seqbuf))[1] = (seqno >> 16) & 0xff;
|
|
721
|
+
((uint8_t*)(seqbuf))[2] = (seqno >> 8) & 0xff;
|
|
722
|
+
((uint8_t*)(seqbuf))[3] = seqno & 0xff;
|
|
723
|
+
|
|
724
|
+
if (is_etm_) {
|
|
725
|
+
// Encrypt everything but packet length
|
|
726
|
+
if (EVP_EncryptUpdate(ctx_,
|
|
727
|
+
packet + 4,
|
|
728
|
+
&outlen,
|
|
729
|
+
packet + 4,
|
|
730
|
+
data_len - 4) != 1) {
|
|
731
|
+
r = kErrOpenSSL;
|
|
732
|
+
goto out;
|
|
733
|
+
}
|
|
734
|
+
if (static_cast<size_t>(outlen) != data_len - 4) {
|
|
735
|
+
r = kErrPartialEncrypt;
|
|
736
|
+
goto out;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// HMAC over unencrypted packet length and ciphertext
|
|
740
|
+
{
|
|
741
|
+
unsigned int outlen = hmac_len_;
|
|
742
|
+
if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
|
|
743
|
+
|| HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
|
|
744
|
+
|| HMAC_Update(ctx_hmac_, packet, data_len) != 1
|
|
745
|
+
|| HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) {
|
|
746
|
+
r = kErrOpenSSL;
|
|
747
|
+
goto out;
|
|
748
|
+
}
|
|
749
|
+
if (outlen != hmac_len_) {
|
|
750
|
+
r = kErrBadHMACLen;
|
|
751
|
+
goto out;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
} else {
|
|
755
|
+
// HMAC over plaintext
|
|
756
|
+
{
|
|
757
|
+
unsigned int outlen = hmac_len_;
|
|
758
|
+
if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
|
|
759
|
+
|| HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
|
|
760
|
+
|| HMAC_Update(ctx_hmac_, packet, data_len) != 1
|
|
761
|
+
|| HMAC_Final(ctx_hmac_, packet + data_len, &outlen) != 1) {
|
|
762
|
+
r = kErrOpenSSL;
|
|
763
|
+
goto out;
|
|
764
|
+
}
|
|
765
|
+
if (outlen != hmac_len_) {
|
|
766
|
+
r = kErrBadHMACLen;
|
|
767
|
+
goto out;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Encrypt packet
|
|
772
|
+
if (EVP_EncryptUpdate(ctx_,
|
|
773
|
+
packet,
|
|
774
|
+
&outlen,
|
|
775
|
+
packet,
|
|
776
|
+
data_len) != 1) {
|
|
777
|
+
r = kErrOpenSSL;
|
|
778
|
+
goto out;
|
|
779
|
+
}
|
|
780
|
+
if (static_cast<size_t>(outlen) != data_len) {
|
|
781
|
+
|
|
782
|
+
r = kErrPartialEncrypt;
|
|
783
|
+
goto out;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
out:
|
|
788
|
+
return r;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
static NAN_METHOD(New) {
|
|
792
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
793
|
+
|
|
794
|
+
if (!info[0]->IsString())
|
|
795
|
+
return Nan::ThrowTypeError("Missing/Invalid cipher name");
|
|
796
|
+
|
|
797
|
+
if (!Buffer::HasInstance(info[1]))
|
|
798
|
+
return Nan::ThrowTypeError("Missing/Invalid cipher key");
|
|
799
|
+
|
|
800
|
+
if (!Buffer::HasInstance(info[2]))
|
|
801
|
+
return Nan::ThrowTypeError("Missing/Invalid cipher IV");
|
|
802
|
+
|
|
803
|
+
if (!info[3]->IsString())
|
|
804
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC name");
|
|
805
|
+
|
|
806
|
+
if (!Buffer::HasInstance(info[4]))
|
|
807
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC key");
|
|
808
|
+
|
|
809
|
+
if (!info[5]->IsBoolean())
|
|
810
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag");
|
|
811
|
+
|
|
812
|
+
const Nan::Utf8String cipher_name(info[0]);
|
|
813
|
+
const Nan::Utf8String mac_name(info[3]);
|
|
814
|
+
int is_etm = (Nan::To<bool>(info[5]).FromJust() ? 1 : 0);
|
|
815
|
+
|
|
816
|
+
GenericCipher* obj = new GenericCipher();
|
|
817
|
+
ErrorType r = obj->init(
|
|
818
|
+
*cipher_name,
|
|
819
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[1])),
|
|
820
|
+
Buffer::Length(info[1]),
|
|
821
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2])),
|
|
822
|
+
Buffer::Length(info[2]),
|
|
823
|
+
*mac_name,
|
|
824
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[4])),
|
|
825
|
+
Buffer::Length(info[4]),
|
|
826
|
+
is_etm
|
|
827
|
+
);
|
|
828
|
+
if (r != kErrNone) {
|
|
829
|
+
if (r == kErrOpenSSL) {
|
|
830
|
+
char msg_buf[128] = {0};
|
|
831
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
832
|
+
ERR_clear_error();
|
|
833
|
+
obj->clear();
|
|
834
|
+
delete obj;
|
|
835
|
+
return Nan::ThrowError(msg_buf);
|
|
836
|
+
}
|
|
837
|
+
obj->clear();
|
|
838
|
+
delete obj;
|
|
839
|
+
switch (r) {
|
|
840
|
+
case kErrBadKeyLen:
|
|
841
|
+
return Nan::ThrowError("Invalid keys length");
|
|
842
|
+
case kErrBadIVLen:
|
|
843
|
+
return Nan::ThrowError("Invalid IV length");
|
|
844
|
+
case kErrBadCipherName:
|
|
845
|
+
return Nan::ThrowError("Invalid cipher name");
|
|
846
|
+
case kErrBadHMACName:
|
|
847
|
+
return Nan::ThrowError("Invalid MAC name");
|
|
848
|
+
case kErrBadInit:
|
|
849
|
+
return Nan::ThrowError("Failed to properly initialize cipher");
|
|
850
|
+
default:
|
|
851
|
+
return Nan::ThrowError("Unknown init failure");
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
obj->Wrap(info.This());
|
|
856
|
+
info.GetReturnValue().Set(info.This());
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
static NAN_METHOD(Encrypt) {
|
|
860
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
861
|
+
|
|
862
|
+
GenericCipher* obj = ObjectWrap::Unwrap<GenericCipher>(info.Holder());
|
|
863
|
+
|
|
864
|
+
if (!Buffer::HasInstance(info[0]))
|
|
865
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
866
|
+
|
|
867
|
+
if (!info[1]->IsUint32())
|
|
868
|
+
return Nan::ThrowTypeError("Missing/Invalid sequence number");
|
|
869
|
+
|
|
870
|
+
ErrorType r = obj->encrypt(
|
|
871
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
872
|
+
Buffer::Length(info[0]),
|
|
873
|
+
Nan::To<uint32_t>(info[1]).FromJust()
|
|
874
|
+
);
|
|
875
|
+
switch (r) {
|
|
876
|
+
case kErrNone:
|
|
877
|
+
return;
|
|
878
|
+
case kErrPartialEncrypt:
|
|
879
|
+
return Nan::ThrowError("Failed to completely encrypt packet");
|
|
880
|
+
case kErrBadHMACLen:
|
|
881
|
+
return Nan::ThrowError("Unexpected HMAC length");
|
|
882
|
+
case kErrOpenSSL: {
|
|
883
|
+
char msg_buf[128] = {0};
|
|
884
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
885
|
+
ERR_clear_error();
|
|
886
|
+
return Nan::ThrowError(msg_buf);
|
|
887
|
+
}
|
|
888
|
+
default:
|
|
889
|
+
return Nan::ThrowError("Unknown encrypt failure");
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
static NAN_METHOD(Free) {
|
|
894
|
+
GenericCipher* obj = ObjectWrap::Unwrap<GenericCipher>(info.Holder());
|
|
895
|
+
obj->clear();
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
899
|
+
static Nan::Persistent<Function> my_constructor;
|
|
900
|
+
return my_constructor;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
EVP_CIPHER_CTX* ctx_;
|
|
904
|
+
HMAC_CTX* ctx_hmac_;
|
|
905
|
+
unsigned int hmac_len_;
|
|
906
|
+
int is_etm_;
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
// =============================================================================
|
|
910
|
+
|
|
911
|
+
class ChaChaPolyDecipher : public ObjectWrap {
|
|
912
|
+
public:
|
|
913
|
+
static NAN_MODULE_INIT(Init) {
|
|
914
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
915
|
+
tpl->SetClassName(Nan::New("ChaChaPolyDecipher").ToLocalChecked());
|
|
916
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
917
|
+
|
|
918
|
+
SetPrototypeMethod(tpl, "decrypt", Decrypt);
|
|
919
|
+
SetPrototypeMethod(tpl, "decryptLen", DecryptLen);
|
|
920
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
921
|
+
|
|
922
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
923
|
+
|
|
924
|
+
Nan::Set(target,
|
|
925
|
+
Nan::New("ChaChaPolyDecipher").ToLocalChecked(),
|
|
926
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
private:
|
|
930
|
+
explicit ChaChaPolyDecipher()
|
|
931
|
+
: ctx_main_(nullptr),
|
|
932
|
+
ctx_pktlen_(nullptr),
|
|
933
|
+
md_ctx_(nullptr),
|
|
934
|
+
polykey_(nullptr) {}
|
|
935
|
+
|
|
936
|
+
~ChaChaPolyDecipher() {
|
|
937
|
+
clear();
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
void clear() {
|
|
941
|
+
if (ctx_pktlen_) {
|
|
942
|
+
EVP_CIPHER_CTX_cleanup(ctx_pktlen_);
|
|
943
|
+
EVP_CIPHER_CTX_free(ctx_pktlen_);
|
|
944
|
+
ctx_pktlen_ = nullptr;
|
|
945
|
+
}
|
|
946
|
+
if (ctx_main_) {
|
|
947
|
+
EVP_CIPHER_CTX_cleanup(ctx_main_);
|
|
948
|
+
EVP_CIPHER_CTX_free(ctx_main_);
|
|
949
|
+
ctx_main_ = nullptr;
|
|
950
|
+
}
|
|
951
|
+
if (polykey_) {
|
|
952
|
+
EVP_PKEY_free(polykey_);
|
|
953
|
+
polykey_ = nullptr;
|
|
954
|
+
}
|
|
955
|
+
if (md_ctx_) {
|
|
956
|
+
EVP_MD_CTX_free(md_ctx_);
|
|
957
|
+
md_ctx_ = nullptr;
|
|
958
|
+
}
|
|
959
|
+
// `polykey_ctx_` is not explicitly freed as it is freed implicitly when
|
|
960
|
+
// `md_ctx_` is freed
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
ErrorType init(unsigned char* keys, size_t keys_len) {
|
|
964
|
+
ErrorType r = kErrNone;
|
|
965
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname("chacha20");
|
|
966
|
+
|
|
967
|
+
if (keys_len != 64) {
|
|
968
|
+
r = kErrBadKeyLen;
|
|
969
|
+
goto out;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
if (cipher == nullptr) {
|
|
973
|
+
r = kErrOpenSSL;
|
|
974
|
+
goto out;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
if ((ctx_pktlen_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
978
|
+
|| (ctx_main_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
979
|
+
|| (md_ctx_ = EVP_MD_CTX_new()) == nullptr
|
|
980
|
+
|| EVP_DecryptInit_ex(ctx_pktlen_,
|
|
981
|
+
cipher,
|
|
982
|
+
nullptr,
|
|
983
|
+
keys + 32,
|
|
984
|
+
nullptr) != 1
|
|
985
|
+
|| EVP_DecryptInit_ex(ctx_main_,
|
|
986
|
+
cipher,
|
|
987
|
+
nullptr,
|
|
988
|
+
keys,
|
|
989
|
+
nullptr) != 1) {
|
|
990
|
+
r = kErrOpenSSL;
|
|
991
|
+
goto out;
|
|
992
|
+
}
|
|
993
|
+
if (EVP_CIPHER_CTX_iv_length(ctx_pktlen_) != 16) {
|
|
994
|
+
r = kErrBadIVLen;
|
|
995
|
+
goto out;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
out:
|
|
999
|
+
return r;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
ErrorType decrypt_length(unsigned char* data,
|
|
1003
|
+
size_t data_len,
|
|
1004
|
+
uint32_t seqno,
|
|
1005
|
+
uint32_t* packet_length) {
|
|
1006
|
+
ErrorType r = kErrNone;
|
|
1007
|
+
int outlen;
|
|
1008
|
+
|
|
1009
|
+
unsigned char dec_length_bytes[4];
|
|
1010
|
+
|
|
1011
|
+
uint8_t seqbuf[16] = {0};
|
|
1012
|
+
((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff;
|
|
1013
|
+
((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff;
|
|
1014
|
+
((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff;
|
|
1015
|
+
((uint8_t*)(seqbuf))[15] = seqno & 0xff;
|
|
1016
|
+
|
|
1017
|
+
if (EVP_DecryptInit_ex(ctx_pktlen_,
|
|
1018
|
+
nullptr,
|
|
1019
|
+
nullptr,
|
|
1020
|
+
nullptr,
|
|
1021
|
+
seqbuf) != 1) {
|
|
1022
|
+
r = kErrOpenSSL;
|
|
1023
|
+
goto out;
|
|
1024
|
+
}
|
|
1025
|
+
if (EVP_DecryptUpdate(ctx_pktlen_,
|
|
1026
|
+
dec_length_bytes,
|
|
1027
|
+
&outlen,
|
|
1028
|
+
data,
|
|
1029
|
+
data_len) != 1) {
|
|
1030
|
+
r = kErrOpenSSL;
|
|
1031
|
+
goto out;
|
|
1032
|
+
}
|
|
1033
|
+
if (static_cast<size_t>(outlen) != 4) {
|
|
1034
|
+
r = kErrPartialDecrypt;
|
|
1035
|
+
goto out;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
*packet_length = (uint32_t)dec_length_bytes[0] << 24
|
|
1039
|
+
| (uint32_t)dec_length_bytes[1] << 16
|
|
1040
|
+
| (uint32_t)dec_length_bytes[2] << 8
|
|
1041
|
+
| (uint32_t)dec_length_bytes[3];
|
|
1042
|
+
memcpy(length_bytes, data, data_len);
|
|
1043
|
+
out:
|
|
1044
|
+
return r;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
ErrorType decrypt(unsigned char* packet,
|
|
1048
|
+
uint32_t packet_len,
|
|
1049
|
+
unsigned char* mac,
|
|
1050
|
+
uint32_t seqno) {
|
|
1051
|
+
ErrorType r = kErrNone;
|
|
1052
|
+
size_t sig_len = 16;
|
|
1053
|
+
int outlen = 0;
|
|
1054
|
+
|
|
1055
|
+
// `packet` layout:
|
|
1056
|
+
// <padding length> <payload> <padding>
|
|
1057
|
+
|
|
1058
|
+
unsigned char polykey[POLY1305_KEYLEN] = {0};
|
|
1059
|
+
unsigned char calc_mac[POLY1305_TAGLEN] = {0};
|
|
1060
|
+
|
|
1061
|
+
uint8_t seqbuf[16] = {0};
|
|
1062
|
+
((uint8_t*)(seqbuf))[12] = (seqno >> 24) & 0xff;
|
|
1063
|
+
((uint8_t*)(seqbuf))[13] = (seqno >> 16) & 0xff;
|
|
1064
|
+
((uint8_t*)(seqbuf))[14] = (seqno >> 8) & 0xff;
|
|
1065
|
+
((uint8_t*)(seqbuf))[15] = seqno & 0xff;
|
|
1066
|
+
|
|
1067
|
+
// Generate Poly1305 key
|
|
1068
|
+
if (EVP_EncryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
|
|
1069
|
+
r = kErrOpenSSL;
|
|
1070
|
+
goto out;
|
|
1071
|
+
}
|
|
1072
|
+
if (EVP_EncryptUpdate(ctx_main_,
|
|
1073
|
+
polykey,
|
|
1074
|
+
&outlen,
|
|
1075
|
+
polykey,
|
|
1076
|
+
sizeof(polykey)) != 1) {
|
|
1077
|
+
r = kErrOpenSSL;
|
|
1078
|
+
goto out;
|
|
1079
|
+
}
|
|
1080
|
+
if (static_cast<size_t>(outlen) != sizeof(polykey)) {
|
|
1081
|
+
r = kErrPartialEncrypt;
|
|
1082
|
+
goto out;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// Poly1305 over ciphertext
|
|
1086
|
+
if (polykey_) {
|
|
1087
|
+
if (EVP_PKEY_CTX_ctrl(polykey_ctx_,
|
|
1088
|
+
-1,
|
|
1089
|
+
EVP_PKEY_OP_SIGNCTX,
|
|
1090
|
+
EVP_PKEY_CTRL_SET_MAC_KEY,
|
|
1091
|
+
sizeof(polykey),
|
|
1092
|
+
(void*)polykey) <= 0) {
|
|
1093
|
+
r = kErrOpenSSL;
|
|
1094
|
+
goto out;
|
|
1095
|
+
}
|
|
1096
|
+
} else {
|
|
1097
|
+
polykey_ = EVP_PKEY_new_raw_private_key(EVP_PKEY_POLY1305,
|
|
1098
|
+
nullptr,
|
|
1099
|
+
polykey,
|
|
1100
|
+
sizeof(polykey));
|
|
1101
|
+
if (polykey_ == nullptr) {
|
|
1102
|
+
r = kErrOpenSSL;
|
|
1103
|
+
goto out;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
if (!EVP_DigestSignInit(md_ctx_,
|
|
1107
|
+
&polykey_ctx_,
|
|
1108
|
+
nullptr,
|
|
1109
|
+
nullptr,
|
|
1110
|
+
polykey_)) {
|
|
1111
|
+
r = kErrOpenSSL;
|
|
1112
|
+
goto out;
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
if (EVP_DigestSignUpdate(md_ctx_,
|
|
1116
|
+
length_bytes,
|
|
1117
|
+
sizeof(length_bytes)) != 1) {
|
|
1118
|
+
r = kErrOpenSSL;
|
|
1119
|
+
goto out;
|
|
1120
|
+
}
|
|
1121
|
+
if (EVP_DigestSignUpdate(md_ctx_, packet, packet_len) != 1) {
|
|
1122
|
+
r = kErrOpenSSL;
|
|
1123
|
+
goto out;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Generate Poly1305 MAC
|
|
1127
|
+
if (EVP_DigestSignFinal(md_ctx_, calc_mac, &sig_len) != 1) {
|
|
1128
|
+
r = kErrOpenSSL;
|
|
1129
|
+
goto out;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// Compare MACs
|
|
1133
|
+
if (CRYPTO_memcmp(mac, calc_mac, sizeof(calc_mac))) {
|
|
1134
|
+
r = kErrInvalidMAC;
|
|
1135
|
+
goto out;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Decrypt packet
|
|
1139
|
+
seqbuf[0] = 1;
|
|
1140
|
+
if (EVP_DecryptInit_ex(ctx_main_, nullptr, nullptr, nullptr, seqbuf) != 1) {
|
|
1141
|
+
r = kErrOpenSSL;
|
|
1142
|
+
goto out;
|
|
1143
|
+
}
|
|
1144
|
+
if (EVP_DecryptUpdate(ctx_main_,
|
|
1145
|
+
packet,
|
|
1146
|
+
&outlen,
|
|
1147
|
+
packet,
|
|
1148
|
+
packet_len) != 1) {
|
|
1149
|
+
r = kErrOpenSSL;
|
|
1150
|
+
goto out;
|
|
1151
|
+
}
|
|
1152
|
+
if (static_cast<size_t>(outlen) != packet_len) {
|
|
1153
|
+
r = kErrPartialDecrypt;
|
|
1154
|
+
goto out;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
out:
|
|
1158
|
+
return r;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
static NAN_METHOD(New) {
|
|
1162
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1163
|
+
|
|
1164
|
+
if (!Buffer::HasInstance(info[0]))
|
|
1165
|
+
return Nan::ThrowTypeError("Missing/Invalid keys");
|
|
1166
|
+
|
|
1167
|
+
ChaChaPolyDecipher* obj = new ChaChaPolyDecipher();
|
|
1168
|
+
ErrorType r = obj->init(
|
|
1169
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
1170
|
+
Buffer::Length(info[0])
|
|
1171
|
+
);
|
|
1172
|
+
if (r != kErrNone) {
|
|
1173
|
+
if (r == kErrOpenSSL) {
|
|
1174
|
+
char msg_buf[128] = {0};
|
|
1175
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1176
|
+
ERR_clear_error();
|
|
1177
|
+
obj->clear();
|
|
1178
|
+
delete obj;
|
|
1179
|
+
return Nan::ThrowError(msg_buf);
|
|
1180
|
+
}
|
|
1181
|
+
obj->clear();
|
|
1182
|
+
delete obj;
|
|
1183
|
+
switch (r) {
|
|
1184
|
+
case kErrBadKeyLen:
|
|
1185
|
+
return Nan::ThrowError("Invalid keys length");
|
|
1186
|
+
case kErrBadIVLen:
|
|
1187
|
+
return Nan::ThrowError("Invalid IV length");
|
|
1188
|
+
default:
|
|
1189
|
+
return Nan::ThrowError("Unknown init failure");
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
obj->Wrap(info.This());
|
|
1194
|
+
info.GetReturnValue().Set(info.This());
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
static NAN_METHOD(DecryptLen) {
|
|
1198
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1199
|
+
|
|
1200
|
+
ChaChaPolyDecipher* obj =
|
|
1201
|
+
ObjectWrap::Unwrap<ChaChaPolyDecipher>(info.Holder());
|
|
1202
|
+
|
|
1203
|
+
if (!Buffer::HasInstance(info[0]) || Buffer::Length(info[0]) != 4)
|
|
1204
|
+
return Nan::ThrowTypeError("Missing/Invalid length bytes");
|
|
1205
|
+
|
|
1206
|
+
if (!info[1]->IsUint32())
|
|
1207
|
+
return Nan::ThrowTypeError("Missing/Invalid sequence number");
|
|
1208
|
+
|
|
1209
|
+
unsigned char* length_bytes =
|
|
1210
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0]));
|
|
1211
|
+
|
|
1212
|
+
uint32_t dec_packet_length;
|
|
1213
|
+
ErrorType r = obj->decrypt_length(
|
|
1214
|
+
length_bytes,
|
|
1215
|
+
Buffer::Length(info[0]),
|
|
1216
|
+
Nan::To<uint32_t>(info[1]).FromJust(),
|
|
1217
|
+
&dec_packet_length
|
|
1218
|
+
);
|
|
1219
|
+
|
|
1220
|
+
switch (r) {
|
|
1221
|
+
case kErrNone:
|
|
1222
|
+
return info.GetReturnValue().Set(dec_packet_length);
|
|
1223
|
+
case kErrPartialDecrypt:
|
|
1224
|
+
return Nan::ThrowError("Failed to completely decrypt packet length");
|
|
1225
|
+
case kErrOpenSSL: {
|
|
1226
|
+
char msg_buf[128] = {0};
|
|
1227
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1228
|
+
ERR_clear_error();
|
|
1229
|
+
return Nan::ThrowError(msg_buf);
|
|
1230
|
+
}
|
|
1231
|
+
default:
|
|
1232
|
+
return Nan::ThrowError("Unknown decrypt failure");
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
static NAN_METHOD(Decrypt) {
|
|
1237
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1238
|
+
|
|
1239
|
+
ChaChaPolyDecipher* obj =
|
|
1240
|
+
ObjectWrap::Unwrap<ChaChaPolyDecipher>(info.Holder());
|
|
1241
|
+
|
|
1242
|
+
if (!Buffer::HasInstance(info[0]))
|
|
1243
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
1244
|
+
|
|
1245
|
+
if (!Buffer::HasInstance(info[1])
|
|
1246
|
+
|| Buffer::Length(info[1]) != POLY1305_TAGLEN) {
|
|
1247
|
+
return Nan::ThrowTypeError("Missing/Invalid mac");
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (!info[2]->IsUint32())
|
|
1251
|
+
return Nan::ThrowTypeError("Missing/Invalid sequence number");
|
|
1252
|
+
|
|
1253
|
+
ErrorType r = obj->decrypt(
|
|
1254
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
1255
|
+
Buffer::Length(info[0]),
|
|
1256
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[1])),
|
|
1257
|
+
Nan::To<uint32_t>(info[2]).FromJust()
|
|
1258
|
+
);
|
|
1259
|
+
|
|
1260
|
+
switch (r) {
|
|
1261
|
+
case kErrNone:
|
|
1262
|
+
return;
|
|
1263
|
+
case kErrInvalidMAC:
|
|
1264
|
+
return Nan::ThrowError("Invalid MAC");
|
|
1265
|
+
case kErrPartialDecrypt:
|
|
1266
|
+
return Nan::ThrowError("Failed to completely decrypt packet length");
|
|
1267
|
+
case kErrOpenSSL: {
|
|
1268
|
+
char msg_buf[128] = {0};
|
|
1269
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1270
|
+
ERR_clear_error();
|
|
1271
|
+
return Nan::ThrowError(msg_buf);
|
|
1272
|
+
}
|
|
1273
|
+
default:
|
|
1274
|
+
return Nan::ThrowError("Unknown decrypt failure");
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
static NAN_METHOD(Free) {
|
|
1279
|
+
ChaChaPolyDecipher* obj =
|
|
1280
|
+
ObjectWrap::Unwrap<ChaChaPolyDecipher>(info.Holder());
|
|
1281
|
+
obj->clear();
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
1285
|
+
static Nan::Persistent<Function> my_constructor;
|
|
1286
|
+
return my_constructor;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
unsigned char length_bytes[4];
|
|
1290
|
+
EVP_CIPHER_CTX* ctx_main_;
|
|
1291
|
+
EVP_CIPHER_CTX* ctx_pktlen_;
|
|
1292
|
+
EVP_MD_CTX* md_ctx_;
|
|
1293
|
+
EVP_PKEY* polykey_;
|
|
1294
|
+
EVP_PKEY_CTX* polykey_ctx_;
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
class AESGCMDecipher : public ObjectWrap {
|
|
1298
|
+
public:
|
|
1299
|
+
static NAN_MODULE_INIT(Init) {
|
|
1300
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
1301
|
+
tpl->SetClassName(Nan::New("AESGCMDecipher").ToLocalChecked());
|
|
1302
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
1303
|
+
|
|
1304
|
+
SetPrototypeMethod(tpl, "decrypt", Decrypt);
|
|
1305
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
1306
|
+
|
|
1307
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
1308
|
+
|
|
1309
|
+
Nan::Set(target,
|
|
1310
|
+
Nan::New("AESGCMDecipher").ToLocalChecked(),
|
|
1311
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
private:
|
|
1315
|
+
explicit AESGCMDecipher() : ctx_(nullptr) {}
|
|
1316
|
+
|
|
1317
|
+
~AESGCMDecipher() {
|
|
1318
|
+
clear();
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
void clear() {
|
|
1322
|
+
if (ctx_) {
|
|
1323
|
+
EVP_CIPHER_CTX_cleanup(ctx_);
|
|
1324
|
+
EVP_CIPHER_CTX_free(ctx_);
|
|
1325
|
+
ctx_ = nullptr;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
ErrorType init(const char* name,
|
|
1330
|
+
unsigned char* key,
|
|
1331
|
+
size_t key_len,
|
|
1332
|
+
unsigned char* iv,
|
|
1333
|
+
size_t iv_len) {
|
|
1334
|
+
ErrorType r = kErrNone;
|
|
1335
|
+
|
|
1336
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
|
|
1337
|
+
if (cipher == nullptr) {
|
|
1338
|
+
r = kErrOpenSSL;
|
|
1339
|
+
goto out;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
if (cipher != EVP_aes_128_gcm() && cipher != EVP_aes_256_gcm()) {
|
|
1343
|
+
r = kErrBadCipherName;
|
|
1344
|
+
goto out;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
1348
|
+
|| EVP_DecryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
|
|
1349
|
+
r = kErrOpenSSL;
|
|
1350
|
+
goto out;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr)) {
|
|
1354
|
+
r = kErrOpenSSL;
|
|
1355
|
+
goto out;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
//~ if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
|
|
1359
|
+
//~ r = kErrBadIVLen;
|
|
1360
|
+
//~ goto out;
|
|
1361
|
+
//~ }
|
|
1362
|
+
|
|
1363
|
+
if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
|
|
1364
|
+
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
|
1365
|
+
r = kErrBadKeyLen;
|
|
1366
|
+
goto out;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Set key and IV
|
|
1371
|
+
if (EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
|
|
1372
|
+
r = kErrOpenSSL;
|
|
1373
|
+
goto out;
|
|
1374
|
+
}
|
|
1375
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IV_FIXED, -1, iv)) {
|
|
1376
|
+
r = kErrOpenSSL;
|
|
1377
|
+
goto out;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
// Disable padding
|
|
1381
|
+
EVP_CIPHER_CTX_set_padding(ctx_, 0);
|
|
1382
|
+
|
|
1383
|
+
out:
|
|
1384
|
+
return r;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
ErrorType decrypt(unsigned char* packet,
|
|
1388
|
+
uint32_t packet_len,
|
|
1389
|
+
unsigned char* length_bytes,
|
|
1390
|
+
unsigned char* tag) {
|
|
1391
|
+
ErrorType r = kErrNone;
|
|
1392
|
+
|
|
1393
|
+
// `packet` layout:
|
|
1394
|
+
// <padding length> <payload> <padding>
|
|
1395
|
+
|
|
1396
|
+
int outlen;
|
|
1397
|
+
|
|
1398
|
+
// Increment IV
|
|
1399
|
+
unsigned char lastiv[1];
|
|
1400
|
+
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_IV_GEN, 1, lastiv)) {
|
|
1401
|
+
r = kErrOpenSSL;
|
|
1402
|
+
goto out;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
// Set AAD (the packet length)
|
|
1406
|
+
if (!EVP_DecryptUpdate(ctx_, nullptr, &outlen, length_bytes, 4)) {
|
|
1407
|
+
r = kErrOpenSSL;
|
|
1408
|
+
goto out;
|
|
1409
|
+
}
|
|
1410
|
+
if (outlen != 4) {
|
|
1411
|
+
r = kErrAADFailure;
|
|
1412
|
+
goto out;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// Decrypt everything but the packet length
|
|
1416
|
+
if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) {
|
|
1417
|
+
r = kErrOpenSSL;
|
|
1418
|
+
goto out;
|
|
1419
|
+
}
|
|
1420
|
+
if (static_cast<size_t>(outlen) != packet_len) {
|
|
1421
|
+
r = kErrPartialDecrypt;
|
|
1422
|
+
goto out;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// Set authentication tag
|
|
1426
|
+
if (EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_TAG, 16, tag) != 1) {
|
|
1427
|
+
r = kErrOpenSSL;
|
|
1428
|
+
goto out;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
// Verify authentication tag
|
|
1432
|
+
if (!EVP_DecryptFinal_ex(ctx_, nullptr, &outlen)) {
|
|
1433
|
+
r = kErrOpenSSL;
|
|
1434
|
+
goto out;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
out:
|
|
1438
|
+
return r;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
static NAN_METHOD(New) {
|
|
1442
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1443
|
+
|
|
1444
|
+
if (!info[0]->IsString())
|
|
1445
|
+
return Nan::ThrowTypeError("Missing/Invalid OpenSSL cipher name");
|
|
1446
|
+
|
|
1447
|
+
if (!Buffer::HasInstance(info[1]))
|
|
1448
|
+
return Nan::ThrowTypeError("Missing/Invalid key");
|
|
1449
|
+
|
|
1450
|
+
if (!Buffer::HasInstance(info[2]))
|
|
1451
|
+
return Nan::ThrowTypeError("Missing/Invalid iv");
|
|
1452
|
+
|
|
1453
|
+
const Nan::Utf8String cipher_name(info[0]);
|
|
1454
|
+
|
|
1455
|
+
AESGCMDecipher* obj = new AESGCMDecipher();
|
|
1456
|
+
ErrorType r = obj->init(
|
|
1457
|
+
*cipher_name,
|
|
1458
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[1])),
|
|
1459
|
+
Buffer::Length(info[1]),
|
|
1460
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2])),
|
|
1461
|
+
Buffer::Length(info[2])
|
|
1462
|
+
);
|
|
1463
|
+
if (r != kErrNone) {
|
|
1464
|
+
if (r == kErrOpenSSL) {
|
|
1465
|
+
char msg_buf[128] = {0};
|
|
1466
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1467
|
+
ERR_clear_error();
|
|
1468
|
+
obj->clear();
|
|
1469
|
+
delete obj;
|
|
1470
|
+
return Nan::ThrowError(msg_buf);
|
|
1471
|
+
}
|
|
1472
|
+
obj->clear();
|
|
1473
|
+
delete obj;
|
|
1474
|
+
switch (r) {
|
|
1475
|
+
case kErrBadKeyLen:
|
|
1476
|
+
return Nan::ThrowError("Invalid keys length");
|
|
1477
|
+
case kErrBadIVLen:
|
|
1478
|
+
return Nan::ThrowError("Invalid IV length");
|
|
1479
|
+
case kErrBadCipherName:
|
|
1480
|
+
return Nan::ThrowError("Invalid AES GCM cipher name");
|
|
1481
|
+
default:
|
|
1482
|
+
return Nan::ThrowError("Unknown init failure");
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
obj->Wrap(info.This());
|
|
1487
|
+
info.GetReturnValue().Set(info.This());
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
static NAN_METHOD(Decrypt) {
|
|
1491
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1492
|
+
|
|
1493
|
+
AESGCMDecipher* obj = ObjectWrap::Unwrap<AESGCMDecipher>(info.Holder());
|
|
1494
|
+
|
|
1495
|
+
if (!Buffer::HasInstance(info[0]))
|
|
1496
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
1497
|
+
|
|
1498
|
+
if (!info[1]->IsUint32())
|
|
1499
|
+
return Nan::ThrowTypeError("Missing/Invalid length");
|
|
1500
|
+
|
|
1501
|
+
if (!Buffer::HasInstance(info[2]) || Buffer::Length(info[2]) != 16)
|
|
1502
|
+
return Nan::ThrowTypeError("Missing/Invalid tag");
|
|
1503
|
+
|
|
1504
|
+
uint32_t length = Nan::To<uint32_t>(info[1]).FromJust();
|
|
1505
|
+
unsigned char length_bytes[4];
|
|
1506
|
+
length_bytes[0] = (length >> 24) & 0xFF;
|
|
1507
|
+
length_bytes[1] = (length >> 16) & 0xFF;
|
|
1508
|
+
length_bytes[2] = (length >> 8) & 0xFF;
|
|
1509
|
+
length_bytes[3] = length & 0xFF;
|
|
1510
|
+
|
|
1511
|
+
ErrorType r = obj->decrypt(
|
|
1512
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
1513
|
+
Buffer::Length(info[0]),
|
|
1514
|
+
length_bytes,
|
|
1515
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2]))
|
|
1516
|
+
);
|
|
1517
|
+
switch (r) {
|
|
1518
|
+
case kErrNone:
|
|
1519
|
+
return;
|
|
1520
|
+
case kErrAADFailure:
|
|
1521
|
+
return Nan::ThrowError("Error setting AAD");
|
|
1522
|
+
case kErrPartialDecrypt:
|
|
1523
|
+
return Nan::ThrowError("Failed to completely decrypt packet");
|
|
1524
|
+
case kErrTagFailure:
|
|
1525
|
+
return Nan::ThrowError("Error generating authentication tag");
|
|
1526
|
+
case kErrOpenSSL: {
|
|
1527
|
+
char msg_buf[128] = {0};
|
|
1528
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1529
|
+
ERR_clear_error();
|
|
1530
|
+
return Nan::ThrowError(msg_buf);
|
|
1531
|
+
}
|
|
1532
|
+
default:
|
|
1533
|
+
return Nan::ThrowError("Unknown decrypt failure");
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
static NAN_METHOD(Free) {
|
|
1538
|
+
AESGCMDecipher* obj = ObjectWrap::Unwrap<AESGCMDecipher>(info.Holder());
|
|
1539
|
+
obj->clear();
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
1543
|
+
static Nan::Persistent<Function> my_constructor;
|
|
1544
|
+
return my_constructor;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
EVP_CIPHER_CTX* ctx_;
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
class GenericDecipher : public ObjectWrap {
|
|
1551
|
+
public:
|
|
1552
|
+
static NAN_MODULE_INIT(Init) {
|
|
1553
|
+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
|
|
1554
|
+
tpl->SetClassName(Nan::New("GenericDecipher").ToLocalChecked());
|
|
1555
|
+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
|
1556
|
+
|
|
1557
|
+
SetPrototypeMethod(tpl, "decryptBlock", DecryptBlock);
|
|
1558
|
+
SetPrototypeMethod(tpl, "decrypt", Decrypt);
|
|
1559
|
+
SetPrototypeMethod(tpl, "free", Free);
|
|
1560
|
+
|
|
1561
|
+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
|
1562
|
+
|
|
1563
|
+
Nan::Set(target,
|
|
1564
|
+
Nan::New("GenericDecipher").ToLocalChecked(),
|
|
1565
|
+
Nan::GetFunction(tpl).ToLocalChecked());
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
private:
|
|
1569
|
+
explicit GenericDecipher()
|
|
1570
|
+
: ctx_(nullptr),
|
|
1571
|
+
ctx_hmac_(nullptr),
|
|
1572
|
+
hmac_len_(0),
|
|
1573
|
+
is_etm_(0) {}
|
|
1574
|
+
|
|
1575
|
+
~GenericDecipher() {
|
|
1576
|
+
clear();
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
void clear() {
|
|
1580
|
+
if (ctx_) {
|
|
1581
|
+
EVP_CIPHER_CTX_cleanup(ctx_);
|
|
1582
|
+
EVP_CIPHER_CTX_free(ctx_);
|
|
1583
|
+
ctx_ = nullptr;
|
|
1584
|
+
}
|
|
1585
|
+
if (ctx_hmac_) {
|
|
1586
|
+
HMAC_CTX_free(ctx_hmac_);
|
|
1587
|
+
ctx_hmac_ = nullptr;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
ErrorType init(const char* name,
|
|
1592
|
+
unsigned char* key,
|
|
1593
|
+
size_t key_len,
|
|
1594
|
+
unsigned char* iv,
|
|
1595
|
+
size_t iv_len,
|
|
1596
|
+
const char* hmac_name,
|
|
1597
|
+
unsigned char* hmac_key,
|
|
1598
|
+
size_t hmac_key_len,
|
|
1599
|
+
int is_etm,
|
|
1600
|
+
size_t hmac_actual_len) {
|
|
1601
|
+
ErrorType r = kErrNone;
|
|
1602
|
+
|
|
1603
|
+
const EVP_MD* md;
|
|
1604
|
+
const EVP_CIPHER* const cipher = EVP_get_cipherbyname(name);
|
|
1605
|
+
if (cipher == nullptr) {
|
|
1606
|
+
r = kErrOpenSSL;
|
|
1607
|
+
goto out;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
if ((ctx_ = EVP_CIPHER_CTX_new()) == nullptr
|
|
1611
|
+
|| EVP_DecryptInit_ex(ctx_, cipher, nullptr, nullptr, nullptr) != 1) {
|
|
1612
|
+
r = kErrOpenSSL;
|
|
1613
|
+
goto out;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
if (iv_len != static_cast<size_t>(EVP_CIPHER_CTX_iv_length(ctx_))) {
|
|
1617
|
+
r = kErrBadIVLen;
|
|
1618
|
+
goto out;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
if (key_len != static_cast<size_t>(EVP_CIPHER_CTX_key_length(ctx_))) {
|
|
1622
|
+
if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) {
|
|
1623
|
+
r = kErrBadKeyLen;
|
|
1624
|
+
goto out;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// Set key and IV
|
|
1629
|
+
if (EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, iv) != 1) {
|
|
1630
|
+
r = kErrOpenSSL;
|
|
1631
|
+
goto out;
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// Disable padding
|
|
1635
|
+
EVP_CIPHER_CTX_set_padding(ctx_, 0);
|
|
1636
|
+
|
|
1637
|
+
if (cipher == EVP_rc4()) {
|
|
1638
|
+
/* The "arcfour128" algorithm is the RC4 cipher, as described in
|
|
1639
|
+
[SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
|
|
1640
|
+
generated by the cipher MUST be discarded, and the first byte of the
|
|
1641
|
+
first encrypted packet MUST be encrypted using the 1537th byte of
|
|
1642
|
+
keystream.
|
|
1643
|
+
|
|
1644
|
+
-- http://tools.ietf.org/html/rfc4345#section-4 */
|
|
1645
|
+
unsigned char zeros[1536] = {0};
|
|
1646
|
+
int outlen = sizeof(zeros);
|
|
1647
|
+
if (EVP_DecryptUpdate(ctx_,
|
|
1648
|
+
zeros,
|
|
1649
|
+
&outlen,
|
|
1650
|
+
zeros,
|
|
1651
|
+
sizeof(zeros)) != 1) {
|
|
1652
|
+
r = kErrOpenSSL;
|
|
1653
|
+
goto out;
|
|
1654
|
+
}
|
|
1655
|
+
if (static_cast<size_t>(outlen) != sizeof(zeros)) {
|
|
1656
|
+
r = kErrBadInit;
|
|
1657
|
+
goto out;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
md = EVP_get_digestbyname(hmac_name);
|
|
1662
|
+
if (md == nullptr) {
|
|
1663
|
+
r = kErrBadHMACName;
|
|
1664
|
+
goto out;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
if ((ctx_hmac_ = HMAC_CTX_new()) == nullptr
|
|
1668
|
+
|| HMAC_Init_ex(ctx_hmac_, hmac_key, hmac_key_len, md, nullptr) != 1) {
|
|
1669
|
+
r = kErrOpenSSL;
|
|
1670
|
+
goto out;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
hmac_len_ = HMAC_size(ctx_hmac_);
|
|
1674
|
+
hmac_actual_len_ = hmac_actual_len;
|
|
1675
|
+
is_etm_ = is_etm;
|
|
1676
|
+
switch (EVP_CIPHER_CTX_mode(ctx_)) {
|
|
1677
|
+
case EVP_CIPH_STREAM_CIPHER:
|
|
1678
|
+
case EVP_CIPH_CTR_MODE:
|
|
1679
|
+
is_stream_ = 1;
|
|
1680
|
+
break;
|
|
1681
|
+
default:
|
|
1682
|
+
is_stream_ = 0;
|
|
1683
|
+
}
|
|
1684
|
+
block_size_ = EVP_CIPHER_CTX_block_size(ctx_);
|
|
1685
|
+
|
|
1686
|
+
out:
|
|
1687
|
+
return r;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
ErrorType decrypt_block(unsigned char* data, uint32_t data_len) {
|
|
1691
|
+
ErrorType r = kErrNone;
|
|
1692
|
+
|
|
1693
|
+
int outlen;
|
|
1694
|
+
|
|
1695
|
+
if (!is_stream_ && data_len != block_size_) {
|
|
1696
|
+
r = kErrBadBlockLen;
|
|
1697
|
+
goto out;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
// Decrypt block
|
|
1701
|
+
if (EVP_DecryptUpdate(ctx_, data, &outlen, data, data_len) != 1) {
|
|
1702
|
+
r = kErrOpenSSL;
|
|
1703
|
+
goto out;
|
|
1704
|
+
}
|
|
1705
|
+
if (static_cast<size_t>(outlen) != data_len) {
|
|
1706
|
+
r = kErrPartialDecrypt;
|
|
1707
|
+
goto out;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
out:
|
|
1711
|
+
return r;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
ErrorType decrypt(unsigned char* packet,
|
|
1715
|
+
uint32_t packet_len,
|
|
1716
|
+
uint32_t seqno,
|
|
1717
|
+
unsigned char* first_block,
|
|
1718
|
+
uint32_t first_block_len,
|
|
1719
|
+
unsigned char* mac,
|
|
1720
|
+
uint32_t mac_len) {
|
|
1721
|
+
ErrorType r = kErrNone;
|
|
1722
|
+
|
|
1723
|
+
int outlen;
|
|
1724
|
+
unsigned char calc_mac[MAX_MAC_LEN] = {0};
|
|
1725
|
+
|
|
1726
|
+
uint8_t seqbuf[4] = {0};
|
|
1727
|
+
((uint8_t*)(seqbuf))[0] = (seqno >> 24) & 0xff;
|
|
1728
|
+
((uint8_t*)(seqbuf))[1] = (seqno >> 16) & 0xff;
|
|
1729
|
+
((uint8_t*)(seqbuf))[2] = (seqno >> 8) & 0xff;
|
|
1730
|
+
((uint8_t*)(seqbuf))[3] = seqno & 0xff;
|
|
1731
|
+
|
|
1732
|
+
if (is_etm_) {
|
|
1733
|
+
// `first_block` for ETM should just be the unencrypted packet length
|
|
1734
|
+
if (first_block_len != 4) {
|
|
1735
|
+
r = kErrBadBlockLen;
|
|
1736
|
+
goto out;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// HMAC over unencrypted packet length and ciphertext
|
|
1740
|
+
{
|
|
1741
|
+
unsigned int outlen = hmac_len_;
|
|
1742
|
+
if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
|
|
1743
|
+
|| HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
|
|
1744
|
+
|| HMAC_Update(ctx_hmac_, first_block, 4) != 1
|
|
1745
|
+
|| HMAC_Update(ctx_hmac_, packet, packet_len) != 1
|
|
1746
|
+
|| HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) {
|
|
1747
|
+
r = kErrOpenSSL;
|
|
1748
|
+
goto out;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
if (outlen != hmac_len_ || mac_len != hmac_len_) {
|
|
1752
|
+
r = kErrBadHMACLen;
|
|
1753
|
+
goto out;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// Compare MACs
|
|
1757
|
+
if (CRYPTO_memcmp(mac, calc_mac, hmac_len_)) {
|
|
1758
|
+
r = kErrInvalidMAC;
|
|
1759
|
+
goto out;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
// Decrypt packet
|
|
1764
|
+
if (EVP_DecryptUpdate(ctx_, packet, &outlen, packet, packet_len) != 1) {
|
|
1765
|
+
r = kErrOpenSSL;
|
|
1766
|
+
goto out;
|
|
1767
|
+
}
|
|
1768
|
+
if (static_cast<size_t>(outlen) != packet_len) {
|
|
1769
|
+
r = kErrPartialDecrypt;
|
|
1770
|
+
goto out;
|
|
1771
|
+
}
|
|
1772
|
+
} else {
|
|
1773
|
+
// `first_block` for non-ETM should be a completely decrypted first block
|
|
1774
|
+
if (!is_stream_ && first_block_len != block_size_) {
|
|
1775
|
+
r = kErrBadBlockLen;
|
|
1776
|
+
goto out;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
const int offset = (is_stream_ ? 0 : block_size_ - 4);
|
|
1780
|
+
// Decrypt the rest of the packet
|
|
1781
|
+
if (EVP_DecryptUpdate(ctx_,
|
|
1782
|
+
packet + offset,
|
|
1783
|
+
&outlen,
|
|
1784
|
+
packet + offset,
|
|
1785
|
+
packet_len - offset) != 1) {
|
|
1786
|
+
r = kErrOpenSSL;
|
|
1787
|
+
goto out;
|
|
1788
|
+
}
|
|
1789
|
+
if (static_cast<size_t>(outlen) != packet_len - offset) {
|
|
1790
|
+
r = kErrPartialDecrypt;
|
|
1791
|
+
goto out;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// HMAC over plaintext
|
|
1795
|
+
{
|
|
1796
|
+
unsigned int outlen = hmac_len_;
|
|
1797
|
+
if (HMAC_Init_ex(ctx_hmac_, nullptr, 0, nullptr, nullptr) != 1
|
|
1798
|
+
|| HMAC_Update(ctx_hmac_, seqbuf, sizeof(seqbuf)) != 1
|
|
1799
|
+
|| HMAC_Update(ctx_hmac_, first_block, 4) != 1
|
|
1800
|
+
|| HMAC_Update(ctx_hmac_, packet, packet_len) != 1
|
|
1801
|
+
|| HMAC_Final(ctx_hmac_, calc_mac, &outlen) != 1) {
|
|
1802
|
+
r = kErrOpenSSL;
|
|
1803
|
+
goto out;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
if (outlen != hmac_len_ || mac_len != hmac_actual_len_) {
|
|
1807
|
+
r = kErrBadHMACLen;
|
|
1808
|
+
goto out;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
// Compare MACs
|
|
1812
|
+
if (CRYPTO_memcmp(mac, calc_mac, hmac_actual_len_)) {
|
|
1813
|
+
r = kErrInvalidMAC;
|
|
1814
|
+
goto out;
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
out:
|
|
1820
|
+
return r;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
static NAN_METHOD(New) {
|
|
1824
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1825
|
+
|
|
1826
|
+
if (!info[0]->IsString())
|
|
1827
|
+
return Nan::ThrowTypeError("Missing/Invalid decipher name");
|
|
1828
|
+
|
|
1829
|
+
if (!Buffer::HasInstance(info[1]))
|
|
1830
|
+
return Nan::ThrowTypeError("Missing/Invalid decipher key");
|
|
1831
|
+
|
|
1832
|
+
if (!Buffer::HasInstance(info[2]))
|
|
1833
|
+
return Nan::ThrowTypeError("Missing/Invalid decipher IV");
|
|
1834
|
+
|
|
1835
|
+
if (!info[3]->IsString())
|
|
1836
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC name");
|
|
1837
|
+
|
|
1838
|
+
if (!Buffer::HasInstance(info[4]))
|
|
1839
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC key");
|
|
1840
|
+
|
|
1841
|
+
if (!info[5]->IsBoolean())
|
|
1842
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag");
|
|
1843
|
+
|
|
1844
|
+
if (!info[6]->IsUint32())
|
|
1845
|
+
return Nan::ThrowTypeError("Missing/Invalid HMAC ETM flag");
|
|
1846
|
+
|
|
1847
|
+
const Nan::Utf8String cipher_name(info[0]);
|
|
1848
|
+
const Nan::Utf8String mac_name(info[3]);
|
|
1849
|
+
int is_etm = (Nan::To<bool>(info[5]).FromJust() ? 1 : 0);
|
|
1850
|
+
|
|
1851
|
+
GenericDecipher* obj = new GenericDecipher();
|
|
1852
|
+
ErrorType r = obj->init(
|
|
1853
|
+
*cipher_name,
|
|
1854
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[1])),
|
|
1855
|
+
Buffer::Length(info[1]),
|
|
1856
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2])),
|
|
1857
|
+
Buffer::Length(info[2]),
|
|
1858
|
+
*mac_name,
|
|
1859
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[4])),
|
|
1860
|
+
Buffer::Length(info[4]),
|
|
1861
|
+
is_etm,
|
|
1862
|
+
Nan::To<uint32_t>(info[6]).FromJust()
|
|
1863
|
+
);
|
|
1864
|
+
if (r != kErrNone) {
|
|
1865
|
+
if (r == kErrOpenSSL) {
|
|
1866
|
+
char msg_buf[128] = {0};
|
|
1867
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1868
|
+
ERR_clear_error();
|
|
1869
|
+
obj->clear();
|
|
1870
|
+
delete obj;
|
|
1871
|
+
return Nan::ThrowError(msg_buf);
|
|
1872
|
+
}
|
|
1873
|
+
obj->clear();
|
|
1874
|
+
delete obj;
|
|
1875
|
+
switch (r) {
|
|
1876
|
+
case kErrBadKeyLen:
|
|
1877
|
+
return Nan::ThrowError("Invalid decipher key length");
|
|
1878
|
+
case kErrBadIVLen:
|
|
1879
|
+
return Nan::ThrowError("Invalid decipher IV length");
|
|
1880
|
+
case kErrBadCipherName:
|
|
1881
|
+
return Nan::ThrowError("Invalid decipher name");
|
|
1882
|
+
case kErrBadHMACName:
|
|
1883
|
+
return Nan::ThrowError("Invalid MAC name");
|
|
1884
|
+
case kErrBadInit:
|
|
1885
|
+
return Nan::ThrowError("Failed to properly initialize decipher");
|
|
1886
|
+
default:
|
|
1887
|
+
return Nan::ThrowError("Unknown init failure");
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
obj->Wrap(info.This());
|
|
1892
|
+
info.GetReturnValue().Set(info.This());
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
static NAN_METHOD(DecryptBlock) {
|
|
1896
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1897
|
+
|
|
1898
|
+
GenericDecipher* obj = ObjectWrap::Unwrap<GenericDecipher>(info.Holder());
|
|
1899
|
+
|
|
1900
|
+
if (!Buffer::HasInstance(info[0]))
|
|
1901
|
+
return Nan::ThrowTypeError("Missing/Invalid block");
|
|
1902
|
+
|
|
1903
|
+
ErrorType r = obj->decrypt_block(
|
|
1904
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
1905
|
+
Buffer::Length(info[0])
|
|
1906
|
+
);
|
|
1907
|
+
switch (r) {
|
|
1908
|
+
case kErrNone:
|
|
1909
|
+
return;
|
|
1910
|
+
case kErrBadBlockLen:
|
|
1911
|
+
return Nan::ThrowError("Invalid block length");
|
|
1912
|
+
case kErrPartialDecrypt:
|
|
1913
|
+
return Nan::ThrowError("Failed to completely decrypt packet");
|
|
1914
|
+
case kErrOpenSSL: {
|
|
1915
|
+
char msg_buf[128] = {0};
|
|
1916
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1917
|
+
ERR_clear_error();
|
|
1918
|
+
return Nan::ThrowError(msg_buf);
|
|
1919
|
+
}
|
|
1920
|
+
default:
|
|
1921
|
+
return Nan::ThrowError("Unknown decrypt failure");
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
static NAN_METHOD(Decrypt) {
|
|
1926
|
+
MarkPopErrorOnReturn mark_pop_error_on_return;
|
|
1927
|
+
|
|
1928
|
+
GenericDecipher* obj = ObjectWrap::Unwrap<GenericDecipher>(info.Holder());
|
|
1929
|
+
|
|
1930
|
+
if (!Buffer::HasInstance(info[0]))
|
|
1931
|
+
return Nan::ThrowTypeError("Missing/Invalid packet");
|
|
1932
|
+
|
|
1933
|
+
if (!info[1]->IsUint32())
|
|
1934
|
+
return Nan::ThrowTypeError("Missing/Invalid sequence number");
|
|
1935
|
+
|
|
1936
|
+
if (!Buffer::HasInstance(info[2]))
|
|
1937
|
+
return Nan::ThrowTypeError("Missing/Invalid first block");
|
|
1938
|
+
|
|
1939
|
+
if (!Buffer::HasInstance(info[3]))
|
|
1940
|
+
return Nan::ThrowTypeError("Missing/Invalid MAC");
|
|
1941
|
+
|
|
1942
|
+
ErrorType r = obj->decrypt(
|
|
1943
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[0])),
|
|
1944
|
+
Buffer::Length(info[0]),
|
|
1945
|
+
Nan::To<uint32_t>(info[1]).FromJust(),
|
|
1946
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[2])),
|
|
1947
|
+
Buffer::Length(info[2]),
|
|
1948
|
+
reinterpret_cast<unsigned char*>(Buffer::Data(info[3])),
|
|
1949
|
+
Buffer::Length(info[3])
|
|
1950
|
+
);
|
|
1951
|
+
switch (r) {
|
|
1952
|
+
case kErrNone:
|
|
1953
|
+
return;
|
|
1954
|
+
case kErrBadBlockLen:
|
|
1955
|
+
return Nan::ThrowError("Invalid block length");
|
|
1956
|
+
case kErrPartialDecrypt:
|
|
1957
|
+
return Nan::ThrowError("Failed to completely decrypt packet");
|
|
1958
|
+
case kErrBadHMACLen:
|
|
1959
|
+
return Nan::ThrowError("Unexpected HMAC length");
|
|
1960
|
+
case kErrInvalidMAC:
|
|
1961
|
+
return Nan::ThrowError("Invalid MAC");
|
|
1962
|
+
case kErrOpenSSL: {
|
|
1963
|
+
char msg_buf[128] = {0};
|
|
1964
|
+
ERR_error_string_n(ERR_get_error(), msg_buf, sizeof(msg_buf));
|
|
1965
|
+
ERR_clear_error();
|
|
1966
|
+
return Nan::ThrowError(msg_buf);
|
|
1967
|
+
}
|
|
1968
|
+
default:
|
|
1969
|
+
return Nan::ThrowError("Unknown decrypt failure");
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
static NAN_METHOD(Free) {
|
|
1974
|
+
GenericDecipher* obj = ObjectWrap::Unwrap<GenericDecipher>(info.Holder());
|
|
1975
|
+
obj->clear();
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
static inline Nan::Persistent<Function> & constructor() {
|
|
1979
|
+
static Nan::Persistent<Function> my_constructor;
|
|
1980
|
+
return my_constructor;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
EVP_CIPHER_CTX* ctx_;
|
|
1984
|
+
HMAC_CTX* ctx_hmac_;
|
|
1985
|
+
unsigned int hmac_len_;
|
|
1986
|
+
unsigned int hmac_actual_len_;
|
|
1987
|
+
uint8_t is_etm_;
|
|
1988
|
+
uint8_t is_stream_;
|
|
1989
|
+
uint32_t block_size_;
|
|
1990
|
+
};
|
|
1991
|
+
|
|
1992
|
+
|
|
1993
|
+
NAN_MODULE_INIT(init) {
|
|
1994
|
+
ChaChaPolyCipher::Init(target);
|
|
1995
|
+
AESGCMCipher::Init(target);
|
|
1996
|
+
GenericCipher::Init(target);
|
|
1997
|
+
|
|
1998
|
+
ChaChaPolyDecipher::Init(target);
|
|
1999
|
+
AESGCMDecipher::Init(target);
|
|
2000
|
+
GenericDecipher::Init(target);
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
NODE_MODULE(sshcrypto, init)
|