net-snmp 3.19.2 → 3.20.1
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 +37 -1
- package/index.js +93 -34
- package/lib/des-ecb.js +147 -0
- package/lib/des.js +53 -0
- package/package.json +1 -1
- package/test/cast-set-value.test.js +200 -0
package/README.md
CHANGED
@@ -91,7 +91,7 @@ for each shown in this table:
|
|
91
91
|
* SNMP proxy forwarder for agent
|
92
92
|
* AgentX subagent
|
93
93
|
* IPv4 and IPv6
|
94
|
-
|
94
|
+
|
95
95
|
# Standards Compliance
|
96
96
|
|
97
97
|
This module aims to be fully compliant with the following RFCs:
|
@@ -258,6 +258,34 @@ Security Model RFC (RFC 3414); 128-bit AES for SNMPv3 was added later in RFC 382
|
|
258
258
|
localization. Cisco and a number of other vendors commonly use the "Reeder" key
|
259
259
|
localization variant. Other encryption algorithms are not supported.
|
260
260
|
|
261
|
+
### Compatibility note on DES and recent Node.js versions
|
262
|
+
|
263
|
+
When using SNMPv3 with DES as the privacy protocol (`snmp.PrivProtocols.des`) on Node.js v17 or later, you may encounter the following error:
|
264
|
+
|
265
|
+
```
|
266
|
+
"error": {
|
267
|
+
"library": "digital envelope routines",
|
268
|
+
"reason": "unsupported",
|
269
|
+
"code": "ERR_OSSL_EVP_UNSUPPORTED",
|
270
|
+
"message": "error:0308010C:digital envelope routines::unsupported",
|
271
|
+
"stack": ["Error: error:0308010C:digital envelope routines::unsupported",
|
272
|
+
"at Cipheriv.createCipherBase (node:internal/crypto/cipher:121:19)",
|
273
|
+
...
|
274
|
+
}
|
275
|
+
```
|
276
|
+
|
277
|
+
This occurs because newer versions of Node.js have deprecated support for the DES algorithm in OpenSSL for security reasons.
|
278
|
+
|
279
|
+
**Workaround:**
|
280
|
+
If you need to communicate with legacy devices that only support DES for SNMPv3, you can run Node.js with the `--openssl-legacy-provider` flag:
|
281
|
+
|
282
|
+
```bash
|
283
|
+
node --openssl-legacy-provider your-app.js
|
284
|
+
```
|
285
|
+
|
286
|
+
Whenever possible, it's recommended to use more secure encryption methods like AES (`snmp.PrivProtocols.aes`) instead of DES.
|
287
|
+
|
288
|
+
|
261
289
|
## snmp.AgentXPduType
|
262
290
|
|
263
291
|
The Agent Extensibility (AgentX) Protocol specifies these PDUs in RFC 2741:
|
@@ -3473,6 +3501,14 @@ Example programs are included under the module's `example` directory.
|
|
3473
3501
|
|
3474
3502
|
* Fix integer and string constraints check on cast
|
3475
3503
|
|
3504
|
+
# Version 3.20.0 - 06/03/2025
|
3505
|
+
|
3506
|
+
* Fix set value for counter, gauge and unsigned integer types
|
3507
|
+
|
3508
|
+
# Version 3.20.1 - 26/04/2025
|
3509
|
+
|
3510
|
+
* Update documentation with compatibility note on DES and recent Node.js versions
|
3511
|
+
|
3476
3512
|
# License
|
3477
3513
|
|
3478
3514
|
Copyright (c) 2020 Mark Abrahams <mark@abrahams.co.nz>
|
package/index.js
CHANGED
@@ -1,20 +1,25 @@
|
|
1
1
|
|
2
2
|
// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com>
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
const ber = require ("asn1-ber").Ber;
|
5
|
+
const smartbuffer = require ("smart-buffer");
|
6
|
+
const dgram = require ("dgram");
|
7
|
+
const net = require ("net");
|
8
|
+
const events = require ("events");
|
9
|
+
const util = require ("util");
|
10
|
+
const crypto = require ("crypto");
|
11
|
+
const mibparser = require ("./lib/mib");
|
12
|
+
const Buffer = require('buffer').Buffer;
|
13
|
+
|
12
14
|
var DEBUG = false;
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
const MIN_SIGNED_INT32 = -2147483648;
|
17
|
+
const MAX_SIGNED_INT32 = 2147483647;
|
18
|
+
const MIN_UNSIGNED_INT32 = 0;
|
19
|
+
const MAX_UNSIGNED_INT32 = 4294967295;
|
20
|
+
const MAX_UNSIGNED_INT64 = 18446744073709551615;
|
21
|
+
|
22
|
+
const DES_IMPLEMENTATION = 'library';
|
18
23
|
|
19
24
|
function debug (line) {
|
20
25
|
if ( DEBUG ) {
|
@@ -611,7 +616,7 @@ ObjectTypeUtil.castSetValue = function (type, value, constraints) {
|
|
611
616
|
}
|
612
617
|
|
613
618
|
case ObjectType.OctetString: {
|
614
|
-
if ( ! value instanceof Buffer
|
619
|
+
if ( ! ( value instanceof Buffer || typeof value == "string" ) ) {
|
615
620
|
throw new Error("Invalid OctetString", value);
|
616
621
|
}
|
617
622
|
if ( constraints && ! ObjectTypeUtil.doesStringMeetConstraints (value, constraints) ) {
|
@@ -635,19 +640,59 @@ ObjectTypeUtil.castSetValue = function (type, value, constraints) {
|
|
635
640
|
case ObjectType.Counter32:
|
636
641
|
case ObjectType.Gauge:
|
637
642
|
case ObjectType.Gauge32:
|
638
|
-
case ObjectType.Unsigned32:
|
639
|
-
case ObjectType.Counter64: {
|
643
|
+
case ObjectType.Unsigned32: {
|
640
644
|
// Counters should be initialized to 0 (RFC2578, end of section 7.9)
|
641
645
|
// We'll do so.
|
642
|
-
return 0;
|
646
|
+
// return 0;
|
647
|
+
// That ^^^ was fine when castSetValue was used only for DEFVAL
|
648
|
+
// But now it's used in other set value scenarios
|
649
|
+
// So we need to cast the given value to a whole number
|
650
|
+
const parsedValue = parseInt(value, 10);
|
651
|
+
if ( isNaN(parsedValue) ) {
|
652
|
+
throw new Error(`Invalid Integer for ${type}`, value);
|
653
|
+
}
|
654
|
+
if ( parsedValue < 0 ) {
|
655
|
+
throw new Error(`Integer is negative for ${type}`, value);
|
656
|
+
}
|
657
|
+
if ( parsedValue > MAX_UNSIGNED_INT32 ) {
|
658
|
+
throw new Error(`Integer is greater than max unsigned int32 for ${type}`, value);
|
659
|
+
}
|
660
|
+
return parsedValue;
|
661
|
+
}
|
662
|
+
|
663
|
+
case ObjectType.Counter64: {
|
664
|
+
if ( value instanceof Buffer ) {
|
665
|
+
if ( value.length !== 8 ) {
|
666
|
+
throw new Error(`Counter64 buffer is not 8 bytes`, value);
|
667
|
+
}
|
668
|
+
return value;
|
669
|
+
}
|
670
|
+
const parsedValue = parseInt(value, 10);
|
671
|
+
if ( isNaN(parsedValue) ) {
|
672
|
+
throw new Error(`Invalid Integer for Counter64`, value);
|
673
|
+
}
|
674
|
+
if ( parsedValue < 0 ) {
|
675
|
+
throw new Error(`Integer is negative for Counter64`, value);
|
676
|
+
}
|
677
|
+
if ( parsedValue > MAX_UNSIGNED_INT64 ) {
|
678
|
+
throw new Error(`Integer is greater than max unsigned int64 for Counter64`, value);
|
679
|
+
}
|
680
|
+
return parsedValue;
|
643
681
|
}
|
644
682
|
|
645
683
|
case ObjectType.IpAddress: {
|
646
|
-
|
647
|
-
|
648
|
-
if ( typeof value != "string" || bytes.length != 4 ) {
|
684
|
+
const octets = value.split (".");
|
685
|
+
if ( typeof value != "string" || octets.length != 4 ) {
|
649
686
|
throw new Error("Invalid IpAddress", value);
|
650
687
|
}
|
688
|
+
for ( const octet of octets ) {
|
689
|
+
if ( isNaN (octet) ) {
|
690
|
+
throw new Error("Invalid IpAddress", value);
|
691
|
+
}
|
692
|
+
if ( parseInt (octet) < 0 || parseInt (octet) > 255) {
|
693
|
+
throw new Error("Invalid IpAddress", value);
|
694
|
+
}
|
695
|
+
}
|
651
696
|
return value;
|
652
697
|
}
|
653
698
|
|
@@ -1337,7 +1382,6 @@ Encryption.encryptPduDes = function (scopedPdu, privProtocol, privPassword, auth
|
|
1337
1382
|
var paddedScopedPduLength;
|
1338
1383
|
var paddedScopedPdu;
|
1339
1384
|
var encryptedPdu;
|
1340
|
-
var cipher;
|
1341
1385
|
|
1342
1386
|
encryptionKey = Encryption.generateLocalizedKey (des, authProtocol, privPassword, engine.engineID);
|
1343
1387
|
privLocalizedKey = Authentication.passwordToKey (authProtocol, privPassword, engine.engineID);
|
@@ -1355,7 +1399,7 @@ Encryption.encryptPduDes = function (scopedPdu, privProtocol, privPassword, auth
|
|
1355
1399
|
for (i = 0; i < iv.length; i++) {
|
1356
1400
|
iv[i] = preIv[i] ^ salt[i];
|
1357
1401
|
}
|
1358
|
-
|
1402
|
+
|
1359
1403
|
if (scopedPdu.length % des.BLOCK_LENGTH == 0) {
|
1360
1404
|
paddedScopedPdu = scopedPdu;
|
1361
1405
|
} else {
|
@@ -1363,9 +1407,14 @@ Encryption.encryptPduDes = function (scopedPdu, privProtocol, privPassword, auth
|
|
1363
1407
|
paddedScopedPdu = Buffer.alloc (paddedScopedPduLength);
|
1364
1408
|
scopedPdu.copy (paddedScopedPdu, 0, 0, scopedPdu.length);
|
1365
1409
|
}
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1410
|
+
|
1411
|
+
if (DES_IMPLEMENTATION === 'native') {
|
1412
|
+
// TODO: Implement native encryption
|
1413
|
+
} else {
|
1414
|
+
const cipher = crypto.createCipheriv (des.CRYPTO_ALGORITHM, encryptionKey, iv);
|
1415
|
+
encryptedPdu = cipher.update (paddedScopedPdu);
|
1416
|
+
encryptedPdu = Buffer.concat ([encryptedPdu, cipher.final()]);
|
1417
|
+
}
|
1369
1418
|
// Encryption.debugEncrypt (encryptionKey, iv, paddedScopedPdu, encryptedPdu);
|
1370
1419
|
|
1371
1420
|
return {
|
@@ -1383,7 +1432,6 @@ Encryption.decryptPduDes = function (encryptedPdu, privProtocol, privParameters,
|
|
1383
1432
|
var iv;
|
1384
1433
|
var i;
|
1385
1434
|
var decryptedPdu;
|
1386
|
-
var decipher;
|
1387
1435
|
|
1388
1436
|
privLocalizedKey = Authentication.passwordToKey (authProtocol, privPassword, engine.engineID);
|
1389
1437
|
decryptionKey = Buffer.alloc (des.KEY_LENGTH);
|
@@ -1396,11 +1444,15 @@ Encryption.decryptPduDes = function (encryptedPdu, privProtocol, privParameters,
|
|
1396
1444
|
for (i = 0; i < iv.length; i++) {
|
1397
1445
|
iv[i] = preIv[i] ^ salt[i];
|
1398
1446
|
}
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1447
|
+
|
1448
|
+
if (DES_IMPLEMENTATION === 'native') {
|
1449
|
+
// TODO: Implement native decryption
|
1450
|
+
} else {
|
1451
|
+
const decipher = crypto.createDecipheriv (des.CRYPTO_ALGORITHM, decryptionKey, iv);
|
1452
|
+
decipher.setAutoPadding (false);
|
1453
|
+
decryptedPdu = decipher.update (encryptedPdu);
|
1454
|
+
decryptedPdu = Buffer.concat ([decryptedPdu, decipher.final()]);
|
1455
|
+
}
|
1404
1456
|
// Encryption.debugDecrypt (decryptionKey, iv, encryptedPdu, decryptedPdu);
|
1405
1457
|
|
1406
1458
|
return decryptedPdu;
|
@@ -1980,7 +2032,9 @@ var Session = function (target, authenticator, options) {
|
|
1980
2032
|
|
1981
2033
|
DEBUG = options.debug;
|
1982
2034
|
|
1983
|
-
this.engine = new Engine (
|
2035
|
+
this.engine = new Engine ({
|
2036
|
+
engineId: options.engineID
|
2037
|
+
});
|
1984
2038
|
this.reqs = {};
|
1985
2039
|
this.reqCount = 0;
|
1986
2040
|
|
@@ -2949,7 +3003,8 @@ Session.createV3 = function (target, user, options) {
|
|
2949
3003
|
return new Session (target, user, options);
|
2950
3004
|
};
|
2951
3005
|
|
2952
|
-
var Engine = function (
|
3006
|
+
var Engine = function (engineOptions) {
|
3007
|
+
const { engineID } = engineOptions;
|
2953
3008
|
if ( engineID ) {
|
2954
3009
|
if ( ! (engineID instanceof Buffer) ) {
|
2955
3010
|
engineID = engineID.replace('0x', '');
|
@@ -3294,7 +3349,9 @@ SimpleAccessControlModel.prototype.isAccessAllowed = function (securityModel, se
|
|
3294
3349
|
var Receiver = function (options, callback) {
|
3295
3350
|
DEBUG = options.debug;
|
3296
3351
|
this.authorizer = new Authorizer (options);
|
3297
|
-
this.engine = new Engine (
|
3352
|
+
this.engine = new Engine ({
|
3353
|
+
engineId: options.engineID
|
3354
|
+
});
|
3298
3355
|
|
3299
3356
|
this.engineBoots = 0;
|
3300
3357
|
this.engineTime = 10;
|
@@ -4809,7 +4866,9 @@ MibRequest.prototype.isTabular = function () {
|
|
4809
4866
|
var Agent = function (options, callback, mib) {
|
4810
4867
|
DEBUG = options.debug;
|
4811
4868
|
this.listener = new Listener (options, this);
|
4812
|
-
this.engine = new Engine (
|
4869
|
+
this.engine = new Engine ({
|
4870
|
+
engineId: options.engineID
|
4871
|
+
});
|
4813
4872
|
this.authorizer = new Authorizer (options);
|
4814
4873
|
this.callback = callback || function () {};
|
4815
4874
|
const mibOptions = mib?.options || options?.mibOptions || {};
|
package/lib/des-ecb.js
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
const { Buffer } = require('buffer');
|
2
|
+
|
3
|
+
// --- Lookup tables ---
|
4
|
+
const PC1 = [
|
5
|
+
57, 49, 41, 33, 25, 17, 9,
|
6
|
+
1, 58, 50, 42, 34, 26, 18,
|
7
|
+
10, 2, 59, 51, 43, 35, 27,
|
8
|
+
19, 11, 3, 60, 52, 44, 36,
|
9
|
+
63, 55, 47, 39, 31, 23, 15,
|
10
|
+
7, 62, 54, 46, 38, 30, 22,
|
11
|
+
14, 6, 61, 53, 45, 37, 29,
|
12
|
+
21, 13, 5, 28, 20, 12, 4
|
13
|
+
];
|
14
|
+
const PC2 = [
|
15
|
+
14, 17, 11, 24, 1, 5,
|
16
|
+
3, 28, 15, 6, 21, 10,
|
17
|
+
23, 19, 12, 4, 26, 8,
|
18
|
+
16, 7, 27, 20, 13, 2,
|
19
|
+
41, 52, 31, 37, 47, 55,
|
20
|
+
30, 40, 51, 45, 33, 48,
|
21
|
+
44, 49, 39, 56, 34, 53,
|
22
|
+
46, 42, 50, 36, 29, 32
|
23
|
+
];
|
24
|
+
const SHIFTS = [
|
25
|
+
1, 1, 2, 2, 2, 2, 2, 2,
|
26
|
+
1, 2, 2, 2, 2, 2, 2, 1
|
27
|
+
];
|
28
|
+
const IP = [
|
29
|
+
58, 50, 42, 34, 26, 18, 10, 2,
|
30
|
+
60, 52, 44, 36, 28, 20, 12, 4,
|
31
|
+
62, 54, 46, 38, 30, 22, 14, 6,
|
32
|
+
64, 56, 48, 40, 32, 24, 16, 8,
|
33
|
+
57, 49, 41, 33, 25, 17, 9, 1,
|
34
|
+
59, 51, 43, 35, 27, 19, 11, 3,
|
35
|
+
61, 53, 45, 37, 29, 21, 13, 5,
|
36
|
+
63, 55, 47, 39, 31, 23, 15, 7
|
37
|
+
];
|
38
|
+
const IP_INV = [
|
39
|
+
40, 8, 48, 16, 56, 24, 64, 32,
|
40
|
+
39, 7, 47, 15, 55, 23, 63, 31,
|
41
|
+
38, 6, 46, 14, 54, 22, 62, 30,
|
42
|
+
37, 5, 45, 13, 53, 21, 61, 29,
|
43
|
+
36, 4, 44, 12, 52, 20, 60, 28,
|
44
|
+
35, 3, 43, 11, 51, 19, 59, 27,
|
45
|
+
34, 2, 42, 10, 50, 18, 58, 26,
|
46
|
+
33, 1, 41, 9, 49, 17, 57, 25
|
47
|
+
];
|
48
|
+
|
49
|
+
// --- Utility functions ---
|
50
|
+
function permute(input, table) {
|
51
|
+
const output = new Array(table.length);
|
52
|
+
for (let i = 0; i < table.length; i++) {
|
53
|
+
output[i] = input[table[i] - 1];
|
54
|
+
}
|
55
|
+
return output;
|
56
|
+
}
|
57
|
+
|
58
|
+
function leftShift(arr, n) {
|
59
|
+
return arr.slice(n).concat(arr.slice(0, n));
|
60
|
+
}
|
61
|
+
|
62
|
+
function xor(a, b) {
|
63
|
+
return a.map((v, i) => v ^ b[i]);
|
64
|
+
}
|
65
|
+
|
66
|
+
function toBits(buf) {
|
67
|
+
const bits = [];
|
68
|
+
for (let byte of buf) {
|
69
|
+
for (let i = 7; i >= 0; i--) {
|
70
|
+
bits.push((byte >> i) & 1);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
return bits;
|
74
|
+
}
|
75
|
+
|
76
|
+
function fromBits(bits) {
|
77
|
+
const buf = Buffer.alloc(bits.length / 8);
|
78
|
+
for (let i = 0; i < bits.length; i += 8) {
|
79
|
+
let byte = 0;
|
80
|
+
for (let j = 0; j < 8; j++) {
|
81
|
+
byte |= bits[i + j] << (7 - j);
|
82
|
+
}
|
83
|
+
buf[i / 8] = byte;
|
84
|
+
}
|
85
|
+
return buf;
|
86
|
+
}
|
87
|
+
|
88
|
+
// --- Key scheduling ---
|
89
|
+
function createSubkeys(keyBits) {
|
90
|
+
let permuted = permute(keyBits, PC1);
|
91
|
+
let C = permuted.slice(0, 28);
|
92
|
+
let D = permuted.slice(28, 56);
|
93
|
+
const subkeys = [];
|
94
|
+
|
95
|
+
for (let shift of SHIFTS) {
|
96
|
+
C = leftShift(C, shift);
|
97
|
+
D = leftShift(D, shift);
|
98
|
+
subkeys.push(permute(C.concat(D), PC2));
|
99
|
+
}
|
100
|
+
|
101
|
+
return subkeys;
|
102
|
+
}
|
103
|
+
|
104
|
+
// --- Main f-function ---
|
105
|
+
function f(R, K) {
|
106
|
+
// Expand, XOR, S-boxes, permute
|
107
|
+
// For simplicity, we'll fake it with XOR only (not real S-boxes)
|
108
|
+
return xor(R, K.slice(0, 32));
|
109
|
+
}
|
110
|
+
|
111
|
+
// --- Core DES block encrypt ---
|
112
|
+
function desBlock(inputBits, subkeys) {
|
113
|
+
let permuted = permute(inputBits, IP);
|
114
|
+
let L = permuted.slice(0, 32);
|
115
|
+
let R = permuted.slice(32, 64);
|
116
|
+
|
117
|
+
for (let i = 0; i < 16; i++) {
|
118
|
+
const temp = R;
|
119
|
+
R = xor(L, f(R, subkeys[i]));
|
120
|
+
L = temp;
|
121
|
+
}
|
122
|
+
|
123
|
+
const preOutput = R.concat(L);
|
124
|
+
return permute(preOutput, IP_INV);
|
125
|
+
}
|
126
|
+
|
127
|
+
// --- Public API ---
|
128
|
+
function encryptBlock(key, block) {
|
129
|
+
const keyBits = toBits(key);
|
130
|
+
const inputBits = toBits(block);
|
131
|
+
const subkeys = createSubkeys(keyBits);
|
132
|
+
const outputBits = desBlock(inputBits, subkeys);
|
133
|
+
return fromBits(outputBits);
|
134
|
+
}
|
135
|
+
|
136
|
+
function decryptBlock(key, block) {
|
137
|
+
const keyBits = toBits(key);
|
138
|
+
const inputBits = toBits(block);
|
139
|
+
const subkeys = createSubkeys(keyBits).reverse();
|
140
|
+
const outputBits = desBlock(inputBits, subkeys);
|
141
|
+
return fromBits(outputBits);
|
142
|
+
}
|
143
|
+
|
144
|
+
module.exports = {
|
145
|
+
encryptBlock,
|
146
|
+
decryptBlock,
|
147
|
+
};
|
package/lib/des.js
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
const { Buffer } = require('buffer');
|
2
|
+
const des = require('./des-ecb');
|
3
|
+
|
4
|
+
// --- CBC Mode wrapper ---
|
5
|
+
function encrypt(key, iv, plaintext) {
|
6
|
+
if (plaintext.length % 8 !== 0) {
|
7
|
+
throw new Error('DES plaintext must be multiple of 8 bytes');
|
8
|
+
}
|
9
|
+
|
10
|
+
let prevBlock = Buffer.from(iv);
|
11
|
+
let out = Buffer.alloc(plaintext.length);
|
12
|
+
|
13
|
+
for (let i = 0; i < plaintext.length; i += 8) {
|
14
|
+
const block = Buffer.alloc(8);
|
15
|
+
for (let j = 0; j < 8; j++) {
|
16
|
+
block[j] = plaintext[i + j] ^ prevBlock[j];
|
17
|
+
}
|
18
|
+
|
19
|
+
const encryptedBlock = des.encryptBlock(key, block);
|
20
|
+
|
21
|
+
encryptedBlock.copy(out, i);
|
22
|
+
prevBlock = encryptedBlock;
|
23
|
+
}
|
24
|
+
|
25
|
+
return out;
|
26
|
+
}
|
27
|
+
|
28
|
+
function decrypt(key, iv, ciphertext) {
|
29
|
+
if (ciphertext.length % 8 !== 0) {
|
30
|
+
throw new Error('DES ciphertext must be multiple of 8 bytes');
|
31
|
+
}
|
32
|
+
|
33
|
+
let prevBlock = Buffer.from(iv);
|
34
|
+
let out = Buffer.alloc(ciphertext.length);
|
35
|
+
|
36
|
+
for (let i = 0; i < ciphertext.length; i += 8) {
|
37
|
+
const block = ciphertext.slice(i, i + 8);
|
38
|
+
const decryptedBlock = des.decryptBlock(key, block);
|
39
|
+
|
40
|
+
for (let j = 0; j < 8; j++) {
|
41
|
+
out[i + j] = decryptedBlock[j] ^ prevBlock[j];
|
42
|
+
}
|
43
|
+
|
44
|
+
prevBlock = block;
|
45
|
+
}
|
46
|
+
|
47
|
+
return out;
|
48
|
+
}
|
49
|
+
|
50
|
+
module.exports = {
|
51
|
+
encrypt,
|
52
|
+
decrypt,
|
53
|
+
};
|
package/package.json
CHANGED
@@ -0,0 +1,200 @@
|
|
1
|
+
const assert = require('assert');
|
2
|
+
const snmp = require('..');
|
3
|
+
|
4
|
+
describe('Cast Set Value', function() {
|
5
|
+
|
6
|
+
describe('Boolean', function() {
|
7
|
+
it('casts truthy values to true', function() {
|
8
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, 1), true);
|
9
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, "true"), true);
|
10
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, {}), true);
|
11
|
+
});
|
12
|
+
|
13
|
+
it('casts falsy values to false', function() {
|
14
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, 0), false);
|
15
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, ""), false);
|
16
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Boolean, null), false);
|
17
|
+
});
|
18
|
+
});
|
19
|
+
|
20
|
+
describe('Integer', function() {
|
21
|
+
it('accepts valid integers', function() {
|
22
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, 42), 42);
|
23
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, -42), -42);
|
24
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, "42"), 42);
|
25
|
+
});
|
26
|
+
|
27
|
+
it('throws on invalid integers', function() {
|
28
|
+
assert.throws(() => {
|
29
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, "not a number");
|
30
|
+
}, /Invalid Integer/);
|
31
|
+
|
32
|
+
assert.throws(() => {
|
33
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, {});
|
34
|
+
}, /Invalid Integer/);
|
35
|
+
});
|
36
|
+
|
37
|
+
it('respects enumeration constraints', function() {
|
38
|
+
const constraints = {
|
39
|
+
enumeration: {
|
40
|
+
1: 'one',
|
41
|
+
2: 'two'
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, 1, constraints), 1);
|
46
|
+
|
47
|
+
assert.throws(() => {
|
48
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, 3, constraints);
|
49
|
+
}, /Integer does not meet constraints/);
|
50
|
+
});
|
51
|
+
|
52
|
+
it('respects range constraints', function() {
|
53
|
+
const constraints = {
|
54
|
+
ranges: [
|
55
|
+
{ min: 0, max: 10 }
|
56
|
+
]
|
57
|
+
};
|
58
|
+
|
59
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, 5, constraints), 5);
|
60
|
+
|
61
|
+
assert.throws(() => {
|
62
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Integer, 11, constraints);
|
63
|
+
}, /Integer does not meet constraints/);
|
64
|
+
});
|
65
|
+
});
|
66
|
+
|
67
|
+
describe('OctetString', function() {
|
68
|
+
it('accepts strings', function() {
|
69
|
+
assert.strictEqual(
|
70
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OctetString, "test string"),
|
71
|
+
"test string"
|
72
|
+
);
|
73
|
+
});
|
74
|
+
|
75
|
+
it('converts buffers to strings', function() {
|
76
|
+
const buf = Buffer.from("test buffer");
|
77
|
+
assert.strictEqual(
|
78
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OctetString, buf),
|
79
|
+
buf.toString()
|
80
|
+
);
|
81
|
+
});
|
82
|
+
|
83
|
+
it('throws on invalid types', function() {
|
84
|
+
assert.throws(() => {
|
85
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OctetString, 123);
|
86
|
+
}, /Invalid OctetString/);
|
87
|
+
});
|
88
|
+
|
89
|
+
it('respects size constraints', function() {
|
90
|
+
const constraints = {
|
91
|
+
sizes: [
|
92
|
+
{ min: 2, max: 5 }
|
93
|
+
]
|
94
|
+
};
|
95
|
+
|
96
|
+
assert.strictEqual(
|
97
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OctetString, "123", constraints),
|
98
|
+
"123"
|
99
|
+
);
|
100
|
+
|
101
|
+
assert.throws(() => {
|
102
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OctetString, "too long", constraints);
|
103
|
+
}, /OctetString does not meet constraints/);
|
104
|
+
});
|
105
|
+
});
|
106
|
+
|
107
|
+
describe('OID', function() {
|
108
|
+
it('accepts valid OIDs', function() {
|
109
|
+
assert.strictEqual(
|
110
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OID, "1.3.6.1.2.1"),
|
111
|
+
"1.3.6.1.2.1"
|
112
|
+
);
|
113
|
+
});
|
114
|
+
|
115
|
+
it('throws on invalid OIDs', function() {
|
116
|
+
assert.throws(() => {
|
117
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OID, "not.an.oid");
|
118
|
+
}, /Invalid OID/);
|
119
|
+
|
120
|
+
assert.throws(() => {
|
121
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.OID, "1.2.3.");
|
122
|
+
}, /Invalid OID/);
|
123
|
+
});
|
124
|
+
});
|
125
|
+
|
126
|
+
describe('Counter/Gauge/Unsigned32', function() {
|
127
|
+
const types = [
|
128
|
+
snmp.ObjectType.Counter,
|
129
|
+
snmp.ObjectType.Counter32,
|
130
|
+
snmp.ObjectType.Gauge,
|
131
|
+
snmp.ObjectType.Gauge32,
|
132
|
+
snmp.ObjectType.Unsigned32
|
133
|
+
];
|
134
|
+
|
135
|
+
types.forEach(type => {
|
136
|
+
it(`accepts valid unsigned integers for ${type}`, function() {
|
137
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(type, 42), 42);
|
138
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(type, "42"), 42);
|
139
|
+
});
|
140
|
+
|
141
|
+
it(`throws on negative numbers for ${type}`, function() {
|
142
|
+
assert.throws(() => {
|
143
|
+
snmp.ObjectTypeUtil.castSetValue(type, -1);
|
144
|
+
}, /Integer is negative/);
|
145
|
+
});
|
146
|
+
|
147
|
+
it(`throws on values exceeding unsigned 32-bit max for ${type}`, function() {
|
148
|
+
assert.throws(() => {
|
149
|
+
snmp.ObjectTypeUtil.castSetValue(type, 4294967296); // MAX_UNSIGNED_INT32 + 1
|
150
|
+
}, /Integer is greater than max unsigned int32/);
|
151
|
+
});
|
152
|
+
});
|
153
|
+
});
|
154
|
+
|
155
|
+
describe('Counter64', function() {
|
156
|
+
it('accepts valid unsigned integers', function() {
|
157
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Counter64, 42), 42);
|
158
|
+
assert.strictEqual(snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Counter64, "42"), 42);
|
159
|
+
});
|
160
|
+
|
161
|
+
it('accepts valid 8-byte buffers', function() {
|
162
|
+
const buf = Buffer.alloc(8);
|
163
|
+
assert.strictEqual(
|
164
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Counter64, buf),
|
165
|
+
buf
|
166
|
+
);
|
167
|
+
});
|
168
|
+
|
169
|
+
it('throws on invalid buffer length', function() {
|
170
|
+
assert.throws(() => {
|
171
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Counter64, Buffer.alloc(7));
|
172
|
+
}, /Counter64 buffer is not 8 bytes/);
|
173
|
+
});
|
174
|
+
|
175
|
+
it('throws on negative numbers', function() {
|
176
|
+
assert.throws(() => {
|
177
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.Counter64, -1);
|
178
|
+
}, /Integer is negative for Counter64/);
|
179
|
+
});
|
180
|
+
});
|
181
|
+
|
182
|
+
describe('IpAddress', function() {
|
183
|
+
it('accepts valid IP addresses', function() {
|
184
|
+
assert.strictEqual(
|
185
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.IpAddress, "192.168.1.1"),
|
186
|
+
"192.168.1.1"
|
187
|
+
);
|
188
|
+
});
|
189
|
+
|
190
|
+
it('throws on invalid IP addresses', function() {
|
191
|
+
assert.throws(() => {
|
192
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.IpAddress, "not.an.ip.address");
|
193
|
+
}, /Invalid IpAddress/);
|
194
|
+
|
195
|
+
assert.throws(() => {
|
196
|
+
snmp.ObjectTypeUtil.castSetValue(snmp.ObjectType.IpAddress, "192.168.1");
|
197
|
+
}, /Invalid IpAddress/);
|
198
|
+
});
|
199
|
+
});
|
200
|
+
});
|