diff --git a/src/core/Utils.mjs b/src/core/Utils.mjs index a9c381d7..dabec6e8 100755 --- a/src/core/Utils.mjs +++ b/src/core/Utils.mjs @@ -327,6 +327,8 @@ class Utils { * * @param {string} str * @param {string} type - One of "Binary", "Hex", "Decimal", "Base64", "UTF8" or "Latin1" + * @param {string} [delim="Auto"] - (Hex only) Delimiter used to split the input string. Set to "Auto" by default. + * @param {boolean} [throwError=false] - (Hex only) Whether to throw an error on invalid input. Defaults to false. * @returns {byteArray} * * @example @@ -339,12 +341,12 @@ class Utils { * // returns [208, 159, 209, 128, 208, 184, 208, 178, 208, 181, 209, 130] * Utils.convertToByteArray("0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1", "base64"); */ - static convertToByteArray(str, type) { + static convertToByteArray(str, type, delim = "Auto", throwError = false) { switch (type.toLowerCase()) { case "binary": return fromBinary(str); case "hex": - return fromHex(str); + return fromHex(str, delim, 2, throwError); case "decimal": return fromDecimal(str); case "base64": diff --git a/src/core/lib/Hex.mjs b/src/core/lib/Hex.mjs index 78e1ad58..71ce7a13 100644 --- a/src/core/lib/Hex.mjs +++ b/src/core/lib/Hex.mjs @@ -91,6 +91,7 @@ export function toHexFast(data) { * @param {string} data * @param {string} [delim] * @param {number} [byteLen=2] + * @param {boolean} [throwError=false] * @returns {byteArray} * * @example @@ -100,7 +101,7 @@ export function toHexFast(data) { * // returns [10,20,30] * fromHex("0a:14:1e", "Colon"); */ -export function fromHex(data, delim="Auto", byteLen=2) { +export function fromHex(data, delim="Auto", byteLen=2, throwError=false) { if (byteLen < 1 || Math.round(byteLen) !== byteLen) throw new OperationError("Byte length must be a positive integer"); @@ -114,7 +115,11 @@ export function fromHex(data, delim="Auto", byteLen=2) { const output = []; for (let i = 0; i < data.length; i++) { for (let j = 0; j < data[i].length; j += byteLen) { - output.push(parseInt(data[i].substr(j, byteLen), 16)); + const chunk = data[i].substr(j, byteLen); + if (throwError && /[^a-f\d]/i.test(chunk)) { + throw new OperationError(`Invalid hex character in chunk "${chunk}"`); + } + output.push(parseInt(chunk, 16)); } } return output; diff --git a/src/core/operations/XOR.mjs b/src/core/operations/XOR.mjs index aa228842..511a7680 100644 --- a/src/core/operations/XOR.mjs +++ b/src/core/operations/XOR.mjs @@ -5,6 +5,7 @@ */ import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; import Utils from "../Utils.mjs"; import { bitOp, xor, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs"; @@ -41,6 +42,11 @@ class XOR extends Operation { "name": "Null preserving", "type": "boolean", "value": false + }, + { + "name": "Filter Key", + "type": "boolean", + "value": true } ]; } @@ -52,10 +58,14 @@ class XOR extends Operation { */ run(input, args) { input = new Uint8Array(input); - const key = Utils.convertToByteArray(args[0].string || "", args[0].option), - [, scheme, nullPreserving] = args; + try { + const key = Utils.convertToByteArray(args[0].string || "", args[0].option, args[3] ? "Auto" : "None", true), + [, scheme, nullPreserving] = args; - return bitOp(input, key, xor, nullPreserving, scheme); + return bitOp(input, key, xor, nullPreserving, scheme); + } catch (error) { + throw new OperationError("Invalid Characters in key"); + } } /** diff --git a/tests/node/tests/operations.mjs b/tests/node/tests/operations.mjs index 022b0701..b434b1dd 100644 --- a/tests/node/tests/operations.mjs +++ b/tests/node/tests/operations.mjs @@ -989,6 +989,27 @@ smothering ampersand abreast`; "QV\u0010\u0004UDWQ"); }), + it("XOR: should throw 'Invalid Characters in key' error when key contains invalid characters", () => { + const invalidKeys = [ + { string: "zz 00 11", option: "Hex" }, + + { string: "4~ 00 11", option: "Hex" } + ]; + invalidKeys.forEach(invalidKey => { + assert.throws(() => { + chef.XOR("fe023da5", { key: invalidKey, filterKey: false }); + }, /Invalid Characters in key/); + }); + }), + + it("XOR: should not throw 'Invalid Characters in key' error when key contains only valid characters", () => { + assert.strictEqual(chef.XOR("fe023da5", { + key: "736f6d65", + filterKey: false + }).toString(), + "\u0015\n]W@\u000b\fP"); + }), + it("XPath expression", () => { assert.strictEqual( chef.XPathExpression("abc", {xPath: "contact-info/company"}).toString(),