Ported Bitwise operations

also enabled bitshift tests
This commit is contained in:
Matt C 2018-05-23 18:59:57 +01:00
parent 9ffab374db
commit 95f81ad740
9 changed files with 707 additions and 1 deletions

117
src/core/lib/BitwiseOp.mjs Normal file
View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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";