node-noise
Version:
150 lines • 6.41 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decryptStream = exports.encryptStream = void 0;
var streams = __importStar(require("stream"));
var chacha20poly1305_1 = require("@stablelib/chacha20poly1305");
var encoder_1 = require("../encoder");
var doImmediate = (typeof setImmediate !== 'undefined') ? setImmediate : function (fn) {
setTimeout(fn, 0);
};
// Returns generator that encrypts payload from the user
function encryptStream(handshake, metrics, noLengthCodec, noiseMsgMaxLengthBytes) {
var maxLengthBytes = noiseMsgMaxLengthBytes || -1;
var maxLengthBytesWithoutTag = maxLengthBytes - 16;
var nextWrite = null;
return new streams.Transform({
autoDestroy: true,
read: function (size) {
var nextWriteLocal = nextWrite;
if (nextWriteLocal) {
nextWrite = null;
nextWriteLocal();
}
},
write: function (chunk, encoding, callback) {
var _this = this;
var i = 0;
var next = function () {
var end = chunk.length;
if (i < chunk.length) {
if (maxLengthBytesWithoutTag > 0) {
end = i + maxLengthBytesWithoutTag;
if (end > chunk.length) {
end = chunk.length;
}
}
var plaintext = chunk.subarray(i, end);
var data = Buffer.from(handshake.encrypt(plaintext, handshake.session));
metrics === null || metrics === void 0 ? void 0 : metrics.encryptedPackets.increment();
if (!noLengthCodec) {
var encodedLength = (0, encoder_1.uint16BEEncode)(data.byteLength);
_this.push(encodedLength);
}
i += plaintext.length;
if (_this.push(data)) {
doImmediate(next);
}
else {
if (nextWrite) {
callback(new Error('illegal write'));
return;
}
nextWrite = next;
}
}
else {
callback();
}
};
next();
}
});
}
exports.encryptStream = encryptStream;
// Decrypt received payload to the user
function decryptStream(handshake, metrics, noiseMsgMaxLengthBytes) {
var maxLengthBytes = noiseMsgMaxLengthBytes || -1;
var maxLengthBytesWithoutTag = maxLengthBytes - 16;
var nextWrite = null;
return new streams.Transform({
autoDestroy: true,
read: function (size) {
var nextWriteLocal = nextWrite;
if (nextWriteLocal) {
nextWrite = null;
nextWriteLocal();
}
},
write: function (chunk, encoding, callback) {
var _this = this;
var i = 0;
var next = function () {
if (i < chunk.length) {
var end = chunk.length;
if (maxLengthBytes > 0) {
end = i + maxLengthBytes;
if (end > chunk.length) {
end = chunk.length;
}
}
if (end - chacha20poly1305_1.TAG_LENGTH < i) {
callback(new Error('Invalid chunk'));
return;
}
var encrypted = chunk.subarray(i, end);
// memory allocation is not cheap so reuse the encrypted Uint8Array
// see https://github.com/ChainSafe/js-libp2p-noise/pull/242#issue-1422126164
// this is ok because chacha20 reads bytes one by one and don't reread after that
// it's also tested in https://github.com/ChainSafe/as-chacha20poly1305/pull/1/files#diff-25252846b58979dcaf4e41d47b3eadd7e4f335e7fb98da6c049b1f9cd011f381R48
var dst = chunk.subarray(i, end - chacha20poly1305_1.TAG_LENGTH);
i += encrypted.length;
var _a = handshake.decrypt(encrypted, handshake.session, dst), decrypted = _a.plaintext, valid = _a.valid;
if (!valid) {
metrics === null || metrics === void 0 ? void 0 : metrics.decryptErrors.increment();
throw new Error('Failed to validate decrypted chunk');
}
metrics === null || metrics === void 0 ? void 0 : metrics.decryptedPackets.increment();
if (_this.push(decrypted)) {
doImmediate(next);
}
else {
if (nextWrite) {
callback(new Error('illegal write'));
return;
}
nextWrite = next;
}
}
else {
callback();
}
};
next();
}
});
}
exports.decryptStream = decryptStream;
//# sourceMappingURL=streaming.js.map