node-opcua-chunkmanager 2.128.0 → 2.129.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/dist/chunk_manager.d.ts +21 -34
- package/dist/chunk_manager.js +163 -132
- package/dist/chunk_manager.js.map +1 -1
- package/dist/read_message_header.js +3 -4
- package/dist/read_message_header.js.map +1 -1
- package/package.json +2 -2
- package/source/chunk_manager.ts +111 -87
- package/source/read_message_header.ts +3 -5
package/dist/chunk_manager.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
1
3
|
/***
|
|
2
4
|
* @module node-opcua-chunkmanager
|
|
3
5
|
*/
|
|
4
6
|
import { EventEmitter } from "events";
|
|
5
7
|
export declare function verify_message_chunk(messageChunk: Buffer): void;
|
|
6
|
-
export type WriteHeaderFunc = (chunk: Buffer, isLast: boolean, expectedLength: number) => void;
|
|
7
|
-
export type WriteSequenceHeaderFunc = (chunk: Buffer) => void;
|
|
8
|
-
export type SignBufferFunc = (buffer: Buffer) => Buffer;
|
|
9
|
-
export type EncryptBufferFunc = (buffer: Buffer) => Buffer;
|
|
8
|
+
export type WriteHeaderFunc = (this: ChunkManager, chunk: Buffer, isLast: boolean, expectedLength: number) => void;
|
|
9
|
+
export type WriteSequenceHeaderFunc = (this: ChunkManager, chunk: Buffer) => void;
|
|
10
|
+
export type SignBufferFunc = (this: ChunkManager, buffer: Buffer) => Buffer;
|
|
11
|
+
export type EncryptBufferFunc = (this: ChunkManager, buffer: Buffer) => Buffer;
|
|
10
12
|
export interface IChunkManagerOptions {
|
|
11
13
|
chunkSize: number;
|
|
12
14
|
signatureLength: number;
|
|
@@ -19,41 +21,26 @@ export interface IChunkManagerOptions {
|
|
|
19
21
|
headerSize: number;
|
|
20
22
|
writeHeaderFunc?: WriteHeaderFunc;
|
|
21
23
|
}
|
|
24
|
+
export declare enum Mode {
|
|
25
|
+
None = 1,
|
|
26
|
+
Sign = 2,
|
|
27
|
+
SignAndEncrypt = 3
|
|
28
|
+
}
|
|
22
29
|
export declare class ChunkManager extends EventEmitter {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
private readonly maxBodySize;
|
|
34
|
-
private readonly maxBlock?;
|
|
35
|
-
private readonly dataOffset;
|
|
36
|
-
private chunk;
|
|
37
|
-
private cursor;
|
|
38
|
-
private pendingChunk;
|
|
39
|
-
private dataEnd;
|
|
40
|
-
constructor(options: IChunkManagerOptions);
|
|
30
|
+
#private;
|
|
31
|
+
readonly chunkSize: number;
|
|
32
|
+
readonly headerSize: number;
|
|
33
|
+
readonly maxBodySize: number;
|
|
34
|
+
readonly signatureLength: number;
|
|
35
|
+
readonly sequenceHeaderSize: number;
|
|
36
|
+
readonly cipherBlockSize: number;
|
|
37
|
+
readonly plainBlockSize: number;
|
|
38
|
+
readonly securityMode: Mode;
|
|
39
|
+
constructor(securityMode: Mode, options: IChunkManagerOptions);
|
|
41
40
|
evaluateTotalLengthAndChunks(bodySize: number): {
|
|
42
41
|
totalLength: number;
|
|
43
42
|
chunkCount: number;
|
|
44
43
|
};
|
|
45
44
|
write(buffer: Buffer, length?: number): void;
|
|
46
45
|
end(): void;
|
|
47
|
-
/**
|
|
48
|
-
* compute the signature of the chunk and append it at the end
|
|
49
|
-
* of the data block.
|
|
50
|
-
*
|
|
51
|
-
* @method _write_signature
|
|
52
|
-
* @private
|
|
53
|
-
*/
|
|
54
|
-
private _write_signature;
|
|
55
|
-
private _encrypt;
|
|
56
|
-
private _push_pending_chunk;
|
|
57
|
-
private _write_padding_bytes;
|
|
58
|
-
private _post_process_current_chunk;
|
|
59
46
|
}
|
package/dist/chunk_manager.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _ChunkManager_instances, _ChunkManager_signBufferFunc, _ChunkManager_encryptBufferFunc, _ChunkManager_writeSequenceHeaderFunc, _ChunkManager_writeHeaderFunc, _ChunkManager_maxBlock, _ChunkManager_dataOffset, _ChunkManager_chunk, _ChunkManager_cursor, _ChunkManager_pendingChunk, _ChunkManager_dataEnd, _ChunkManager__write_signature, _ChunkManager__encrypt, _ChunkManager__push_pending_chunk, _ChunkManager__write_padding_bytes, _ChunkManager__post_process_current_chunk;
|
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ChunkManager = void 0;
|
|
4
|
-
exports.verify_message_chunk = verify_message_chunk;
|
|
15
|
+
exports.ChunkManager = exports.Mode = exports.verify_message_chunk = void 0;
|
|
5
16
|
/***
|
|
6
17
|
* @module node-opcua-chunkmanager
|
|
7
18
|
*/
|
|
@@ -18,57 +29,80 @@ function verify_message_chunk(messageChunk) {
|
|
|
18
29
|
throw new Error(" chunk length = " + messageChunk.length + " message length " + header.length);
|
|
19
30
|
}
|
|
20
31
|
}
|
|
32
|
+
exports.verify_message_chunk = verify_message_chunk;
|
|
33
|
+
var Mode;
|
|
34
|
+
(function (Mode) {
|
|
35
|
+
Mode[Mode["None"] = 1] = "None";
|
|
36
|
+
Mode[Mode["Sign"] = 2] = "Sign";
|
|
37
|
+
Mode[Mode["SignAndEncrypt"] = 3] = "SignAndEncrypt";
|
|
38
|
+
})(Mode || (exports.Mode = Mode = {}));
|
|
21
39
|
class ChunkManager extends events_1.EventEmitter {
|
|
22
|
-
constructor(options) {
|
|
40
|
+
constructor(securityMode, options) {
|
|
23
41
|
super();
|
|
42
|
+
_ChunkManager_instances.add(this);
|
|
43
|
+
_ChunkManager_signBufferFunc.set(this, void 0);
|
|
44
|
+
_ChunkManager_encryptBufferFunc.set(this, void 0);
|
|
45
|
+
_ChunkManager_writeSequenceHeaderFunc.set(this, void 0);
|
|
46
|
+
_ChunkManager_writeHeaderFunc.set(this, void 0);
|
|
47
|
+
// --------------
|
|
48
|
+
_ChunkManager_maxBlock.set(this, void 0);
|
|
49
|
+
_ChunkManager_dataOffset.set(this, void 0);
|
|
50
|
+
_ChunkManager_chunk.set(this, void 0);
|
|
51
|
+
_ChunkManager_cursor.set(this, void 0);
|
|
52
|
+
_ChunkManager_pendingChunk.set(this, void 0);
|
|
53
|
+
_ChunkManager_dataEnd.set(this, void 0);
|
|
54
|
+
this.securityMode = securityMode;
|
|
24
55
|
// { chunkSize : 32, headerSize : 10 ,signatureLength: 32 }
|
|
25
56
|
this.chunkSize = options.chunkSize;
|
|
26
57
|
this.headerSize = options.headerSize || 0;
|
|
27
58
|
if (this.headerSize) {
|
|
28
|
-
this
|
|
29
|
-
(0, node_opcua_assert_1.assert)(typeof this
|
|
59
|
+
__classPrivateFieldSet(this, _ChunkManager_writeHeaderFunc, options.writeHeaderFunc, "f");
|
|
60
|
+
(0, node_opcua_assert_1.assert)(typeof __classPrivateFieldGet(this, _ChunkManager_writeHeaderFunc, "f") === "function");
|
|
30
61
|
}
|
|
31
62
|
this.sequenceHeaderSize = options.sequenceHeaderSize === undefined ? 8 : options.sequenceHeaderSize;
|
|
32
63
|
if (this.sequenceHeaderSize > 0) {
|
|
33
|
-
this
|
|
34
|
-
(0, node_opcua_assert_1.assert)(typeof this
|
|
64
|
+
__classPrivateFieldSet(this, _ChunkManager_writeSequenceHeaderFunc, options.writeSequenceHeaderFunc, "f");
|
|
65
|
+
(0, node_opcua_assert_1.assert)(typeof __classPrivateFieldGet(this, _ChunkManager_writeSequenceHeaderFunc, "f") === "function");
|
|
35
66
|
}
|
|
36
67
|
this.signatureLength = options.signatureLength || 0;
|
|
37
|
-
this
|
|
68
|
+
__classPrivateFieldSet(this, _ChunkManager_signBufferFunc, options.signBufferFunc, "f");
|
|
38
69
|
this.plainBlockSize = options.plainBlockSize || 0; // 256-14;
|
|
39
70
|
this.cipherBlockSize = options.cipherBlockSize || 0; // 256;
|
|
40
|
-
this
|
|
71
|
+
__classPrivateFieldSet(this, _ChunkManager_dataEnd, 0, "f");
|
|
41
72
|
if (this.cipherBlockSize === 0) {
|
|
73
|
+
(0, node_opcua_assert_1.assert)(securityMode === Mode.None || securityMode === Mode.Sign);
|
|
74
|
+
// we don't encrypt,we just sign
|
|
42
75
|
(0, node_opcua_assert_1.assert)(this.plainBlockSize === 0);
|
|
43
76
|
// unencrypted block
|
|
44
77
|
this.maxBodySize = this.chunkSize - this.headerSize - this.signatureLength - this.sequenceHeaderSize;
|
|
45
|
-
this
|
|
78
|
+
__classPrivateFieldSet(this, _ChunkManager_encryptBufferFunc, undefined, "f");
|
|
46
79
|
}
|
|
47
80
|
else {
|
|
81
|
+
(0, node_opcua_assert_1.assert)(securityMode === Mode.SignAndEncrypt || securityMode === Mode.Sign);
|
|
48
82
|
(0, node_opcua_assert_1.assert)(this.plainBlockSize !== 0);
|
|
49
83
|
// During encryption a block with a size equal to PlainTextBlockSize is processed to produce a block
|
|
50
84
|
// with size equal to CipherTextBlockSize. These values depend on the encryption algorithm and may
|
|
51
85
|
// be the same.
|
|
52
|
-
this
|
|
53
|
-
(0, node_opcua_assert_1.assert)(typeof this
|
|
86
|
+
__classPrivateFieldSet(this, _ChunkManager_encryptBufferFunc, options.encryptBufferFunc, "f");
|
|
87
|
+
(0, node_opcua_assert_1.assert)(typeof __classPrivateFieldGet(this, _ChunkManager_encryptBufferFunc, "f") === "function", "an encryptBufferFunc is required");
|
|
54
88
|
// this is the formula proposed by OPCUA
|
|
55
89
|
this.maxBodySize =
|
|
56
90
|
this.plainBlockSize *
|
|
57
91
|
Math.floor((this.chunkSize - this.headerSize - this.signatureLength - 1) / this.cipherBlockSize) -
|
|
58
92
|
this.sequenceHeaderSize;
|
|
59
93
|
// this is the formula proposed by ERN
|
|
60
|
-
this
|
|
61
|
-
this.maxBodySize = this.plainBlockSize * this
|
|
94
|
+
__classPrivateFieldSet(this, _ChunkManager_maxBlock, Math.floor((this.chunkSize - this.headerSize) / this.cipherBlockSize), "f");
|
|
95
|
+
this.maxBodySize = this.plainBlockSize * __classPrivateFieldGet(this, _ChunkManager_maxBlock, "f") - this.sequenceHeaderSize - this.signatureLength - 1;
|
|
62
96
|
if (this.plainBlockSize > 256) {
|
|
63
97
|
this.maxBodySize -= 1;
|
|
64
98
|
}
|
|
65
99
|
}
|
|
66
100
|
(0, node_opcua_assert_1.assert)(this.maxBodySize > 0); // no space left to write data
|
|
67
101
|
// where the data starts in the block
|
|
68
|
-
this
|
|
69
|
-
this
|
|
70
|
-
this
|
|
71
|
-
this
|
|
102
|
+
__classPrivateFieldSet(this, _ChunkManager_dataOffset, this.headerSize + this.sequenceHeaderSize, "f");
|
|
103
|
+
__classPrivateFieldSet(this, _ChunkManager_chunk, null, "f");
|
|
104
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, 0, "f");
|
|
105
|
+
__classPrivateFieldSet(this, _ChunkManager_pendingChunk, null, "f");
|
|
72
106
|
}
|
|
73
107
|
evaluateTotalLengthAndChunks(bodySize) {
|
|
74
108
|
const chunkCount = Math.ceil(bodySize / this.maxBodySize);
|
|
@@ -83,140 +117,137 @@ class ChunkManager extends events_1.EventEmitter {
|
|
|
83
117
|
let inputCursor = 0;
|
|
84
118
|
while (l > 0) {
|
|
85
119
|
(0, node_opcua_assert_1.assert)(length - inputCursor !== 0);
|
|
86
|
-
if (this
|
|
87
|
-
this.
|
|
120
|
+
if (__classPrivateFieldGet(this, _ChunkManager_cursor, "f") === 0) {
|
|
121
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__push_pending_chunk).call(this, false);
|
|
88
122
|
}
|
|
89
123
|
// space left in current chunk
|
|
90
|
-
const spaceLeft = this.maxBodySize - this
|
|
124
|
+
const spaceLeft = this.maxBodySize - __classPrivateFieldGet(this, _ChunkManager_cursor, "f");
|
|
91
125
|
const nbToWrite = Math.min(length - inputCursor, spaceLeft);
|
|
92
|
-
this
|
|
126
|
+
__classPrivateFieldSet(this, _ChunkManager_chunk, __classPrivateFieldGet(this, _ChunkManager_chunk, "f") || (0, node_opcua_buffer_utils_1.createFastUninitializedBuffer)(this.chunkSize), "f");
|
|
93
127
|
if (buffer) {
|
|
94
|
-
buffer.copy(this
|
|
128
|
+
buffer.copy(__classPrivateFieldGet(this, _ChunkManager_chunk, "f"), __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + __classPrivateFieldGet(this, _ChunkManager_dataOffset, "f"), inputCursor, inputCursor + nbToWrite);
|
|
95
129
|
}
|
|
96
130
|
inputCursor += nbToWrite;
|
|
97
|
-
this
|
|
98
|
-
if (this
|
|
99
|
-
this.
|
|
131
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + nbToWrite, "f");
|
|
132
|
+
if (__classPrivateFieldGet(this, _ChunkManager_cursor, "f") >= this.maxBodySize) {
|
|
133
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__post_process_current_chunk).call(this);
|
|
100
134
|
}
|
|
101
135
|
l -= nbToWrite;
|
|
102
136
|
}
|
|
103
137
|
}
|
|
104
138
|
end() {
|
|
105
|
-
if (this
|
|
106
|
-
this.
|
|
139
|
+
if (__classPrivateFieldGet(this, _ChunkManager_cursor, "f") > 0) {
|
|
140
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__post_process_current_chunk).call(this);
|
|
107
141
|
}
|
|
108
|
-
this.
|
|
142
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__push_pending_chunk).call(this, true);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.ChunkManager = ChunkManager;
|
|
146
|
+
_ChunkManager_signBufferFunc = new WeakMap(), _ChunkManager_encryptBufferFunc = new WeakMap(), _ChunkManager_writeSequenceHeaderFunc = new WeakMap(), _ChunkManager_writeHeaderFunc = new WeakMap(), _ChunkManager_maxBlock = new WeakMap(), _ChunkManager_dataOffset = new WeakMap(), _ChunkManager_chunk = new WeakMap(), _ChunkManager_cursor = new WeakMap(), _ChunkManager_pendingChunk = new WeakMap(), _ChunkManager_dataEnd = new WeakMap(), _ChunkManager_instances = new WeakSet(), _ChunkManager__write_signature = function _ChunkManager__write_signature(chunk) {
|
|
147
|
+
if (this.securityMode === Mode.None) {
|
|
148
|
+
(0, node_opcua_assert_1.assert)(this.signatureLength === 0, "expecting NO SIGN");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (__classPrivateFieldGet(this, _ChunkManager_signBufferFunc, "f")) {
|
|
152
|
+
(0, node_opcua_assert_1.assert)(typeof __classPrivateFieldGet(this, _ChunkManager_signBufferFunc, "f") === "function");
|
|
153
|
+
(0, node_opcua_assert_1.assert)(this.signatureLength !== 0);
|
|
154
|
+
const signatureStart = __classPrivateFieldGet(this, _ChunkManager_dataEnd, "f");
|
|
155
|
+
const sectionToSign = chunk.subarray(0, signatureStart);
|
|
156
|
+
const signature = __classPrivateFieldGet(this, _ChunkManager_signBufferFunc, "f").call(this, sectionToSign);
|
|
157
|
+
(0, node_opcua_assert_1.assert)(signature.length === this.signatureLength, "expecting signature length to match");
|
|
158
|
+
signature.copy(chunk, signatureStart);
|
|
109
159
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
160
|
+
else {
|
|
161
|
+
(0, node_opcua_assert_1.assert)(this.signatureLength === 0, "expecting NO SIGN");
|
|
162
|
+
}
|
|
163
|
+
}, _ChunkManager__encrypt = function _ChunkManager__encrypt(chunk) {
|
|
164
|
+
if (this.securityMode === Mode.None) {
|
|
165
|
+
// nothing todo
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (this.plainBlockSize > 0 && __classPrivateFieldGet(this, _ChunkManager_encryptBufferFunc, "f")) {
|
|
169
|
+
(0, node_opcua_assert_1.assert)(__classPrivateFieldGet(this, _ChunkManager_dataEnd, "f") !== undefined);
|
|
170
|
+
const startEncryptionPos = this.headerSize;
|
|
171
|
+
const endEncryptionPos = __classPrivateFieldGet(this, _ChunkManager_dataEnd, "f") + this.signatureLength;
|
|
172
|
+
const areaToEncrypt = chunk.subarray(startEncryptionPos, endEncryptionPos);
|
|
173
|
+
(0, node_opcua_assert_1.assert)(areaToEncrypt.length % this.plainBlockSize === 0); // padding should have been applied
|
|
174
|
+
const nbBlock = areaToEncrypt.length / this.plainBlockSize;
|
|
175
|
+
const encryptedBuffer = __classPrivateFieldGet(this, _ChunkManager_encryptBufferFunc, "f").call(this, areaToEncrypt);
|
|
176
|
+
(0, node_opcua_assert_1.assert)(encryptedBuffer.length % this.cipherBlockSize === 0);
|
|
177
|
+
(0, node_opcua_assert_1.assert)(encryptedBuffer.length === nbBlock * this.cipherBlockSize);
|
|
178
|
+
encryptedBuffer.copy(chunk, this.headerSize, 0);
|
|
179
|
+
}
|
|
180
|
+
}, _ChunkManager__push_pending_chunk = function _ChunkManager__push_pending_chunk(isLast) {
|
|
181
|
+
if (__classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f")) {
|
|
182
|
+
const expectedLength = __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f").length;
|
|
183
|
+
if (this.headerSize > 0) {
|
|
184
|
+
// Release 1.02 39 OPC Unified Architecture, Part 6:
|
|
185
|
+
// The sequence header ensures that the first encrypted block of every Message sent over
|
|
186
|
+
// a channel will start with different data.
|
|
187
|
+
__classPrivateFieldGet(this, _ChunkManager_writeHeaderFunc, "f").call(this, __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f").subarray(0, this.headerSize), isLast, expectedLength);
|
|
126
188
|
}
|
|
127
|
-
|
|
128
|
-
(
|
|
189
|
+
if (this.sequenceHeaderSize > 0) {
|
|
190
|
+
__classPrivateFieldGet(this, _ChunkManager_writeSequenceHeaderFunc, "f").call(this, __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f").subarray(this.headerSize, this.headerSize + this.sequenceHeaderSize));
|
|
129
191
|
}
|
|
192
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__write_signature).call(this, __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f"));
|
|
193
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__encrypt).call(this, __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f"));
|
|
194
|
+
/**
|
|
195
|
+
* @event chunk
|
|
196
|
+
* @param chunk {Buffer}
|
|
197
|
+
* @param isLast {Boolean} , true if final chunk
|
|
198
|
+
*/
|
|
199
|
+
this.emit("chunk", __classPrivateFieldGet(this, _ChunkManager_pendingChunk, "f"), isLast);
|
|
200
|
+
__classPrivateFieldSet(this, _ChunkManager_pendingChunk, null, "f");
|
|
130
201
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
(0, node_opcua_assert_1.assert)(encryptedBuffer.length % this.cipherBlockSize === 0);
|
|
141
|
-
(0, node_opcua_assert_1.assert)(encryptedBuffer.length === nbBlock * this.cipherBlockSize);
|
|
142
|
-
encryptedBuffer.copy(chunk, this.headerSize, 0);
|
|
143
|
-
}
|
|
202
|
+
}, _ChunkManager__write_padding_bytes = function _ChunkManager__write_padding_bytes(nbPaddingByteTotal) {
|
|
203
|
+
const nbPaddingByte = nbPaddingByteTotal % 256;
|
|
204
|
+
const extraNbPaddingByte = Math.floor(nbPaddingByteTotal / 256);
|
|
205
|
+
(0, node_opcua_assert_1.assert)(extraNbPaddingByte === 0 || this.plainBlockSize > 256, "extraNbPaddingByte only requested when key size > 2048");
|
|
206
|
+
// write the padding byte
|
|
207
|
+
__classPrivateFieldGet(this, _ChunkManager_chunk, "f").writeUInt8(nbPaddingByte, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + __classPrivateFieldGet(this, _ChunkManager_dataOffset, "f"));
|
|
208
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + 1, "f");
|
|
209
|
+
for (let i = 0; i < nbPaddingByteTotal; i++) {
|
|
210
|
+
__classPrivateFieldGet(this, _ChunkManager_chunk, "f").writeUInt8(nbPaddingByte, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + __classPrivateFieldGet(this, _ChunkManager_dataOffset, "f") + i);
|
|
144
211
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// Release 1.02 39 OPC Unified Architecture, Part 6:
|
|
150
|
-
// The sequence header ensures that the first encrypted block of every Message sent over
|
|
151
|
-
// a channel will start with different data.
|
|
152
|
-
this.writeHeaderFunc(this.pendingChunk.subarray(0, this.headerSize), isLast, expectedLength);
|
|
153
|
-
}
|
|
154
|
-
if (this.sequenceHeaderSize > 0) {
|
|
155
|
-
this.writeSequenceHeaderFunc(this.pendingChunk.subarray(this.headerSize, this.headerSize + this.sequenceHeaderSize));
|
|
156
|
-
}
|
|
157
|
-
this._write_signature(this.pendingChunk);
|
|
158
|
-
this._encrypt(this.pendingChunk);
|
|
159
|
-
/**
|
|
160
|
-
* @event chunk
|
|
161
|
-
* @param chunk {Buffer}
|
|
162
|
-
* @param isLast {Boolean} , true if final chunk
|
|
163
|
-
*/
|
|
164
|
-
this.emit("chunk", this.pendingChunk, isLast);
|
|
165
|
-
this.pendingChunk = null;
|
|
166
|
-
}
|
|
212
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + nbPaddingByteTotal, "f");
|
|
213
|
+
if (this.plainBlockSize > 256) {
|
|
214
|
+
__classPrivateFieldGet(this, _ChunkManager_chunk, "f").writeUInt8(extraNbPaddingByte, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + __classPrivateFieldGet(this, _ChunkManager_dataOffset, "f"));
|
|
215
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + 1, "f");
|
|
167
216
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// write
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
this.cursor += nbPaddingByteTotal;
|
|
217
|
+
}, _ChunkManager__post_process_current_chunk = function _ChunkManager__post_process_current_chunk() {
|
|
218
|
+
let extraEncryptionBytes = 0;
|
|
219
|
+
// add padding bytes if needed
|
|
220
|
+
if (this.plainBlockSize > 0) {
|
|
221
|
+
// write padding ( if encryption )
|
|
222
|
+
// let's calculate curLength = the length of the block to encrypt without padding yet
|
|
223
|
+
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
224
|
+
// |SequenceHeader | data | paddingByte | padding | extraPadding | signature |
|
|
225
|
+
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
226
|
+
let curLength = this.sequenceHeaderSize + __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + this.signatureLength;
|
|
179
227
|
if (this.plainBlockSize > 256) {
|
|
180
|
-
|
|
181
|
-
this.cursor += 1;
|
|
228
|
+
curLength += 2; // account for extraPadding Byte Number;
|
|
182
229
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
let extraEncryptionBytes = 0;
|
|
186
|
-
// add padding bytes if needed
|
|
187
|
-
if (this.plainBlockSize > 0) {
|
|
188
|
-
// write padding ( if encryption )
|
|
189
|
-
// let's calculate curLength = the length of the block to encrypt without padding yet
|
|
190
|
-
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
191
|
-
// |SequenceHeader | data | paddingByte | padding | extraPadding | signature |
|
|
192
|
-
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
193
|
-
let curLength = this.sequenceHeaderSize + this.cursor + this.signatureLength;
|
|
194
|
-
if (this.plainBlockSize > 256) {
|
|
195
|
-
curLength += 2; // account for extraPadding Byte Number;
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
curLength += 1;
|
|
199
|
-
}
|
|
200
|
-
// let's calculate the required number of padding bytes
|
|
201
|
-
const n = curLength % this.plainBlockSize;
|
|
202
|
-
const nbPaddingByteTotal = (this.plainBlockSize - n) % this.plainBlockSize;
|
|
203
|
-
this._write_padding_bytes(nbPaddingByteTotal);
|
|
204
|
-
const adjustedLength = this.sequenceHeaderSize + this.cursor + this.signatureLength;
|
|
205
|
-
(0, node_opcua_assert_1.assert)(adjustedLength % this.plainBlockSize === 0);
|
|
206
|
-
const nbBlock = adjustedLength / this.plainBlockSize;
|
|
207
|
-
extraEncryptionBytes = nbBlock * (this.cipherBlockSize - this.plainBlockSize);
|
|
230
|
+
else {
|
|
231
|
+
curLength += 1;
|
|
208
232
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
this
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.chunk = null;
|
|
218
|
-
this.cursor = 0;
|
|
233
|
+
// let's calculate the required number of padding bytes
|
|
234
|
+
const n = curLength % this.plainBlockSize;
|
|
235
|
+
const nbPaddingByteTotal = (this.plainBlockSize - n) % this.plainBlockSize;
|
|
236
|
+
__classPrivateFieldGet(this, _ChunkManager_instances, "m", _ChunkManager__write_padding_bytes).call(this, nbPaddingByteTotal);
|
|
237
|
+
const adjustedLength = this.sequenceHeaderSize + __classPrivateFieldGet(this, _ChunkManager_cursor, "f") + this.signatureLength;
|
|
238
|
+
(0, node_opcua_assert_1.assert)(adjustedLength % this.plainBlockSize === 0);
|
|
239
|
+
const nbBlock = adjustedLength / this.plainBlockSize;
|
|
240
|
+
extraEncryptionBytes = nbBlock * (this.cipherBlockSize - this.plainBlockSize);
|
|
219
241
|
}
|
|
220
|
-
|
|
221
|
-
|
|
242
|
+
__classPrivateFieldSet(this, _ChunkManager_dataEnd, __classPrivateFieldGet(this, _ChunkManager_dataOffset, "f") + __classPrivateFieldGet(this, _ChunkManager_cursor, "f"), "f");
|
|
243
|
+
// calculate the expected length of the chunk, once encrypted if encryption apply
|
|
244
|
+
const expectedLength = __classPrivateFieldGet(this, _ChunkManager_dataEnd, "f") + this.signatureLength + extraEncryptionBytes;
|
|
245
|
+
__classPrivateFieldSet(this, _ChunkManager_pendingChunk, __classPrivateFieldGet(this, _ChunkManager_chunk, "f").subarray(0, expectedLength), "f");
|
|
246
|
+
// note :
|
|
247
|
+
// - this.pending_chunk has the correct size but is not signed nor encrypted yet
|
|
248
|
+
// as we don't know what to write in the header yet
|
|
249
|
+
// - as a result,
|
|
250
|
+
__classPrivateFieldSet(this, _ChunkManager_chunk, null, "f");
|
|
251
|
+
__classPrivateFieldSet(this, _ChunkManager_cursor, 0, "f");
|
|
252
|
+
};
|
|
222
253
|
//# sourceMappingURL=chunk_manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk_manager.js","sourceRoot":"","sources":["../source/chunk_manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chunk_manager.js","sourceRoot":"","sources":["../source/chunk_manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readMessageHeader =
|
|
3
|
+
exports.readMessageHeader = void 0;
|
|
4
4
|
function readMessageHeader(stream) {
|
|
5
|
-
const msgType = String.fromCharCode(stream.readUInt8()) +
|
|
6
|
-
String.fromCharCode(stream.readUInt8()) +
|
|
7
|
-
String.fromCharCode(stream.readUInt8());
|
|
5
|
+
const msgType = String.fromCharCode(stream.readUInt8()) + String.fromCharCode(stream.readUInt8()) + String.fromCharCode(stream.readUInt8());
|
|
8
6
|
const isFinal = String.fromCharCode(stream.readUInt8());
|
|
9
7
|
const length = stream.readUInt32();
|
|
10
8
|
return { msgType, isFinal, length };
|
|
11
9
|
}
|
|
10
|
+
exports.readMessageHeader = readMessageHeader;
|
|
12
11
|
//# sourceMappingURL=read_message_header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read_message_header.js","sourceRoot":"","sources":["../source/read_message_header.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read_message_header.js","sourceRoot":"","sources":["../source/read_message_header.ts"],"names":[],"mappings":";;;AAMA,SAAgB,iBAAiB,CAAC,MAAoB;IAClD,MAAM,OAAO,GACT,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAEhI,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IACnC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC;AAPD,8CAOC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-opcua-chunkmanager",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.129.0",
|
|
4
4
|
"description": "pure nodejs OPCUA SDK - module chunkmanager",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"internet of things"
|
|
37
37
|
],
|
|
38
38
|
"homepage": "http://node-opcua.github.io/",
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "8a1754350fb95a764e278d37a289f0c48ccb8c9d",
|
|
40
40
|
"files": [
|
|
41
41
|
"dist",
|
|
42
42
|
"source"
|
package/source/chunk_manager.ts
CHANGED
|
@@ -49,10 +49,10 @@ export function verify_message_chunk(messageChunk: Buffer): void {
|
|
|
49
49
|
// - The PaddingSize and Padding fields are not present if the MessageChunk is not encrypted.
|
|
50
50
|
// - The Signature field is not present if the MessageChunk is not signed.
|
|
51
51
|
|
|
52
|
-
export type WriteHeaderFunc = (chunk: Buffer, isLast: boolean, expectedLength: number) => void;
|
|
53
|
-
export type WriteSequenceHeaderFunc = (chunk: Buffer) => void;
|
|
54
|
-
export type SignBufferFunc = (buffer: Buffer) => Buffer;
|
|
55
|
-
export type EncryptBufferFunc = (buffer: Buffer) => Buffer;
|
|
52
|
+
export type WriteHeaderFunc = (this: ChunkManager, chunk: Buffer, isLast: boolean, expectedLength: number) => void;
|
|
53
|
+
export type WriteSequenceHeaderFunc = (this: ChunkManager, chunk: Buffer) => void;
|
|
54
|
+
export type SignBufferFunc = (this: ChunkManager, buffer: Buffer) => Buffer;
|
|
55
|
+
export type EncryptBufferFunc = (this: ChunkManager, buffer: Buffer) => Buffer;
|
|
56
56
|
|
|
57
57
|
export interface IChunkManagerOptions {
|
|
58
58
|
chunkSize: number;
|
|
@@ -69,66 +69,80 @@ export interface IChunkManagerOptions {
|
|
|
69
69
|
writeHeaderFunc?: WriteHeaderFunc; // write header must be specified if headerSize !=0
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export enum Mode {
|
|
73
|
+
None = 1,
|
|
74
|
+
Sign = 2,
|
|
75
|
+
SignAndEncrypt = 3
|
|
76
|
+
}
|
|
77
|
+
|
|
72
78
|
export class ChunkManager extends EventEmitter {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
#signBufferFunc?: SignBufferFunc;
|
|
80
|
+
#encryptBufferFunc?: EncryptBufferFunc;
|
|
81
|
+
#writeSequenceHeaderFunc?: WriteSequenceHeaderFunc;
|
|
82
|
+
#writeHeaderFunc?: WriteHeaderFunc;
|
|
83
|
+
|
|
84
|
+
public readonly chunkSize: number;
|
|
85
|
+
public readonly headerSize: number;
|
|
86
|
+
public readonly maxBodySize: number;
|
|
87
|
+
public readonly signatureLength: number;
|
|
88
|
+
public readonly sequenceHeaderSize: number;
|
|
89
|
+
public readonly cipherBlockSize: number;
|
|
90
|
+
public readonly plainBlockSize: number;
|
|
84
91
|
|
|
85
92
|
// --------------
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
readonly #maxBlock?: number;
|
|
94
|
+
|
|
95
|
+
readonly #dataOffset: number;
|
|
96
|
+
public readonly securityMode: Mode;
|
|
97
|
+
|
|
98
|
+
#chunk: Buffer | null;
|
|
99
|
+
#cursor: number;
|
|
100
|
+
#pendingChunk: Buffer | null;
|
|
101
|
+
#dataEnd: number;
|
|
102
|
+
|
|
103
|
+
constructor(securityMode: Mode, options: IChunkManagerOptions) {
|
|
95
104
|
super();
|
|
96
105
|
|
|
106
|
+
this.securityMode = securityMode;
|
|
107
|
+
|
|
97
108
|
// { chunkSize : 32, headerSize : 10 ,signatureLength: 32 }
|
|
98
109
|
this.chunkSize = options.chunkSize;
|
|
99
110
|
|
|
100
111
|
this.headerSize = options.headerSize || 0;
|
|
101
112
|
if (this.headerSize) {
|
|
102
|
-
this
|
|
103
|
-
assert(typeof this
|
|
113
|
+
this.#writeHeaderFunc = options.writeHeaderFunc;
|
|
114
|
+
assert(typeof this.#writeHeaderFunc === "function");
|
|
104
115
|
}
|
|
105
116
|
|
|
106
117
|
this.sequenceHeaderSize = options.sequenceHeaderSize === undefined ? 8 : options.sequenceHeaderSize;
|
|
107
118
|
if (this.sequenceHeaderSize > 0) {
|
|
108
|
-
this
|
|
109
|
-
assert(typeof this
|
|
119
|
+
this.#writeSequenceHeaderFunc = options.writeSequenceHeaderFunc;
|
|
120
|
+
assert(typeof this.#writeSequenceHeaderFunc === "function");
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
this.signatureLength = options.signatureLength || 0;
|
|
113
|
-
this
|
|
124
|
+
this.#signBufferFunc = options.signBufferFunc;
|
|
114
125
|
|
|
115
126
|
this.plainBlockSize = options.plainBlockSize || 0; // 256-14;
|
|
116
127
|
this.cipherBlockSize = options.cipherBlockSize || 0; // 256;
|
|
117
|
-
this
|
|
128
|
+
this.#dataEnd = 0;
|
|
118
129
|
|
|
119
130
|
if (this.cipherBlockSize === 0) {
|
|
131
|
+
assert(securityMode === Mode.None || securityMode === Mode.Sign);
|
|
132
|
+
// we don't encrypt,we just sign
|
|
120
133
|
assert(this.plainBlockSize === 0);
|
|
121
134
|
// unencrypted block
|
|
122
135
|
this.maxBodySize = this.chunkSize - this.headerSize - this.signatureLength - this.sequenceHeaderSize;
|
|
123
|
-
this
|
|
136
|
+
this.#encryptBufferFunc = undefined;
|
|
124
137
|
} else {
|
|
138
|
+
assert(securityMode === Mode.SignAndEncrypt || securityMode === Mode.Sign);
|
|
125
139
|
assert(this.plainBlockSize !== 0);
|
|
126
140
|
// During encryption a block with a size equal to PlainTextBlockSize is processed to produce a block
|
|
127
141
|
// with size equal to CipherTextBlockSize. These values depend on the encryption algorithm and may
|
|
128
142
|
// be the same.
|
|
129
143
|
|
|
130
|
-
this
|
|
131
|
-
assert(typeof this
|
|
144
|
+
this.#encryptBufferFunc = options.encryptBufferFunc;
|
|
145
|
+
assert(typeof this.#encryptBufferFunc === "function", "an encryptBufferFunc is required");
|
|
132
146
|
|
|
133
147
|
// this is the formula proposed by OPCUA
|
|
134
148
|
this.maxBodySize =
|
|
@@ -137,8 +151,8 @@ export class ChunkManager extends EventEmitter {
|
|
|
137
151
|
this.sequenceHeaderSize;
|
|
138
152
|
|
|
139
153
|
// this is the formula proposed by ERN
|
|
140
|
-
this
|
|
141
|
-
this.maxBodySize = this.plainBlockSize * this
|
|
154
|
+
this.#maxBlock = Math.floor((this.chunkSize - this.headerSize) / this.cipherBlockSize);
|
|
155
|
+
this.maxBodySize = this.plainBlockSize * this.#maxBlock - this.sequenceHeaderSize - this.signatureLength - 1;
|
|
142
156
|
|
|
143
157
|
if (this.plainBlockSize > 256) {
|
|
144
158
|
this.maxBodySize -= 1;
|
|
@@ -147,11 +161,11 @@ export class ChunkManager extends EventEmitter {
|
|
|
147
161
|
assert(this.maxBodySize > 0); // no space left to write data
|
|
148
162
|
|
|
149
163
|
// where the data starts in the block
|
|
150
|
-
this
|
|
164
|
+
this.#dataOffset = this.headerSize + this.sequenceHeaderSize;
|
|
151
165
|
|
|
152
|
-
this
|
|
153
|
-
this
|
|
154
|
-
this
|
|
166
|
+
this.#chunk = null;
|
|
167
|
+
this.#cursor = 0;
|
|
168
|
+
this.#pendingChunk = null;
|
|
155
169
|
}
|
|
156
170
|
|
|
157
171
|
public evaluateTotalLengthAndChunks(bodySize: number): { totalLength: number; chunkCount: number } {
|
|
@@ -171,36 +185,36 @@ export class ChunkManager extends EventEmitter {
|
|
|
171
185
|
while (l > 0) {
|
|
172
186
|
assert(length - inputCursor !== 0);
|
|
173
187
|
|
|
174
|
-
if (this
|
|
175
|
-
this
|
|
188
|
+
if (this.#cursor === 0) {
|
|
189
|
+
this.#_push_pending_chunk(false);
|
|
176
190
|
}
|
|
177
191
|
|
|
178
192
|
// space left in current chunk
|
|
179
|
-
const spaceLeft = this.maxBodySize - this
|
|
193
|
+
const spaceLeft = this.maxBodySize - this.#cursor;
|
|
180
194
|
|
|
181
195
|
const nbToWrite = Math.min(length - inputCursor, spaceLeft);
|
|
182
196
|
|
|
183
|
-
this
|
|
197
|
+
this.#chunk = this.#chunk || createFastUninitializedBuffer(this.chunkSize);
|
|
184
198
|
|
|
185
199
|
if (buffer) {
|
|
186
|
-
buffer.copy(this
|
|
200
|
+
buffer.copy(this.#chunk!, this.#cursor + this.#dataOffset, inputCursor, inputCursor + nbToWrite);
|
|
187
201
|
}
|
|
188
202
|
|
|
189
203
|
inputCursor += nbToWrite;
|
|
190
|
-
this
|
|
204
|
+
this.#cursor += nbToWrite;
|
|
191
205
|
|
|
192
|
-
if (this
|
|
193
|
-
this
|
|
206
|
+
if (this.#cursor >= this.maxBodySize) {
|
|
207
|
+
this.#_post_process_current_chunk();
|
|
194
208
|
}
|
|
195
209
|
l -= nbToWrite;
|
|
196
210
|
}
|
|
197
211
|
}
|
|
198
212
|
|
|
199
213
|
public end() {
|
|
200
|
-
if (this
|
|
201
|
-
this
|
|
214
|
+
if (this.#cursor > 0) {
|
|
215
|
+
this.#_post_process_current_chunk();
|
|
202
216
|
}
|
|
203
|
-
this
|
|
217
|
+
this.#_push_pending_chunk(true);
|
|
204
218
|
}
|
|
205
219
|
|
|
206
220
|
/**
|
|
@@ -210,35 +224,42 @@ export class ChunkManager extends EventEmitter {
|
|
|
210
224
|
* @method _write_signature
|
|
211
225
|
* @private
|
|
212
226
|
*/
|
|
213
|
-
|
|
214
|
-
if (this.
|
|
215
|
-
assert(
|
|
227
|
+
#_write_signature(chunk: Buffer) {
|
|
228
|
+
if (this.securityMode === Mode.None) {
|
|
229
|
+
assert(this.signatureLength === 0, "expecting NO SIGN");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (this.#signBufferFunc) {
|
|
233
|
+
assert(typeof this.#signBufferFunc === "function");
|
|
216
234
|
assert(this.signatureLength !== 0);
|
|
217
235
|
|
|
218
|
-
const signatureStart = this
|
|
236
|
+
const signatureStart = this.#dataEnd;
|
|
219
237
|
const sectionToSign = chunk.subarray(0, signatureStart);
|
|
220
238
|
|
|
221
|
-
const signature = this.
|
|
222
|
-
assert(signature.length === this.signatureLength
|
|
223
|
-
|
|
239
|
+
const signature = this.#signBufferFunc.call(this, sectionToSign);
|
|
240
|
+
assert(signature.length === this.signatureLength, "expecting signature length to match");
|
|
224
241
|
signature.copy(chunk, signatureStart);
|
|
225
242
|
} else {
|
|
226
243
|
assert(this.signatureLength === 0, "expecting NO SIGN");
|
|
227
244
|
}
|
|
228
245
|
}
|
|
229
246
|
|
|
230
|
-
|
|
231
|
-
if (this.
|
|
232
|
-
|
|
247
|
+
#_encrypt(chunk: Buffer) {
|
|
248
|
+
if (this.securityMode === Mode.None) {
|
|
249
|
+
// nothing todo
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (this.plainBlockSize > 0 && this.#encryptBufferFunc) {
|
|
253
|
+
assert(this.#dataEnd !== undefined);
|
|
233
254
|
const startEncryptionPos = this.headerSize;
|
|
234
|
-
const endEncryptionPos = this
|
|
255
|
+
const endEncryptionPos = this.#dataEnd + this.signatureLength;
|
|
235
256
|
|
|
236
257
|
const areaToEncrypt = chunk.subarray(startEncryptionPos, endEncryptionPos);
|
|
237
258
|
|
|
238
259
|
assert(areaToEncrypt.length % this.plainBlockSize === 0); // padding should have been applied
|
|
239
260
|
const nbBlock = areaToEncrypt.length / this.plainBlockSize;
|
|
240
261
|
|
|
241
|
-
const encryptedBuffer = this
|
|
262
|
+
const encryptedBuffer = this.#encryptBufferFunc!.call(this, areaToEncrypt);
|
|
242
263
|
assert(encryptedBuffer.length % this.cipherBlockSize === 0);
|
|
243
264
|
assert(encryptedBuffer.length === nbBlock * this.cipherBlockSize);
|
|
244
265
|
|
|
@@ -246,56 +267,59 @@ export class ChunkManager extends EventEmitter {
|
|
|
246
267
|
}
|
|
247
268
|
}
|
|
248
269
|
|
|
249
|
-
|
|
250
|
-
if (this
|
|
251
|
-
const expectedLength = this
|
|
270
|
+
#_push_pending_chunk(isLast: boolean) {
|
|
271
|
+
if (this.#pendingChunk) {
|
|
272
|
+
const expectedLength = this.#pendingChunk.length;
|
|
252
273
|
|
|
253
274
|
if (this.headerSize > 0) {
|
|
254
275
|
// Release 1.02 39 OPC Unified Architecture, Part 6:
|
|
255
276
|
// The sequence header ensures that the first encrypted block of every Message sent over
|
|
256
277
|
// a channel will start with different data.
|
|
257
|
-
this
|
|
278
|
+
this.#writeHeaderFunc!.call(this, this.#pendingChunk.subarray(0, this.headerSize), isLast, expectedLength);
|
|
258
279
|
}
|
|
259
280
|
if (this.sequenceHeaderSize > 0) {
|
|
260
|
-
this
|
|
281
|
+
this.#writeSequenceHeaderFunc!.call(
|
|
282
|
+
this,
|
|
283
|
+
this.#pendingChunk.subarray(this.headerSize, this.headerSize + this.sequenceHeaderSize)
|
|
284
|
+
);
|
|
261
285
|
}
|
|
262
286
|
|
|
263
|
-
this
|
|
287
|
+
this.#_write_signature(this.#pendingChunk);
|
|
264
288
|
|
|
265
|
-
this
|
|
289
|
+
this.#_encrypt(this.#pendingChunk);
|
|
266
290
|
|
|
267
291
|
/**
|
|
268
292
|
* @event chunk
|
|
269
293
|
* @param chunk {Buffer}
|
|
270
294
|
* @param isLast {Boolean} , true if final chunk
|
|
271
295
|
*/
|
|
272
|
-
this.emit("chunk", this
|
|
273
|
-
this
|
|
296
|
+
this.emit("chunk", this.#pendingChunk, isLast);
|
|
297
|
+
this.#pendingChunk = null;
|
|
274
298
|
}
|
|
275
299
|
}
|
|
276
300
|
|
|
277
|
-
|
|
301
|
+
#_write_padding_bytes(nbPaddingByteTotal: number) {
|
|
278
302
|
const nbPaddingByte = nbPaddingByteTotal % 256;
|
|
279
303
|
const extraNbPaddingByte = Math.floor(nbPaddingByteTotal / 256);
|
|
280
304
|
|
|
281
305
|
assert(extraNbPaddingByte === 0 || this.plainBlockSize > 256, "extraNbPaddingByte only requested when key size > 2048");
|
|
282
306
|
|
|
283
307
|
// write the padding byte
|
|
284
|
-
this
|
|
285
|
-
this
|
|
308
|
+
this.#chunk!.writeUInt8(nbPaddingByte, this.#cursor + this.#dataOffset);
|
|
309
|
+
this.#cursor += 1;
|
|
286
310
|
|
|
287
311
|
for (let i = 0; i < nbPaddingByteTotal; i++) {
|
|
288
|
-
this
|
|
312
|
+
this.#chunk!.writeUInt8(nbPaddingByte, this.#cursor + this.#dataOffset + i);
|
|
289
313
|
}
|
|
290
|
-
this
|
|
314
|
+
this.#cursor += nbPaddingByteTotal;
|
|
291
315
|
|
|
292
316
|
if (this.plainBlockSize > 256) {
|
|
293
|
-
this
|
|
294
|
-
this
|
|
317
|
+
this.#chunk!.writeUInt8(extraNbPaddingByte, this.#cursor + this.#dataOffset);
|
|
318
|
+
this.#cursor += 1;
|
|
295
319
|
}
|
|
296
320
|
}
|
|
297
321
|
|
|
298
|
-
|
|
322
|
+
#_post_process_current_chunk() {
|
|
299
323
|
let extraEncryptionBytes = 0;
|
|
300
324
|
// add padding bytes if needed
|
|
301
325
|
if (this.plainBlockSize > 0) {
|
|
@@ -305,7 +329,7 @@ export class ChunkManager extends EventEmitter {
|
|
|
305
329
|
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
306
330
|
// |SequenceHeader | data | paddingByte | padding | extraPadding | signature |
|
|
307
331
|
// +---------------+---------------+-------------+---------+--------------+------------+
|
|
308
|
-
let curLength = this.sequenceHeaderSize + this
|
|
332
|
+
let curLength = this.sequenceHeaderSize + this.#cursor + this.signatureLength;
|
|
309
333
|
if (this.plainBlockSize > 256) {
|
|
310
334
|
curLength += 2; // account for extraPadding Byte Number;
|
|
311
335
|
} else {
|
|
@@ -315,25 +339,25 @@ export class ChunkManager extends EventEmitter {
|
|
|
315
339
|
const n = curLength % this.plainBlockSize;
|
|
316
340
|
const nbPaddingByteTotal = (this.plainBlockSize - n) % this.plainBlockSize;
|
|
317
341
|
|
|
318
|
-
this
|
|
319
|
-
const adjustedLength = this.sequenceHeaderSize + this
|
|
342
|
+
this.#_write_padding_bytes(nbPaddingByteTotal);
|
|
343
|
+
const adjustedLength = this.sequenceHeaderSize + this.#cursor + this.signatureLength;
|
|
320
344
|
|
|
321
345
|
assert(adjustedLength % this.plainBlockSize === 0);
|
|
322
346
|
const nbBlock = adjustedLength / this.plainBlockSize;
|
|
323
347
|
extraEncryptionBytes = nbBlock * (this.cipherBlockSize - this.plainBlockSize);
|
|
324
348
|
}
|
|
325
349
|
|
|
326
|
-
this
|
|
350
|
+
this.#dataEnd = this.#dataOffset + this.#cursor;
|
|
327
351
|
|
|
328
352
|
// calculate the expected length of the chunk, once encrypted if encryption apply
|
|
329
|
-
const expectedLength = this
|
|
353
|
+
const expectedLength = this.#dataEnd + this.signatureLength + extraEncryptionBytes;
|
|
330
354
|
|
|
331
|
-
this
|
|
355
|
+
this.#pendingChunk = this.#chunk!.subarray(0, expectedLength);
|
|
332
356
|
// note :
|
|
333
357
|
// - this.pending_chunk has the correct size but is not signed nor encrypted yet
|
|
334
358
|
// as we don't know what to write in the header yet
|
|
335
359
|
// - as a result,
|
|
336
|
-
this
|
|
337
|
-
this
|
|
360
|
+
this.#chunk = null;
|
|
361
|
+
this.#cursor = 0;
|
|
338
362
|
}
|
|
339
363
|
}
|
|
@@ -5,12 +5,10 @@ import { BinaryStream } from "node-opcua-binary-stream";
|
|
|
5
5
|
import { MessageHeader } from "node-opcua-packet-assembler";
|
|
6
6
|
|
|
7
7
|
export function readMessageHeader(stream: BinaryStream): MessageHeader {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
String.fromCharCode(stream.readUInt8()) +
|
|
11
|
-
String.fromCharCode(stream.readUInt8());
|
|
8
|
+
const msgType =
|
|
9
|
+
String.fromCharCode(stream.readUInt8()) + String.fromCharCode(stream.readUInt8()) + String.fromCharCode(stream.readUInt8());
|
|
12
10
|
|
|
13
11
|
const isFinal = String.fromCharCode(stream.readUInt8());
|
|
14
12
|
const length = stream.readUInt32();
|
|
15
|
-
return {msgType, isFinal, length};
|
|
13
|
+
return { msgType, isFinal, length };
|
|
16
14
|
}
|