diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js
index 77eafb4b..b74e932a 100755
--- a/src/core/config/Categories.js
+++ b/src/core/config/Categories.js
@@ -84,8 +84,8 @@ const Categories = [
// "RC2 Decrypt",
// "RC4",
// "RC4 Drop",
- // "ROT13",
- // "ROT47",
+ "ROT13",
+ "ROT47",
// "XOR",
// "XOR Brute Force",
// "Vigenère Encode",
@@ -116,9 +116,9 @@ const Categories = [
// "Object Identifier to Hex",
// ]
// },
- // {
- // name: "Arithmetic / Logic",
- // ops: [
+ {
+ name: "Arithmetic / Logic",
+ ops: [
// "XOR",
// "XOR Brute Force",
// "OR",
@@ -135,11 +135,11 @@ const Categories = [
// "Standard Deviation",
// "Bit shift left",
// "Bit shift right",
- // "Rotate left",
- // "Rotate right",
- // "ROT13",
- // ]
- // },
+ "Rotate left",
+ "Rotate right",
+ "ROT13"
+ ]
+ },
// {
// name: "Networking",
// ops: [
diff --git a/src/core/config/OperationConfig.json b/src/core/config/OperationConfig.json
index 1486c66d..2f18363d 100644
--- a/src/core/config/OperationConfig.json
+++ b/src/core/config/OperationConfig.json
@@ -155,6 +155,44 @@
}
]
},
+ "ROT13": {
+ "module": "Default",
+ "description": "A simple caesar substitution cipher which rotates alphabet characters by the specified amount (default 13).",
+ "inputType": "byteArray",
+ "outputType": "byteArray",
+ "flowControl": false,
+ "args": [
+ {
+ "name": "Rotate lower case chars",
+ "type": "boolean",
+ "value": true
+ },
+ {
+ "name": "Rotate upper case chars",
+ "type": "boolean",
+ "value": true
+ },
+ {
+ "name": "Amount",
+ "type": "number",
+ "value": 13
+ }
+ ]
+ },
+ "ROT47": {
+ "module": "Default",
+ "description": "A slightly more complex variation of a caesar cipher, which includes ASCII characters from 33 '!' to 126 '~'. Default rotation: 47.",
+ "inputType": "byteArray",
+ "outputType": "byteArray",
+ "flowControl": false,
+ "args": [
+ {
+ "name": "Amount",
+ "type": "number",
+ "value": 47
+ }
+ ]
+ },
"Raw Deflate": {
"module": "Compression",
"description": "Compresses data using the deflate algorithm with no headers.",
@@ -210,6 +248,44 @@
}
]
},
+ "Rotate left": {
+ "module": "Default",
+ "description": "Rotates each byte to the left by the number of bits specified, optionally carrying the excess bits over to the next byte. Currently only supports 8-bit values.",
+ "inputType": "byteArray",
+ "outputType": "byteArray",
+ "flowControl": false,
+ "args": [
+ {
+ "name": "Amount",
+ "type": "number",
+ "value": 1
+ },
+ {
+ "name": "Carry through",
+ "type": "boolean",
+ "value": false
+ }
+ ]
+ },
+ "Rotate right": {
+ "module": "Default",
+ "description": "Rotates each byte to the right by the number of bits specified, optionally carrying the excess bits over to the next byte. Currently only supports 8-bit values.",
+ "inputType": "byteArray",
+ "outputType": "byteArray",
+ "flowControl": false,
+ "args": [
+ {
+ "name": "Amount",
+ "type": "number",
+ "value": 1
+ },
+ {
+ "name": "Carry through",
+ "type": "boolean",
+ "value": false
+ }
+ ]
+ },
"Show Base64 offsets": {
"module": "Default",
"description": "When a string is within a block of data and the whole block is Base64'd, the string itself could be represented in Base64 in three distinct ways depending on its offset within the block.
This operation shows all possible offsets for a given string so that each possible encoding can be considered.",
@@ -338,7 +414,7 @@
"module": "Compression",
"description": "Decompresses data using the PKZIP algorithm and displays it per file, with support for passwords.",
"inputType": "byteArray",
- "outputType": "byteArray",
+ "outputType": "html",
"flowControl": false,
"args": [
{
diff --git a/src/core/config/modules/Default.mjs b/src/core/config/modules/Default.mjs
index 34043043..8648aa8a 100644
--- a/src/core/config/modules/Default.mjs
+++ b/src/core/config/modules/Default.mjs
@@ -8,6 +8,10 @@
import FromBase32 from "../../operations/FromBase32";
import FromBase64 from "../../operations/FromBase64";
import FromHex from "../../operations/FromHex";
+import ROT13 from "../../operations/ROT13";
+import ROT47 from "../../operations/ROT47";
+import RotateLeft from "../../operations/RotateLeft";
+import RotateRight from "../../operations/RotateRight";
import ShowBase64Offsets from "../../operations/ShowBase64Offsets";
import ToBase32 from "../../operations/ToBase32";
import ToBase64 from "../../operations/ToBase64";
@@ -19,6 +23,10 @@ OpModules.Default = {
"From Base32": FromBase32,
"From Base64": FromBase64,
"From Hex": FromHex,
+ "ROT13": ROT13,
+ "ROT47": ROT47,
+ "Rotate left": RotateLeft,
+ "Rotate right": RotateRight,
"Show Base64 offsets": ShowBase64Offsets,
"To Base32": ToBase32,
"To Base64": ToBase64,
diff --git a/src/core/lib/Rotate.mjs b/src/core/lib/Rotate.mjs
new file mode 100644
index 00000000..97c4b1df
--- /dev/null
+++ b/src/core/lib/Rotate.mjs
@@ -0,0 +1,112 @@
+/**
+ * Bit rotation functions.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ *
+ * @todo Support for UTF16
+ */
+
+
+/**
+ * Default values for rotation operations
+ */
+export const ROTATE_AMOUNT = 1;
+export const ROTATE_CARRY = false;
+
+
+/**
+ * Runs rotation operations across the input data.
+ *
+ * @param {byteArray} data
+ * @param {number} amount
+ * @param {function} algo - The rotation operation to carry out
+ * @returns {byteArray}
+ */
+export function rot(data, amount, algo) {
+ const result = [];
+ for (let i = 0; i < data.length; i++) {
+ let b = data[i];
+ for (let j = 0; j < amount; j++) {
+ b = algo(b);
+ }
+ result.push(b);
+ }
+ return result;
+}
+
+
+/**
+ * Rotate right bitwise op.
+ *
+ * @param {byte} b
+ * @returns {byte}
+ */
+export function rotr(b) {
+ const bit = (b & 1) << 7;
+ return (b >> 1) | bit;
+}
+
+/**
+ * Rotate left bitwise op.
+ *
+ * @param {byte} b
+ * @returns {byte}
+ */
+export function rotl(b) {
+ const bit = (b >> 7) & 1;
+ return ((b << 1) | bit) & 0xFF;
+}
+
+
+/**
+ * Rotates a byte array to the right by a specific amount as a whole, so that bits are wrapped
+ * from the end of the array to the beginning.
+ *
+ * @private
+ * @param {byteArray} data
+ * @param {number} amount
+ * @returns {byteArray}
+ */
+export function rotrCarry(data, amount) {
+ const result = [];
+ let carryBits = 0,
+ newByte;
+
+ amount = amount % 8;
+ for (let i = 0; i < data.length; i++) {
+ const oldByte = data[i] >>> 0;
+ newByte = (oldByte >> amount) | carryBits;
+ carryBits = (oldByte & (Math.pow(2, amount)-1)) << (8-amount);
+ result.push(newByte);
+ }
+ result[0] |= carryBits;
+ return result;
+}
+
+
+/**
+ * Rotates a byte array to the left by a specific amount as a whole, so that bits are wrapped
+ * from the beginning of the array to the end.
+ *
+ * @private
+ * @param {byteArray} data
+ * @param {number} amount
+ * @returns {byteArray}
+ */
+export function rotlCarry(data, amount) {
+ const result = [];
+ let carryBits = 0,
+ newByte;
+
+ amount = amount % 8;
+ for (let i = data.length-1; i >= 0; i--) {
+ const oldByte = data[i];
+ newByte = ((oldByte << amount) | carryBits) & 0xFF;
+ carryBits = (oldByte >> (8-amount)) & (Math.pow(2, amount)-1);
+ result[i] = (newByte);
+ }
+ result[data.length-1] = result[data.length-1] | carryBits;
+ return result;
+}
diff --git a/src/core/operations/ROT13.mjs b/src/core/operations/ROT13.mjs
new file mode 100644
index 00000000..3bac332a
--- /dev/null
+++ b/src/core/operations/ROT13.mjs
@@ -0,0 +1,110 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * Default arguments for ROT13 operation
+ */
+const ROT13_AMOUNT = 13,
+ ROT13_LOWERCASE = true,
+ ROT13_UPPERCASE = true;
+
+
+/**
+ * ROT13 operation.
+ */
+class ROT13 extends Operation {
+
+ /**
+ * ROT13 constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "ROT13";
+ this.module = "Default";
+ this.description = "A simple caesar substitution cipher which rotates alphabet characters by the specified amount (default 13).";
+ this.inputType = "byteArray";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ name: "Rotate lower case chars",
+ type: "boolean",
+ value: ROT13_LOWERCASE
+ },
+ {
+ name: "Rotate upper case chars",
+ type: "boolean",
+ value: ROT13_UPPERCASE
+ },
+ {
+ name: "Amount",
+ type: "number",
+ value: ROT13_AMOUNT
+ },
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const output = input,
+ rot13Lowercase = args[0],
+ rot13Upperacse = args[1];
+ let amount = args[2],
+ chr;
+
+ if (amount) {
+ if (amount < 0) {
+ amount = 26 - (Math.abs(amount) % 26);
+ }
+
+ for (let i = 0; i < input.length; i++) {
+ chr = input[i];
+ if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
+ chr = (chr - 65 + amount) % 26;
+ output[i] = chr + 65;
+ } else if (rot13Lowercase && chr >= 97 && chr <= 122) { // Lower case
+ chr = (chr - 97 + amount) % 26;
+ output[i] = chr + 97;
+ }
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Highlight ROT13
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ return pos;
+ }
+
+ /**
+ * Highlight ROT13 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 ROT13;
diff --git a/src/core/operations/ROT47.mjs b/src/core/operations/ROT47.mjs
new file mode 100644
index 00000000..0421438b
--- /dev/null
+++ b/src/core/operations/ROT47.mjs
@@ -0,0 +1,93 @@
+/**
+ * @author Matt C [matt@artemisbot.uk]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+
+/**
+ * Default argument for ROT47 operation
+ */
+const ROT47_AMOUNT = 47;
+
+
+/**
+ * ROT47 operation.
+ */
+class ROT47 extends Operation {
+
+ /**
+ * ROT47 constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "ROT47";
+ this.module = "Default";
+ this.description = "A slightly more complex variation of a caesar cipher, which includes ASCII characters from 33 '!' to 126 '~'. Default rotation: 47.";
+ this.inputType = "byteArray";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ name: "Amount",
+ type: "number",
+ value: ROT47_AMOUNT
+ },
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ const output = input;
+ let amount = args[0],
+ chr;
+
+ if (amount) {
+ if (amount < 0) {
+ amount = 94 - (Math.abs(amount) % 94);
+ }
+
+ for (let i = 0; i < input.length; i++) {
+ chr = input[i];
+ if (chr >= 33 && chr <= 126) {
+ chr = (chr - 33 + amount) % 94;
+ output[i] = chr + 33;
+ }
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Highlight ROT47
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ return pos;
+ }
+
+ /**
+ * Highlight ROT47 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 ROT47;
diff --git a/src/core/operations/RotateLeft.mjs b/src/core/operations/RotateLeft.mjs
new file mode 100644
index 00000000..84a14565
--- /dev/null
+++ b/src/core/operations/RotateLeft.mjs
@@ -0,0 +1,80 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import { rot, rotl, rotlCarry, ROTATE_AMOUNT, ROTATE_CARRY } from "../lib/Rotate";
+
+/**
+ * Rotate left operation.
+ */
+class RotateLeft extends Operation {
+
+ /**
+ * RotateLeft constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Rotate left";
+ this.module = "Default";
+ this.description = "Rotates each byte to the left by the number of bits specified, optionally carrying the excess bits over to the next byte. Currently only supports 8-bit values.";
+ this.inputType = "byteArray";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ name: "Amount",
+ type: "number",
+ value: ROTATE_AMOUNT
+ },
+ {
+ name: "Carry through",
+ type: "boolean",
+ value: ROTATE_CARRY
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ if (args[1]) {
+ return rotlCarry(input, args[0]);
+ } else {
+ return rot(input, args[0], rotl);
+ }
+ }
+
+ /**
+ * Highlight rotate left
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ return pos;
+ }
+
+ /**
+ * Highlight rotate left 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 RotateLeft;
diff --git a/src/core/operations/RotateRight.mjs b/src/core/operations/RotateRight.mjs
new file mode 100644
index 00000000..2018c6fc
--- /dev/null
+++ b/src/core/operations/RotateRight.mjs
@@ -0,0 +1,80 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import { rot, rotr, rotrCarry, ROTATE_AMOUNT, ROTATE_CARRY } from "../lib/Rotate";
+
+/**
+ * Rotate right operation.
+ */
+class RotateRight extends Operation {
+
+ /**
+ * RotateRight constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Rotate right";
+ this.module = "Default";
+ this.description = "Rotates each byte to the right by the number of bits specified, optionally carrying the excess bits over to the next byte. Currently only supports 8-bit values.";
+ this.inputType = "byteArray";
+ this.outputType = "byteArray";
+ this.args = [
+ {
+ name: "Amount",
+ type: "number",
+ value: ROTATE_AMOUNT
+ },
+ {
+ name: "Carry through",
+ type: "boolean",
+ value: ROTATE_CARRY
+ }
+ ];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {byteArray}
+ */
+ run(input, args) {
+ if (args[1]) {
+ return rotrCarry(input, args[0]);
+ } else {
+ return rot(input, args[0], rotr);
+ }
+ }
+
+ /**
+ * Highlight rotate right
+ *
+ * @param {Object[]} pos
+ * @param {number} pos[].start
+ * @param {number} pos[].end
+ * @param {Object[]} args
+ * @returns {Object[]} pos
+ */
+ highlight(pos, args) {
+ return pos;
+ }
+
+ /**
+ * Highlight rotate right 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 RotateRight;
diff --git a/src/core/operations/index.mjs b/src/core/operations/index.mjs
index 55a8e79a..5b735963 100644
--- a/src/core/operations/index.mjs
+++ b/src/core/operations/index.mjs
@@ -10,8 +10,12 @@ import FromBase64 from "./FromBase64";
import FromHex from "./FromHex";
import Gunzip from "./Gunzip";
import Gzip from "./Gzip";
+import ROT13 from "./ROT13";
+import ROT47 from "./ROT47";
import RawDeflate from "./RawDeflate";
import RawInflate from "./RawInflate";
+import RotateLeft from "./RotateLeft";
+import RotateRight from "./RotateRight";
import ShowBase64Offsets from "./ShowBase64Offsets";
import ToBase32 from "./ToBase32";
import ToBase64 from "./ToBase64";
@@ -27,8 +31,12 @@ export {
FromHex,
Gunzip,
Gzip,
+ ROT13,
+ ROT47,
RawDeflate,
RawInflate,
+ RotateLeft,
+ RotateRight,
ShowBase64Offsets,
ToBase32,
ToBase64,