Browse Source

Ported Bitwise operations

also enabled bitshift tests
Matt C 7 years ago
parent
commit
95f81ad740

+ 117 - 0
src/core/lib/BitwiseOp.mjs

@@ -0,0 +1,117 @@
+/**
+ * Bitwise operation resources.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+/**
+ * Runs bitwise operations across the input data.
+ *
+ * @param {byteArray} input
+ * @param {byteArray} key
+ * @param {function} func - The bitwise calculation to carry out
+ * @param {boolean} nullPreserving
+ * @param {string} scheme
+ * @returns {byteArray}
+ */
+export function bitOp (input, key, func, nullPreserving, scheme) {
+    if (!key || !key.length) key = [0];
+    const result = [];
+    let x = null,
+        k = null,
+        o = null;
+
+    for (let i = 0; i < input.length; i++) {
+        k = key[i % key.length];
+        o = input[i];
+        x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
+        result.push(x);
+        if (scheme &&
+            scheme !== "Standard" &&
+            !(nullPreserving && (o === 0 || o === k))) {
+            switch (scheme) {
+                case "Input differential":
+                    key[i % key.length] = x;
+                    break;
+                case "Output differential":
+                    key[i % key.length] = o;
+                    break;
+            }
+        }
+    }
+
+    return result;
+}
+
+/**
+ * XOR bitwise calculation.
+ *
+ * @param {number} operand
+ * @param {number} key
+ * @returns {number}
+ */
+export function xor(operand, key) {
+    return operand ^ key;
+}
+
+
+/**
+ * NOT bitwise calculation.
+ *
+ * @param {number} operand
+ * @returns {number}
+ */
+export function not(operand, _) {
+    return ~operand & 0xff;
+}
+
+
+/**
+ * AND bitwise calculation.
+ *
+ * @param {number} operand
+ * @param {number} key
+ * @returns {number}
+ */
+export function and(operand, key) {
+    return operand & key;
+}
+
+
+/**
+ * OR bitwise calculation.
+ *
+ * @param {number} operand
+ * @param {number} key
+ * @returns {number}
+ */
+export function or(operand, key) {
+    return operand | key;
+}
+
+
+/**
+ * ADD bitwise calculation.
+ *
+ * @param {number} operand
+ * @param {number} key
+ * @returns {number}
+ */
+export function add(operand, key) {
+    return (operand + key) % 256;
+}
+
+
+/**
+ * SUB bitwise calculation.
+ *
+ * @param {number} operand
+ * @param {number} key
+ * @returns {number}
+ */
+export function sub(operand, key) {
+    const result = operand - key;
+    return (result < 0) ? 256 + result : result;
+}

+ 76 - 0
src/core/operations/ADD.mjs

@@ -0,0 +1,76 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, add } from "../lib/BitwiseOp";
+
+/**
+ * ADD operation
+ */
+class ADD extends Operation {
+
+    /**
+     * ADD constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "ADD";
+        this.module = "Default";
+        this.description = "ADD the input with the given key (e.g. <code>fe023da5</code>), MOD 255";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "toggleString",
+                "value": "",
+                "toggleValues": ["Hex", "Base64", "UTF8", "Latin1"]
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
+
+        return bitOp(input, key, add);
+    }
+
+    /**
+     * Highlight ADD
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight ADD in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default ADD;

+ 76 - 0
src/core/operations/AND.mjs

@@ -0,0 +1,76 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, and } from "../lib/BitwiseOp";
+
+/**
+ * AND operation
+ */
+class AND extends Operation {
+
+    /**
+     * AND constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "AND";
+        this.module = "Default";
+        this.description = "AND the input with the given key.<br>e.g. <code>fe023da5</code>";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "toggleString",
+                "value": "",
+                "toggleValues": ["Hex", "Base64", "UTF8", "Latin1"]
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
+
+        return bitOp(input, key, and);
+    }
+
+    /**
+     * Highlight AND
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight AND in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default AND;

+ 66 - 0
src/core/operations/NOT.mjs

@@ -0,0 +1,66 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import { bitOp, not } from "../lib/BitwiseOp";
+
+/**
+ * NOT operation
+ */
+class NOT extends Operation {
+
+    /**
+     * NOT constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "NOT";
+        this.module = "Default";
+        this.description = "Returns the inverse of each byte.";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        return bitOp(input, null, not);
+    }
+
+    /**
+     * Highlight NOT
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight NOT in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default NOT;

+ 76 - 0
src/core/operations/OR.mjs

@@ -0,0 +1,76 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, or } from "../lib/BitwiseOp";
+
+/**
+ * OR operation
+ */
+class OR extends Operation {
+
+    /**
+     * OR constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "OR";
+        this.module = "Default";
+        this.description = "OR the input with the given key.<br>e.g. <code>fe023da5</code>";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "toggleString",
+                "value": "",
+                "toggleValues": ["Hex", "Base64", "UTF8", "Latin1"]
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
+
+        return bitOp(input, key, or);
+    }
+
+    /**
+     * Highlight OR
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight OR in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default OR;

+ 76 - 0
src/core/operations/SUB.mjs

@@ -0,0 +1,76 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, sub } from "../lib/BitwiseOp";
+
+/**
+ * SUB operation
+ */
+class SUB extends Operation {
+
+    /**
+     * SUB constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "SUB";
+        this.module = "Default";
+        this.description = "SUB the input with the given key (e.g. <code>fe023da5</code>), MOD 255";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "toggleString",
+                "value": "",
+                "toggleValues": ["Hex", "Base64", "UTF8", "Latin1"]
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
+
+        return bitOp(input, key, sub);
+    }
+
+    /**
+     * Highlight SUB
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight SUB in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default SUB;

+ 87 - 0
src/core/operations/XOR.mjs

@@ -0,0 +1,87 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, xor } from "../lib/BitwiseOp";
+
+/**
+ * XOR operation
+ */
+class XOR extends Operation {
+
+    /**
+     * XOR constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "XOR";
+        this.module = "Default";
+        this.description = "XOR the input with the given key.<br>e.g. <code>fe023da5</code><br><br><strong>Options</strong><br><u>Null preserving:</u> If the current byte is 0x00 or the same as the key, skip it.<br><br><u>Scheme:</u><ul><li>Standard - key is unchanged after each round</li><li>Input differential - key is set to the value of the previous unprocessed byte</li><li>Output differential - key is set to the value of the previous processed byte</li></ul>";
+        this.inputType = "byteArray";
+        this.outputType = "byteArray";
+        this.args = [
+            {
+                "name": "Key",
+                "type": "toggleString",
+                "value": "",
+                "toggleValues": ["Hex", "Base64", "UTF8", "Latin1"]
+            },
+            {
+                "name": "Scheme",
+                "type": "option",
+                "value": ["Standard", "Input differential", "Output differential"]
+            },
+            {
+                "name": "Null preserving",
+                "type": "boolean",
+                "value": false
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {byteArray}
+     */
+    run(input, args) {
+        const key = Utils.convertToByteArray(args[0].string || "", args[0].option),
+            [, scheme, nullPreserving] = args;
+
+        return bitOp(input, key, xor, nullPreserving, scheme);
+    }
+
+    /**
+     * Highlight XOR
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlight(pos, args) {
+        return pos;
+    }
+
+    /**
+     * Highlight XOR in reverse
+     *
+     * @param {Object[]} pos
+     * @param {number} pos[].start
+     * @param {number} pos[].end
+     * @param {Object[]} args
+     * @returns {Object[]} pos
+     */
+    highlightReverse(pos, args) {
+        return pos;
+    }
+
+}
+
+export default XOR;

+ 132 - 0
src/core/operations/XORBruteForce.mjs

@@ -0,0 +1,132 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import Utils from "../Utils";
+import { bitOp, xor } from "../lib/BitwiseOp";
+import { toHex } from "../lib/Hex";
+
+/**
+ * XOR Brute Force operation
+ */
+class XORBruteForce extends Operation {
+
+    /**
+     * XORBruteForce constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "XOR Brute Force";
+        this.module = "Default";
+        this.description = "Enumerate all possible XOR solutions. Current maximum key length is 2 due to browser performance.<br><br>Optionally enter a string that you expect to find in the plaintext to filter results (crib).";
+        this.inputType = "byteArray";
+        this.outputType = "string";
+        this.args = [
+            {
+                "name": "Key length",
+                "type": "number",
+                "value": 1
+            },
+            {
+                "name": "Sample length",
+                "type": "number",
+                "value": 100
+            },
+            {
+                "name": "Sample offset",
+                "type": "number",
+                "value": 0
+            },
+            {
+                "name": "Scheme",
+                "type": "option",
+                "value": ["Standard", "Input differential", "Output differential"]
+            },
+            {
+                "name": "Null preserving",
+                "type": "boolean",
+                "value": false
+            },
+            {
+                "name": "Print key",
+                "type": "boolean",
+                "value": true
+            },
+            {
+                "name": "Output as hex",
+                "type": "boolean",
+                "value": false
+            },
+            {
+                "name": "Crib (known plaintext string)",
+                "type": "binaryString",
+                "value": ""
+            }
+        ];
+    }
+
+    /**
+     * @param {byteArray} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [keyLength, sampleLength, sampleOffset, scheme, nullPreserving, printKey, outputHex, /* ignore element */] = args, //eslint-disable-line array-bracket-spacing
+            crib = args[7].toLowerCase();
+
+        const output = [];
+        let result,
+            resultUtf8,
+            record = "";
+
+        input = input.slice(sampleOffset, sampleOffset + sampleLength);
+
+        if (ENVIRONMENT_IS_WORKER())
+            self.sendStatusMessage("Calculating " + Math.pow(256, keyLength) + " values...");
+
+        /**
+         * Converts an integer to an array of bytes expressing that number.
+         *
+         * @param {number} int
+         * @param {number} len - Length of the resulting array
+         * @returns {array}
+         */
+        const intToByteArray = (int, len) => {
+            const res = Array(len).fill(0);
+            for (let i = len - 1; i >= 0; i--) {
+                res[i] = int & 0xff;
+                int = int >>> 8;
+            }
+            return res;
+        };
+
+        for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
+            if (key % 10000 === 0 && ENVIRONMENT_IS_WORKER()) {
+                self.sendStatusMessage("Calculating " + l + " values... " + Math.floor(key / l * 100) + "%");
+            }
+
+            result = bitOp(input, intToByteArray(key, keyLength), xor, nullPreserving, scheme);
+            resultUtf8 = Utils.byteArrayToUtf8(result);
+            record = "";
+
+            if (crib && resultUtf8.toLowerCase().indexOf(crib) < 0) continue;
+            if (printKey) record += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
+            if (outputHex) {
+                record += toHex(result);
+            } else {
+                record += Utils.printable(resultUtf8, false);
+            }
+
+            output.push(record);
+        }
+
+        return output.join("\n");
+    }
+
+}
+
+export default XORBruteForce;

+ 1 - 1
test/index.mjs

@@ -27,7 +27,7 @@ import TestRegister from "./TestRegister";
 import "./tests/operations/Base58";
 import "./tests/operations/Base64";
 import "./tests/operations/BCD";
-// import "./tests/operations/BitwiseOp";
+import "./tests/operations/BitwiseOp";
 import "./tests/operations/BSON";
 import "./tests/operations/ByteRepr";
 import "./tests/operations/CartesianProduct";