From e92ed13864d5e404fa9986e6972b61ca83a7123a Mon Sep 17 00:00:00 2001 From: n1073645 Date: Thu, 21 Nov 2019 12:53:44 +0000 Subject: [PATCH 01/72] PLIST viewer. --- src/core/operations/PLISTViewer.mjs | 56 +++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/core/operations/PLISTViewer.mjs diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs new file mode 100644 index 00000000..1d263468 --- /dev/null +++ b/src/core/operations/PLISTViewer.mjs @@ -0,0 +1,56 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * PLIST Viewer operation + */ +class PLISTViewer extends Operation { + + /** + * PLISTViewer constructor + */ + constructor() { + super(); + + this.name = "PLIST Viewer"; + this.module = "Other"; + this.description = "Converts PLISTXML file into a human readable format."; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + /* Example arguments. See the project wiki for full details. + { + name: "First arg", + type: "string", + value: "Don't Panic" + }, + { + name: "Second arg", + type: "number", + value: 42 + } + */ + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + // const [firstArg, secondArg] = args; + + throw new OperationError("Test"); + } + +} + +export default PLISTViewer; From 63bb19d48d06c8e780ba402f2abb0274e0ecc250 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 22 Nov 2019 08:32:46 +0000 Subject: [PATCH 02/72] Began implementing the PLIST viewer operation --- src/core/config/Categories.json | 1 + src/core/operations/PLISTViewer.mjs | 111 +++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index f663e16d..11e8f076 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -422,6 +422,7 @@ "Frequency distribution", "Index of Coincidence", "Chi Square", + "PLIST Viewer", "Disassemble x86", "Pseudo-Random Number Generator", "Generate UUID", diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs index 1d263468..6229d336 100644 --- a/src/core/operations/PLISTViewer.mjs +++ b/src/core/operations/PLISTViewer.mjs @@ -5,7 +5,6 @@ */ import Operation from "../Operation.mjs"; -import OperationError from "../errors/OperationError.mjs"; /** * PLIST Viewer operation @@ -46,11 +45,115 @@ class PLISTViewer extends Operation { * @returns {string} */ run(input, args) { - // const [firstArg, secondArg] = args; - throw new OperationError("Test"); + const reserved = [["","",8], + ["","",6], + ["","",9], + ["","", 6], + ["","",6], + ["","",7], + ["","",6], + ["","",5], + ["",false,8], + ["",true,7]]; + + function the_viewer(input, dictionary_flag){ + var new_dict = new Array(); + var result = new Array(); + var new_key = null; + while(dictionary_flag ? input.slice(0,7) != "" : input.slice(0,8) != ""){ + reserved.forEach( function (elem, index){ + var element = elem[0]; + var endelement = elem[1]; + var length = elem[2]; + let temp = input.slice(0,length); + if(temp == element){ + input = input.slice(length); + if(temp == ""){ + var returned = the_viewer(input, true); + input = returned[1]; + if(new_key) + new_dict[new_key] = returned[0]; + else + new_dict["plist"] = returned[0]; + new_key = null; + }else if(temp == ""){ + var returned = the_viewer(input, false); + if(dictionary_flag) + new_dict[new_key] = returned[0]; + else + result.push(returned[0]); + input = returned[1]; + new_key = null; + }else if(temp == ""){ + var end = input.indexOf(endelement); + new_key = input.slice(0, end); + input = input.slice(end+length+1); + }else if(temp == "" || temp == ""){ + new_dict[new_key] = endelement; + new_key = null; + }else{ + var end = input.indexOf(endelement); + var toadd = input.slice(0, end); + if(temp == "") + toadd = parseInt(toadd); + else if(temp == "") + toadd = parseFloat(toadd); + if(dictionary_flag){ + new_dict[new_key] = toadd; + new_key = null; + }else{ + result.push(toadd); + } + input = input.slice(end+length+1); + } + } + }); + } + if(dictionary_flag){ + input = input.slice(7); + return [new_dict, input]; + }else{ + input = input.slice(8); + return [result, input]; + } + } + + let result = ""; + function print_it(input, depth) { + Object.keys(input).forEach((key, index) => { + if(typeof(input[key]) == "object") { + result += (("\t".repeat(depth)) + key + ": {\n"); + print_it(input[key], depth+1); + result += (("\t".repeat(depth)) + "}\n"); + } else { + result += (("\t".repeat(depth)) + key + " : " + input[key] + "\n"); + } + }); + } + + while (input.indexOf("/, ""); + } + while (input.indexOf("") !== -1){ + input = input.replace(/<\/plist>/, ""); + } + console.log(input); + while(input.indexOf("\n") !== -1) + input = input.replace("\n", ""); + while(input.indexOf("\t") !== -1) + input = input.replace("\t", ""); + while(input.indexOf(" ") !== -1) + input = input.replace(" ", ""); + console.log(input); + input = input.slice(input.indexOf("")+6); + //return input + var other = the_viewer(input, 1); + print_it(other[0],1); + result = "{\n" + result; + result += "}"; + return result; } - } export default PLISTViewer; From 8e1e1d56cadbb1465a323adec3ac544e9c53f3af Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 22 Nov 2019 15:39:43 +0000 Subject: [PATCH 03/72] Plist viewer operation added. --- src/core/operations/PLISTViewer.mjs | 156 ++++++++++------------------ 1 file changed, 55 insertions(+), 101 deletions(-) diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs index 6229d336..939b7d1a 100644 --- a/src/core/operations/PLISTViewer.mjs +++ b/src/core/operations/PLISTViewer.mjs @@ -46,112 +46,66 @@ class PLISTViewer extends Operation { */ run(input, args) { - const reserved = [["","",8], - ["","",6], - ["","",9], - ["","", 6], - ["","",6], - ["","",7], - ["","",6], - ["","",5], - ["",false,8], - ["",true,7]]; - - function the_viewer(input, dictionary_flag){ - var new_dict = new Array(); - var result = new Array(); - var new_key = null; - while(dictionary_flag ? input.slice(0,7) != "" : input.slice(0,8) != ""){ - reserved.forEach( function (elem, index){ - var element = elem[0]; - var endelement = elem[1]; - var length = elem[2]; - let temp = input.slice(0,length); - if(temp == element){ - input = input.slice(length); - if(temp == ""){ - var returned = the_viewer(input, true); - input = returned[1]; - if(new_key) - new_dict[new_key] = returned[0]; - else - new_dict["plist"] = returned[0]; - new_key = null; - }else if(temp == ""){ - var returned = the_viewer(input, false); - if(dictionary_flag) - new_dict[new_key] = returned[0]; - else - result.push(returned[0]); - input = returned[1]; - new_key = null; - }else if(temp == ""){ - var end = input.indexOf(endelement); - new_key = input.slice(0, end); - input = input.slice(end+length+1); - }else if(temp == "" || temp == ""){ - new_dict[new_key] = endelement; - new_key = null; - }else{ - var end = input.indexOf(endelement); - var toadd = input.slice(0, end); - if(temp == "") - toadd = parseInt(toadd); - else if(temp == "") - toadd = parseFloat(toadd); - if(dictionary_flag){ - new_dict[new_key] = toadd; - new_key = null; - }else{ - result.push(toadd); - } - input = input.slice(end+length+1); - } - } - }); - } - if(dictionary_flag){ - input = input.slice(7); - return [new_dict, input]; - }else{ - input = input.slice(8); - return [result, input]; - } - } - + // Regexes are designed to transform the xml format into a reasonably more readable string format. + input = input.slice(input.indexOf("/g, "plist => ") + .replace(//g, "{") + .replace(/<\/dict>/g, "}") + .replace(//g, "[") + .replace(/<\/array>/g, "]") + .replace(/.+<\/key>/g, m => `${m.slice(5, m.indexOf(/<\/key>/g)-5)}\t=> `) + .replace(/.+<\/real>/g, m => `${m.slice(6, m.indexOf(/<\/real>/g)-6)}\n`) + .replace(/.+<\/string>/g, m => `${m.slice(8, m.indexOf(/<\/string>/g)-8)}\n`) + .replace(/.+<\/integer>/g, m => `${m.slice(9, m.indexOf(/<\/integer>/g)-9)}\n`) + .replace(//g, m => "false") + .replace(//g, m => "true") + .replace(/<\/plist>/g, "/plist") + .replace(/.+<\/date>/g, m => `${m.slice(6, m.indexOf(/<\/integer>/g)-6)}`) + .replace(/(\s|.)+?<\/data>/g, m => `${m.slice(6, m.indexOf(/<\/data>/g)-6)}`) + .replace(/[ \t\r\f\v]/g, ""); + let result = ""; - function print_it(input, depth) { - Object.keys(input).forEach((key, index) => { - if(typeof(input[key]) == "object") { - result += (("\t".repeat(depth)) + key + ": {\n"); - print_it(input[key], depth+1); - result += (("\t".repeat(depth)) + "}\n"); + + /** + * Formats the input after the regex has replaced all of the relevant parts. + * + * @param {array} input + * @param {number} depthCount + */ + function printIt(input, depthCount) { + if (!(input.length)) + return; + + // If the current position points at a larger dynamic structure. + if (input[0].indexOf("=>") !== -1) { + + // If the LHS also points at a larger structure (nested plists in a dictionary). + if (input[1].indexOf("=>") !== -1) { + result += ("\t".repeat(depthCount)) + input[0].slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n"; } else { - result += (("\t".repeat(depth)) + key + " : " + input[key] + "\n"); + result += ("\t".repeat(depthCount)) + input[0].slice(0, -2) + " => " + input[1] + "\n"; } - }); + + // Controls the tab depth for how many opening braces there have been. + if (input[1] === "{" || input[1] === "[") { + depthCount += 1; + } + input = input.slice(1); + } else { + // Controls the tab depth for how many closing braces there have been. + if (input[0] === "}" || input[0] === "]") + depthCount--; + + // Has to be here since the formatting breaks otherwise. + result += ("\t".repeat(depthCount)) + input[0] + "\n"; + if (input[0] === "{" || input[0] === "[") + depthCount++; + } + printIt(input.slice(1), depthCount); } - while (input.indexOf("/, ""); - } - while (input.indexOf("") !== -1){ - input = input.replace(/<\/plist>/, ""); - } - console.log(input); - while(input.indexOf("\n") !== -1) - input = input.replace("\n", ""); - while(input.indexOf("\t") !== -1) - input = input.replace("\t", ""); - while(input.indexOf(" ") !== -1) - input = input.replace(" ", ""); - console.log(input); - input = input.slice(input.indexOf("")+6); - //return input - var other = the_viewer(input, 1); - print_it(other[0],1); - result = "{\n" + result; - result += "}"; + input = input.split("\n").filter(e => e !== ""); + printIt(input, 0); return result; } } From 0295d0c9b47d6cd6b30492ce3b77b3741414cde9 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Mon, 25 Nov 2019 10:35:45 +0000 Subject: [PATCH 04/72] Tided up presentation of the PLIST --- src/core/operations/PLISTViewer.mjs | 71 +++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs index 939b7d1a..8232fb14 100644 --- a/src/core/operations/PLISTViewer.mjs +++ b/src/core/operations/PLISTViewer.mjs @@ -55,7 +55,7 @@ class PLISTViewer extends Operation { .replace(/<\/array>/g, "]") .replace(/.+<\/key>/g, m => `${m.slice(5, m.indexOf(/<\/key>/g)-5)}\t=> `) .replace(/.+<\/real>/g, m => `${m.slice(6, m.indexOf(/<\/real>/g)-6)}\n`) - .replace(/.+<\/string>/g, m => `${m.slice(8, m.indexOf(/<\/string>/g)-8)}\n`) + .replace(/.+<\/string>/g, m => `"${m.slice(8, m.indexOf(/<\/string>/g)-8)}"\n`) .replace(/.+<\/integer>/g, m => `${m.slice(9, m.indexOf(/<\/integer>/g)-9)}\n`) .replace(//g, m => "false") .replace(//g, m => "true") @@ -64,44 +64,77 @@ class PLISTViewer extends Operation { .replace(/(\s|.)+?<\/data>/g, m => `${m.slice(6, m.indexOf(/<\/data>/g)-6)}`) .replace(/[ \t\r\f\v]/g, ""); + /** + * Depending on the type of brace, it will increment the depth and amount of arrays accordingly. + * + * @param {string} elem + * @param {array} vals + * @param {number} offset + */ + function braces(elem, vals,offset) { + let temp = vals.indexOf(elem); + if (temp !== -1) { + depthCount += offset; + if (temp === 1) + arrCount += offset; + } + } + let result = ""; + let arrCount = 0; + let depthCount = 0; /** * Formats the input after the regex has replaced all of the relevant parts. * * @param {array} input - * @param {number} depthCount + * @param {number} index */ - function printIt(input, depthCount) { + function printIt(input, index) { if (!(input.length)) return; + let temp = ""; + const origArr = arrCount; + let currElem = input[0]; + // If the current position points at a larger dynamic structure. - if (input[0].indexOf("=>") !== -1) { + if (currElem.indexOf("=>") !== -1) { // If the LHS also points at a larger structure (nested plists in a dictionary). - if (input[1].indexOf("=>") !== -1) { - result += ("\t".repeat(depthCount)) + input[0].slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n"; - } else { - result += ("\t".repeat(depthCount)) + input[0].slice(0, -2) + " => " + input[1] + "\n"; - } + if (input[1].indexOf("=>") !== -1) + temp = currElem.slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n"; + else + temp = currElem.slice(0, -2) + " => " + input[1] + "\n"; - // Controls the tab depth for how many opening braces there have been. - if (input[1] === "{" || input[1] === "[") { - depthCount += 1; - } input = input.slice(1); } else { // Controls the tab depth for how many closing braces there have been. - if (input[0] === "}" || input[0] === "]") - depthCount--; + + braces(currElem, ["}", "]"], -1); // Has to be here since the formatting breaks otherwise. - result += ("\t".repeat(depthCount)) + input[0] + "\n"; - if (input[0] === "{" || input[0] === "[") - depthCount++; + temp = currElem + "\n"; } - printIt(input.slice(1), depthCount); + + currElem = input[0]; + + // Tab out to the correct distance. + result += ("\t".repeat(depthCount)); + + // If it is enclosed in an array show index. + if (arrCount > 0 && currElem !== "]") + result += index.toString() + " => "; + + result += temp; + + // Controls the tab depth for how many opening braces there have been. + braces(currElem, ["{", "["],1); + + // If there has been a new array then reset index. + if (arrCount > origArr) + return printIt(input.slice(1), 0); + return printIt(input.slice(1), ++index); } input = input.split("\n").filter(e => e !== ""); From d8405e5f814e17319dd293fdcddfdeeca2a43f15 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Mon, 25 Nov 2019 10:37:30 +0000 Subject: [PATCH 05/72] Linting on PLIST viewer operation. --- src/core/operations/PLISTViewer.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs index 8232fb14..b8a90c5b 100644 --- a/src/core/operations/PLISTViewer.mjs +++ b/src/core/operations/PLISTViewer.mjs @@ -71,8 +71,8 @@ class PLISTViewer extends Operation { * @param {array} vals * @param {number} offset */ - function braces(elem, vals,offset) { - let temp = vals.indexOf(elem); + function braces(elem, vals, offset) { + const temp = vals.indexOf(elem); if (temp !== -1) { depthCount += offset; if (temp === 1) @@ -129,7 +129,7 @@ class PLISTViewer extends Operation { result += temp; // Controls the tab depth for how many opening braces there have been. - braces(currElem, ["{", "["],1); + braces(currElem, ["{", "["], 1); // If there has been a new array then reset index. if (arrCount > origArr) From 0259ed8314c0635124d7be316f9e9ec583f4cce0 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Mon, 27 Jan 2020 16:07:54 +0000 Subject: [PATCH 06/72] LS47 implemented, needs linting --- src/core/lib/LS47.mjs | 148 ++++++++++++++++++++++++++++ src/core/operations/LS47Decrypt.mjs | 58 +++++++++++ src/core/operations/LS47Encrypt.mjs | 63 ++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 src/core/lib/LS47.mjs create mode 100644 src/core/operations/LS47Decrypt.mjs create mode 100644 src/core/operations/LS47Encrypt.mjs diff --git a/src/core/lib/LS47.mjs b/src/core/lib/LS47.mjs new file mode 100644 index 00000000..a4ef10a5 --- /dev/null +++ b/src/core/lib/LS47.mjs @@ -0,0 +1,148 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; + +let letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()"; +let tiles = []; + +export function init_tiles() { + for (let i = 0; i < 49; i++) + tiles.push([letters.charAt(i), [Math.floor(i/7), i % 7]]); +} + +function rotate_down(key, col, n) { + let lines = []; + for (let i = 0; i < 7; i++) + lines.push(key.slice(i*7, (i + 1) * 7)); + let lefts = []; + let mids = []; + let rights = []; + lines.forEach((element) => { + lefts.push(element.slice(0, col)); + mids.push(element.charAt(col)); + rights.push(element.slice(col+1)); + }); + n = (7 - n % 7) % 7; + mids = mids.slice(n).concat(mids.slice(0, n)); + let result = ""; + for (let i = 0; i < 7; i++) + result += lefts[i] + mids[i] + rights[i]; + return result; +} + +function rotate_right(key, row, n) { + let mid = key.slice(row * 7, (row + 1) * 7); + n = (7 - n % 7) % 7; + return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1)); +} + +function find_ix(letter) { + for (let i = 0; i < tiles.length; i++) + if (tiles[i][0] === letter) + return tiles[i][1]; + throw new OperationError("Letter " + letter + " is not included in LS47"); +} + +export function derive_key(password) { + let i = 0; + let k = letters; + for (const c of password) { + let [row, col] = find_ix(c); + k = rotate_down(rotate_right(k, i, col), i, row); + i = (i + 1) % 7; + } + return k; +} + +function check_key(key) { + if (key.length !== letters.length) + throw new OperationError("Wrong key size"); + let counts = new Array(); + for (let i = 0; i < letters.length; i++) + counts[letters.charAt(i)] = 0; + for (const elem of letters){ + if (letters.indexOf(elem) === -1) + throw new OperationError("Letter " + elem + " not in LS47!"); + counts[elem]++; + if (counts[elem] > 1) + throw new OperationError("Letter duplicated in the key!"); + } +} + +function find_pos (key, letter) { + let index = key.indexOf(letter); + if (index >= 0 && index < 49) + return [Math.floor(index/7), index%7]; + throw new OperationError("Letter " + letter + " is not in the key!"); +} + +function find_at_pos(key, coord) { + return key.charAt(coord[1] + (coord[0] * 7)); +} + +function add_pos(a, b) { + return [(a[0] + b[0]) % 7, (a[1] + b[1]) % 7]; +} + +function sub_pos(a, b) { + let asub = a[0] - b[0]; + let bsub = a[1] - b[1]; + return [asub - (Math.floor(asub/7) * 7), bsub - (Math.floor(bsub/7) * 7)]; +} + +function encrypt(key, plaintext) { + check_key(key); + let mp = [0, 0]; + let ciphertext = ''; + for (const p of plaintext) { + let pp = find_pos(key, p); + let mix = find_ix(find_at_pos(key, mp)); + let cp = add_pos(pp, mix); + let c = find_at_pos(key, cp); + ciphertext += c; + key = rotate_right(key, pp[0], 1); + cp = find_pos(key, c); + key = rotate_down(key, cp[1], 1); + mp = add_pos(mp, find_ix(c)); + } + return ciphertext; +} + +function decrypt(key, ciphertext) { + check_key(key); + let mp = [0,0]; + let plaintext = ''; + for (const c of ciphertext) { + let cp = find_pos(key, c); + let mix = find_ix(find_at_pos(key, mp)); + let pp = sub_pos(cp, mix); + let p = find_at_pos(key, pp); + + plaintext += p; + key = rotate_right(key, pp[0], 1); + cp = find_pos(key, c); + key = rotate_down(key, cp[1], 1); + mp = add_pos(mp, find_ix(c)); + } + return plaintext; +} + +export function encrypt_pad(key, plaintext, signature, padding_size) { + init_tiles(); + check_key(key); + let padding = ""; + for (let i = 0; i < padding_size; i++) { + padding += letters.charAt(Math.floor(Math.random() * letters.length)); + } + return encrypt(key, padding+plaintext+'---'+signature); +} + +export function decrypt_pad(key, ciphertext, padding_size) { + init_tiles(); + check_key(key); + return decrypt(key, ciphertext).slice(padding_size); +} \ No newline at end of file diff --git a/src/core/operations/LS47Decrypt.mjs b/src/core/operations/LS47Decrypt.mjs new file mode 100644 index 00000000..ffda8f93 --- /dev/null +++ b/src/core/operations/LS47Decrypt.mjs @@ -0,0 +1,58 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import * as LS47 from "../lib/LS47.mjs" + +/** + * LS47 Decrypt operation + */ +class LS47Decrypt extends Operation { + + /** + * LS47Decrypt constructor + */ + constructor() { + super(); + + this.name = "LS47 Decrypt"; + this.module = "Crypto"; + this.description = ""; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Password", + type: "string", + value: "" + }, + { + name: "Padding", + type: "number", + value: 10 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + this.padding_size = parseInt(args[1], 10); + + LS47.init_tiles(); + + let key = LS47.derive_key(args[0]); + return LS47.decrypt_pad(key, input, this.padding_size); + } + +} + +export default LS47Decrypt; diff --git a/src/core/operations/LS47Encrypt.mjs b/src/core/operations/LS47Encrypt.mjs new file mode 100644 index 00000000..bf3b0306 --- /dev/null +++ b/src/core/operations/LS47Encrypt.mjs @@ -0,0 +1,63 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import * as LS47 from "../lib/LS47.mjs" + +/** + * LS47 Encrypt operation + */ +class LS47Encrypt extends Operation { + + /** + * LS47Encrypt constructor + */ + constructor() { + super(); + + this.name = "LS47 Encrypt"; + this.module = "Crypto"; + this.description = ""; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Password", + type: "string", + value: "" + }, + { + name: "Padding", + type: "number", + value: 10 + }, + { + name: "Signature", + type: "string", + value: "" + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + this.padding_size = parseInt(args[1], 10); + + LS47.init_tiles(); + + let key = LS47.derive_key(args[0]); + return LS47.encrypt_pad(key, input, args[2], this.padding_size); + } + +} + +export default LS47Encrypt; From 5cdd062ed9c639bf387c783667d8bd86302e8acb Mon Sep 17 00:00:00 2001 From: n1073645 Date: Tue, 28 Jan 2020 09:33:32 +0000 Subject: [PATCH 07/72] Linting done --- src/core/config/Categories.json | 2 + src/core/lib/LS47.mjs | 153 ++++++++++++++++++---------- src/core/operations/LS47Decrypt.mjs | 12 +-- src/core/operations/LS47Encrypt.mjs | 14 +-- 4 files changed, 112 insertions(+), 69 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 53ca796d..1b810d37 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -75,6 +75,8 @@ "DES Decrypt", "Triple DES Encrypt", "Triple DES Decrypt", + "LS47 Encrypt", + "LS47 Decrypt", "RC2 Encrypt", "RC2 Decrypt", "RC4", diff --git a/src/core/lib/LS47.mjs b/src/core/lib/LS47.mjs index a4ef10a5..b028fc4f 100644 --- a/src/core/lib/LS47.mjs +++ b/src/core/lib/LS47.mjs @@ -6,21 +6,27 @@ import OperationError from "../errors/OperationError.mjs"; -let letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()"; -let tiles = []; +const letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()"; +const tiles = []; -export function init_tiles() { +/** + * + */ +export function initTiles() { for (let i = 0; i < 49; i++) tiles.push([letters.charAt(i), [Math.floor(i/7), i % 7]]); } -function rotate_down(key, col, n) { - let lines = []; - for (let i = 0; i < 7; i++) +/** + * + */ +function rotateDown(key, col, n) { + const lines = []; + for (let i = 0; i < 7; i++) lines.push(key.slice(i*7, (i + 1) * 7)); - let lefts = []; + const lefts = []; let mids = []; - let rights = []; + const rights = []; lines.forEach((element) => { lefts.push(element.slice(0, col)); mids.push(element.charAt(col)); @@ -34,37 +40,49 @@ function rotate_down(key, col, n) { return result; } -function rotate_right(key, row, n) { - let mid = key.slice(row * 7, (row + 1) * 7); +/** + * + */ +function rotateRight(key, row, n) { + const mid = key.slice(row * 7, (row + 1) * 7); n = (7 - n % 7) % 7; return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1)); } -function find_ix(letter) { +/** + * + */ +function findIx(letter) { for (let i = 0; i < tiles.length; i++) if (tiles[i][0] === letter) return tiles[i][1]; throw new OperationError("Letter " + letter + " is not included in LS47"); } -export function derive_key(password) { +/** + * + */ +export function deriveKey(password) { let i = 0; let k = letters; for (const c of password) { - let [row, col] = find_ix(c); - k = rotate_down(rotate_right(k, i, col), i, row); + const [row, col] = findIx(c); + k = rotateDown(rotateRight(k, i, col), i, row); i = (i + 1) % 7; } return k; } -function check_key(key) { +/** + * + */ +function checkKey(key) { if (key.length !== letters.length) throw new OperationError("Wrong key size"); - let counts = new Array(); + const counts = new Array(); for (let i = 0; i < letters.length; i++) counts[letters.charAt(i)] = 0; - for (const elem of letters){ + for (const elem of letters) { if (letters.indexOf(elem) === -1) throw new OperationError("Letter " + elem + " not in LS47!"); counts[elem]++; @@ -73,76 +91,99 @@ function check_key(key) { } } -function find_pos (key, letter) { - let index = key.indexOf(letter); +/** + * + */ +function findPos (key, letter) { + const index = key.indexOf(letter); if (index >= 0 && index < 49) return [Math.floor(index/7), index%7]; throw new OperationError("Letter " + letter + " is not in the key!"); } -function find_at_pos(key, coord) { +/** + * + */ +function findAtPos(key, coord) { return key.charAt(coord[1] + (coord[0] * 7)); } -function add_pos(a, b) { +/** + * + */ +function addPos(a, b) { return [(a[0] + b[0]) % 7, (a[1] + b[1]) % 7]; } -function sub_pos(a, b) { - let asub = a[0] - b[0]; - let bsub = a[1] - b[1]; +/** + * + */ +function subPos(a, b) { + const asub = a[0] - b[0]; + const bsub = a[1] - b[1]; return [asub - (Math.floor(asub/7) * 7), bsub - (Math.floor(bsub/7) * 7)]; } +/** + * + */ function encrypt(key, plaintext) { - check_key(key); + checkKey(key); let mp = [0, 0]; - let ciphertext = ''; + let ciphertext = ""; for (const p of plaintext) { - let pp = find_pos(key, p); - let mix = find_ix(find_at_pos(key, mp)); - let cp = add_pos(pp, mix); - let c = find_at_pos(key, cp); + const pp = findPos(key, p); + const mix = findIx(findAtPos(key, mp)); + let cp = addPos(pp, mix); + const c = findAtPos(key, cp); ciphertext += c; - key = rotate_right(key, pp[0], 1); - cp = find_pos(key, c); - key = rotate_down(key, cp[1], 1); - mp = add_pos(mp, find_ix(c)); + key = rotateRight(key, pp[0], 1); + cp = findPos(key, c); + key = rotateDown(key, cp[1], 1); + mp = addPos(mp, findIx(c)); } return ciphertext; } +/** + * + */ function decrypt(key, ciphertext) { - check_key(key); - let mp = [0,0]; - let plaintext = ''; + checkKey(key); + let mp = [0, 0]; + let plaintext = ""; for (const c of ciphertext) { - let cp = find_pos(key, c); - let mix = find_ix(find_at_pos(key, mp)); - let pp = sub_pos(cp, mix); - let p = find_at_pos(key, pp); - + let cp = findPos(key, c); + const mix = findIx(findAtPos(key, mp)); + const pp = subPos(cp, mix); + const p = findAtPos(key, pp); plaintext += p; - key = rotate_right(key, pp[0], 1); - cp = find_pos(key, c); - key = rotate_down(key, cp[1], 1); - mp = add_pos(mp, find_ix(c)); + key = rotateRight(key, pp[0], 1); + cp = findPos(key, c); + key = rotateDown(key, cp[1], 1); + mp = addPos(mp, findIx(c)); } return plaintext; } -export function encrypt_pad(key, plaintext, signature, padding_size) { - init_tiles(); - check_key(key); +/** + * + */ +export function encryptPad(key, plaintext, signature, paddingSize) { + initTiles(); + checkKey(key); let padding = ""; - for (let i = 0; i < padding_size; i++) { + for (let i = 0; i < paddingSize; i++) { padding += letters.charAt(Math.floor(Math.random() * letters.length)); } - return encrypt(key, padding+plaintext+'---'+signature); + return encrypt(key, padding+plaintext+"---"+signature); } -export function decrypt_pad(key, ciphertext, padding_size) { - init_tiles(); - check_key(key); - return decrypt(key, ciphertext).slice(padding_size); -} \ No newline at end of file +/** + * + */ +export function decryptPad(key, ciphertext, paddingSize) { + initTiles(); + checkKey(key); + return decrypt(key, ciphertext).slice(paddingSize); +} diff --git a/src/core/operations/LS47Decrypt.mjs b/src/core/operations/LS47Decrypt.mjs index ffda8f93..a5a92ebf 100644 --- a/src/core/operations/LS47Decrypt.mjs +++ b/src/core/operations/LS47Decrypt.mjs @@ -5,7 +5,7 @@ */ import Operation from "../Operation.mjs"; -import * as LS47 from "../lib/LS47.mjs" +import * as LS47 from "../lib/LS47.mjs"; /** * LS47 Decrypt operation @@ -45,12 +45,12 @@ class LS47Decrypt extends Operation { */ run(input, args) { - this.padding_size = parseInt(args[1], 10); + this.paddingSize = parseInt(args[1], 10); - LS47.init_tiles(); - - let key = LS47.derive_key(args[0]); - return LS47.decrypt_pad(key, input, this.padding_size); + LS47.initTiles(); + + const key = LS47.deriveKey(args[0]); + return LS47.decryptPad(key, input, this.paddingSize); } } diff --git a/src/core/operations/LS47Encrypt.mjs b/src/core/operations/LS47Encrypt.mjs index bf3b0306..f82baaab 100644 --- a/src/core/operations/LS47Encrypt.mjs +++ b/src/core/operations/LS47Encrypt.mjs @@ -5,7 +5,7 @@ */ import Operation from "../Operation.mjs"; -import * as LS47 from "../lib/LS47.mjs" +import * as LS47 from "../lib/LS47.mjs"; /** * LS47 Encrypt operation @@ -49,13 +49,13 @@ class LS47Encrypt extends Operation { * @returns {string} */ run(input, args) { - - this.padding_size = parseInt(args[1], 10); - LS47.init_tiles(); - - let key = LS47.derive_key(args[0]); - return LS47.encrypt_pad(key, input, args[2], this.padding_size); + this.paddingSize = parseInt(args[1], 10); + + LS47.initTiles(); + + const key = LS47.deriveKey(args[0]); + return LS47.encryptPad(key, input, args[2], this.paddingSize); } } From 6fd929160d9eb5ee332af80c90e823513b0a86f1 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Tue, 28 Jan 2020 10:35:01 +0000 Subject: [PATCH 08/72] Comments and linting. --- src/core/lib/LS47.mjs | 57 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/core/lib/LS47.mjs b/src/core/lib/LS47.mjs index b028fc4f..6696aafc 100644 --- a/src/core/lib/LS47.mjs +++ b/src/core/lib/LS47.mjs @@ -10,7 +10,7 @@ const letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()"; const tiles = []; /** - * + * Initialises the tiles with values and positions. */ export function initTiles() { for (let i = 0; i < 49; i++) @@ -18,7 +18,12 @@ export function initTiles() { } /** + * Rotates the key "down". * + * @param {string} key + * @param {number} col + * @param {number} n + * @returns {string} */ function rotateDown(key, col, n) { const lines = []; @@ -41,7 +46,12 @@ function rotateDown(key, col, n) { } /** + * Rotates the key "right". * + * @param {string} key + * @param {number} row + * @param {number} n + * @returns {string} */ function rotateRight(key, row, n) { const mid = key.slice(row * 7, (row + 1) * 7); @@ -50,7 +60,10 @@ function rotateRight(key, row, n) { } /** + * Finds the position of a letter in the tiles. * + * @param {string} letter + * @returns {string} */ function findIx(letter) { for (let i = 0; i < tiles.length; i++) @@ -60,7 +73,10 @@ function findIx(letter) { } /** + * Derives key from the input password. * + * @param {string} password + * @returns {string} */ export function deriveKey(password) { let i = 0; @@ -74,7 +90,9 @@ export function deriveKey(password) { } /** + * Checks the key is a valid key. * + * @param {string} key */ function checkKey(key) { if (key.length !== letters.length) @@ -92,7 +110,11 @@ function checkKey(key) { } /** + * Finds the position of a letter in they key. * + * @param {letter} key + * @param {string} letter + * @returns {object} */ function findPos (key, letter) { const index = key.indexOf(letter); @@ -102,21 +124,35 @@ function findPos (key, letter) { } /** + * Returns the character at the position on the tiles. * + * @param {string} key + * @param {object} coord + * @returns {string} */ function findAtPos(key, coord) { return key.charAt(coord[1] + (coord[0] * 7)); } /** + * Returns new position by adding two positions. * + * @param {object} a + * @param {object} b + * @returns {object} */ function addPos(a, b) { return [(a[0] + b[0]) % 7, (a[1] + b[1]) % 7]; } /** + * Returns new position by subtracting two positions. + * Note: We have to manually do the remainder division, since JS does not + * operate correctly on negative numbers (e.g. -3 % 4 = -3 when it should be 1). * + * @param {object} a + * @param {object} b + * @returns {object} */ function subPos(a, b) { const asub = a[0] - b[0]; @@ -125,7 +161,11 @@ function subPos(a, b) { } /** + * Encrypts the plaintext string. * + * @param {string} key + * @param {string} plaintext + * @returns {string} */ function encrypt(key, plaintext) { checkKey(key); @@ -146,7 +186,11 @@ function encrypt(key, plaintext) { } /** + * Decrypts the ciphertext string. * + * @param {string} key + * @param {string} ciphertext + * @returns {string} */ function decrypt(key, ciphertext) { checkKey(key); @@ -167,7 +211,13 @@ function decrypt(key, ciphertext) { } /** + * Adds padding to the input. * + * @param {string} key + * @param {string} plaintext + * @param {string} signature + * @param {number} paddingSize + * @returns {string} */ export function encryptPad(key, plaintext, signature, paddingSize) { initTiles(); @@ -180,7 +230,12 @@ export function encryptPad(key, plaintext, signature, paddingSize) { } /** + * Removes padding from the ouput. * + * @param {string} key + * @param {string} ciphertext + * @param {number} paddingSize + * @returns {string} */ export function decryptPad(key, ciphertext, paddingSize) { initTiles(); From e71794d362cf8112fc940a2ae6177c84ffce3bb5 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 14 Feb 2020 12:28:12 +0000 Subject: [PATCH 09/72] Tests added for LS47 --- src/core/operations/LS47Decrypt.mjs | 4 +-- src/core/operations/LS47Encrypt.mjs | 4 +-- tests/operations/index.mjs | 1 + tests/operations/tests/LS47.mjs | 45 +++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/operations/tests/LS47.mjs diff --git a/src/core/operations/LS47Decrypt.mjs b/src/core/operations/LS47Decrypt.mjs index a5a92ebf..cb92cd27 100644 --- a/src/core/operations/LS47Decrypt.mjs +++ b/src/core/operations/LS47Decrypt.mjs @@ -20,8 +20,8 @@ class LS47Decrypt extends Operation { this.name = "LS47 Decrypt"; this.module = "Crypto"; - this.description = ""; - this.infoURL = ""; + this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.\nThe LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\nA LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; + this.infoURL = "https://gitea.blesmrt.net/exa/ls47/src/branch/master"; this.inputType = "string"; this.outputType = "string"; this.args = [ diff --git a/src/core/operations/LS47Encrypt.mjs b/src/core/operations/LS47Encrypt.mjs index f82baaab..51283844 100644 --- a/src/core/operations/LS47Encrypt.mjs +++ b/src/core/operations/LS47Encrypt.mjs @@ -20,8 +20,8 @@ class LS47Encrypt extends Operation { this.name = "LS47 Encrypt"; this.module = "Crypto"; - this.description = ""; - this.infoURL = ""; + this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.\nThe LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\nA LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; + this.infoURL = "https://gitea.blesmrt.net/exa/ls47/src/branch/master"; this.inputType = "string"; this.outputType = "string"; this.args = [ diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index bf440414..b3731727 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -96,6 +96,7 @@ import "./tests/DefangIP.mjs"; import "./tests/ParseUDP.mjs"; import "./tests/AvroToJSON.mjs"; import "./tests/Lorenz.mjs"; +import "./tests/LS47.mjs"; // Cannot test operations that use the File type yet diff --git a/tests/operations/tests/LS47.mjs b/tests/operations/tests/LS47.mjs new file mode 100644 index 00000000..40d876ee --- /dev/null +++ b/tests/operations/tests/LS47.mjs @@ -0,0 +1,45 @@ +/** + * Cartesian Product tests. + * + * @author n1073645 [n1073645@gmail.com] + * + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "LS47 Encrypt", + input: "thequickbrownfoxjumped", + expectedOutput: "(,t74ci78cp/8trx*yesu:alp1wqy", + recipeConfig: [ + { + op: "LS47 Encrypt", + args: ["helloworld", 0, "test"], + }, + ], + }, + { + name: "LS47 Decrypt", + input: "(,t74ci78cp/8trx*yesu:alp1wqy", + expectedOutput: "thequickbrownfoxjumped---test", + recipeConfig: [ + { + op: "LS47 Decrypt", + args: ["helloworld", 0], + }, + ], + }, + { + name: "LS47 Encrypt", + input: "thequickbrownfoxjumped", + expectedOutput: "Letter H is not included in LS47", + recipeConfig: [ + { + op: "LS47 Encrypt", + args: ["Helloworld", 0, "test"], + }, + ], + } +]); From e91e993fb5e7ec99db8fcb179fbd18a3f53b97bc Mon Sep 17 00:00:00 2001 From: n1073645 <57447333+n1073645@users.noreply.github.com> Date: Fri, 14 Feb 2020 13:43:30 +0000 Subject: [PATCH 10/72] Update LS47.mjs --- tests/operations/tests/LS47.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/operations/tests/LS47.mjs b/tests/operations/tests/LS47.mjs index 40d876ee..ce613923 100644 --- a/tests/operations/tests/LS47.mjs +++ b/tests/operations/tests/LS47.mjs @@ -1,5 +1,5 @@ /** - * Cartesian Product tests. + * LS47 tests. * * @author n1073645 [n1073645@gmail.com] * From 0182cdda69f7c877746084a75600d87b2cb34e19 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Sat, 16 May 2020 00:42:02 +0200 Subject: [PATCH 11/72] Base85: Fix alphabetName --- src/core/lib/Base85.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/lib/Base85.mjs b/src/core/lib/Base85.mjs index 8da729e2..e5778132 100644 --- a/src/core/lib/Base85.mjs +++ b/src/core/lib/Base85.mjs @@ -1,3 +1,5 @@ +import Utils from "../Utils.mjs"; + /** * Base85 resources. * @@ -32,13 +34,12 @@ export const ALPHABET_OPTIONS = [ * @returns {string} */ export function alphabetName(alphabet) { - alphabet = alphabet.replace("'", "'"); - alphabet = alphabet.replace("\"", """); - alphabet = alphabet.replace("\\", "\"); + alphabet = escape(alphabet); let name; ALPHABET_OPTIONS.forEach(function(a) { - if (escape(alphabet) === escape(a.value)) name = a.name; + const expanded = Utils.expandAlphRange(a.value).join(""); + if (alphabet === escape(expanded)) name = a.name; }); return name; From 103ecff6a7465b7a46a8f452885ec99d0e45ea26 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Sat, 16 May 2020 00:42:31 +0200 Subject: [PATCH 12/72] Base85: Ignore whitespace --- src/core/operations/FromBase85.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index c874d5dc..c0d0328e 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -52,6 +52,8 @@ class FromBase85 extends Operation { if (input.length === 0) return []; + input = input.replace(/\s+/g, ""); + const matches = input.match(/<~(.+?)~>/); if (matches !== null) input = matches[1]; From 15dd9d4c93fa5bcfb1341ad8dccdb5671ae08d22 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Sat, 16 May 2020 00:42:50 +0200 Subject: [PATCH 13/72] Add magic checks for base85 --- src/core/operations/FromBase85.mjs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index c0d0328e..42f37a1c 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -33,6 +33,23 @@ class FromBase85 extends Operation { value: ALPHABET_OPTIONS }, ]; + this.checks = [ + { + pattern: "^\\s*(?:<~)?(?:(?:\\s*[!-u]){5}|\\s*z)+[!-u\\s]*(?:~>)?\\s*$", + flags: "i", + args: ["!-u"] + }, + { + pattern: "^(?:\\s*[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#])+\\s*$", + flags: "i", + args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"] + }, + { + pattern: "^(?:\\s*[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~])+\\s*$", + flags: "i", + args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"] + }, + ]; } /** From eab1be0e2c58c3d69f8b2c477e4102f601b611c7 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Wed, 20 May 2020 00:23:50 +0200 Subject: [PATCH 14/72] Magic base85: Remove 'i' flag --- src/core/operations/FromBase85.mjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index 42f37a1c..22033f99 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -36,17 +36,14 @@ class FromBase85 extends Operation { this.checks = [ { pattern: "^\\s*(?:<~)?(?:(?:\\s*[!-u]){5}|\\s*z)+[!-u\\s]*(?:~>)?\\s*$", - flags: "i", args: ["!-u"] }, { pattern: "^(?:\\s*[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#])+\\s*$", - flags: "i", args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"] }, { pattern: "^(?:\\s*[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~])+\\s*$", - flags: "i", args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"] }, ]; From 1294d764e258bb6caa739b6111bb6d79a61d394f Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Fri, 22 May 2020 03:30:15 +0200 Subject: [PATCH 15/72] Base85: Only remove start and end markers with standard/ascii85 encoding --- src/core/operations/FromBase85.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index 22033f99..09ded171 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -68,8 +68,10 @@ class FromBase85 extends Operation { input = input.replace(/\s+/g, ""); - const matches = input.match(/<~(.+?)~>/); - if (matches !== null) input = matches[1]; + if (encoding === "Standard") { + const matches = input.match(/<~(.+?)~>/); + if (matches !== null) input = matches[1]; + } let i = 0; let block, blockBytes; From ee408f7add6d633b9c42a6677f5bfa75055e9ca6 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Fri, 22 May 2020 03:30:57 +0200 Subject: [PATCH 16/72] Base85: Update magic regexes to require 20 non-whitespace base85 chars --- src/core/operations/FromBase85.mjs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index 09ded171..9d73baa1 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -35,16 +35,31 @@ class FromBase85 extends Operation { ]; this.checks = [ { - pattern: "^\\s*(?:<~)?(?:(?:\\s*[!-u]){5}|\\s*z)+[!-u\\s]*(?:~>)?\\s*$", - args: ["!-u"] + pattern: + "^\\s*(?:<~)?" + // Optional whitespace and starting marker + "[\\s!-uz]*" + // Any amount of base85 characters and whitespace + "[!-uz]{20}" + // At least 20 continoues base85 characters without whitespace + "[\\s!-uz]*" + // Any amount of base85 characters and whitespace + "(?:~>)?\\s*$", // Optional ending marker and whitespace + args: ["!-u"], }, { - pattern: "^(?:\\s*[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#])+\\s*$", - args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"] + pattern: + "^" + + "[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" + + "[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]{20}" + // At least 20 continoues base85 characters without whitespace + "[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" + + "$", + args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"], }, { - pattern: "^(?:\\s*[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~])+\\s*$", - args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"] + pattern: + "^" + + "[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" + + "[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]{20}" + // At least 20 continoues base85 characters without whitespace + "[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" + + "$", + args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"], }, ]; } From f5a7db03cd8ab8bf9e7bbd43ec47ae9c57975a37 Mon Sep 17 00:00:00 2001 From: Benedikt Werner <1benediktwerner@gmail.com> Date: Wed, 10 Jun 2020 15:50:26 +0200 Subject: [PATCH 17/72] Base85: Only require 15 continuous base85 chars --- src/core/operations/FromBase85.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index 9d73baa1..3555b020 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -38,7 +38,7 @@ class FromBase85 extends Operation { pattern: "^\\s*(?:<~)?" + // Optional whitespace and starting marker "[\\s!-uz]*" + // Any amount of base85 characters and whitespace - "[!-uz]{20}" + // At least 20 continoues base85 characters without whitespace + "[!-uz]{15}" + // At least 15 continoues base85 characters without whitespace "[\\s!-uz]*" + // Any amount of base85 characters and whitespace "(?:~>)?\\s*$", // Optional ending marker and whitespace args: ["!-u"], @@ -47,7 +47,7 @@ class FromBase85 extends Operation { pattern: "^" + "[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" + - "[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]{20}" + // At least 20 continoues base85 characters without whitespace + "[0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]{15}" + // At least 15 continoues base85 characters without whitespace "[\\s0-9a-zA-Z.\\-:+=^!/*?&<>()[\\]{}@%$#]*" + "$", args: ["0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#"], @@ -56,7 +56,7 @@ class FromBase85 extends Operation { pattern: "^" + "[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" + - "[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]{20}" + // At least 20 continoues base85 characters without whitespace + "[0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]{15}" + // At least 15 continoues base85 characters without whitespace "[\\s0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~]*" + "$", args: ["0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~"], From 3e3c526a625cabeae64d8f3b61f88d326e98473a Mon Sep 17 00:00:00 2001 From: n1073645 Date: Mon, 6 Jul 2020 16:35:14 +0100 Subject: [PATCH 18/72] Caesar Box Cipher Added --- src/core/config/Categories.json | 1 + src/core/operations/CaesarBoxCipher.mjs | 61 ++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/CaesarBoxCipher.mjs | 45 ++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 src/core/operations/CaesarBoxCipher.mjs create mode 100644 tests/operations/tests/CaesarBoxCipher.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 77e3d319..36465ced 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -91,6 +91,7 @@ "Bacon Cipher Decode", "Bifid Cipher Encode", "Bifid Cipher Decode", + "Caesar Box Cipher", "Affine Cipher Encode", "Affine Cipher Decode", "A1Z26 Cipher Encode", diff --git a/src/core/operations/CaesarBoxCipher.mjs b/src/core/operations/CaesarBoxCipher.mjs new file mode 100644 index 00000000..2e4d9830 --- /dev/null +++ b/src/core/operations/CaesarBoxCipher.mjs @@ -0,0 +1,61 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Caesar Box Cipher operation + */ +class CaesarBoxCipher extends Operation { + + /** + * CaesarBoxCipher constructor + */ + constructor() { + super(); + + this.name = "Caesar Box Cipher"; + this.module = "Ciphers"; + this.description = ""; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Box Height", + type: "number", + value: 1 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const tableHeight = args[0]; + const tableWidth = Math.ceil(input.length / tableHeight); + while (input.indexOf(" ") !== -1) + input = input.replace(" ", ""); + for (let i = 0; i < (tableHeight * tableWidth) - input.length; i++) { + input += "\x00"; + } + let result = ""; + for (let i = 0; i < tableHeight; i++) { + for (let j = i; j < input.length; j += tableHeight) { + if (input.charAt(j) !== "\x00") { + result += input.charAt(j); + } + } + } + return result; + } + +} + +export default CaesarBoxCipher; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 8d3cd623..bd6cd3ed 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -101,6 +101,7 @@ import "./tests/LuhnChecksum.mjs"; import "./tests/CipherSaber2.mjs"; import "./tests/Colossus.mjs"; import "./tests/ParseObjectIDTimestamp.mjs"; +import "./tests/CaesarBoxCipher.mjs"; // Cannot test operations that use the File type yet diff --git a/tests/operations/tests/CaesarBoxCipher.mjs b/tests/operations/tests/CaesarBoxCipher.mjs new file mode 100644 index 00000000..3ccdae66 --- /dev/null +++ b/tests/operations/tests/CaesarBoxCipher.mjs @@ -0,0 +1,45 @@ +/** + * Base58 tests. + * + * @author n1073645 [n1073645@gmail.com] + * + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Caesar Box Cipher: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + op: "Caesar Box Cipher", + args: ["1"], + }, + ], + }, + { + name: "Caesar Box Cipher: Hello World!", + input: "Hello World!", + expectedOutput: "Hlodeor!lWl", + recipeConfig: [ + { + op: "Caesar Box Cipher", + args: ["3"], + }, + ], + }, + { + name: "Caesar Box Cipher: Hello World!", + input: "Hlodeor!lWl", + expectedOutput: "HelloWorld!", + recipeConfig: [ + { + op: "Caesar Box Cipher", + args: ["4"], + }, + ], + } +]); From 667dfd820e5e2b93a5daf4258f547d6a0a605a37 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Mon, 6 Jul 2020 16:46:40 +0100 Subject: [PATCH 19/72] info url added --- src/core/operations/CaesarBoxCipher.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/operations/CaesarBoxCipher.mjs b/src/core/operations/CaesarBoxCipher.mjs index 2e4d9830..9c835b4b 100644 --- a/src/core/operations/CaesarBoxCipher.mjs +++ b/src/core/operations/CaesarBoxCipher.mjs @@ -19,8 +19,8 @@ class CaesarBoxCipher extends Operation { this.name = "Caesar Box Cipher"; this.module = "Ciphers"; - this.description = ""; - this.infoURL = ""; + this.description = "Caesar Box Encryption uses a box, a rectangle (or a square), or at least a size W caracterizing its width."; + this.infoURL = "https://www.dcode.fr/caesar-box-cipher"; this.inputType = "string"; this.outputType = "string"; this.args = [ From e8f91316ffd280715a3e90177a5b04068689883d Mon Sep 17 00:00:00 2001 From: MikeCAT Date: Wed, 20 Oct 2021 21:28:48 +0900 Subject: [PATCH 20/72] Added ROT13/47 Brute Force --- src/core/config/Categories.json | 2 + src/core/operations/ROT13BruteForce.mjs | 102 ++++++++++++++++++++++++ src/core/operations/ROT47BruteForce.mjs | 82 +++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 src/core/operations/ROT13BruteForce.mjs create mode 100644 src/core/operations/ROT47BruteForce.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 09ee8d15..1369267a 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -82,7 +82,9 @@ "RC4", "RC4 Drop", "ROT13", + "ROT13 Brute Force", "ROT47", + "ROT47 Brute Force", "XOR", "XOR Brute Force", "Vigenère Encode", diff --git a/src/core/operations/ROT13BruteForce.mjs b/src/core/operations/ROT13BruteForce.mjs new file mode 100644 index 00000000..bdf9d40a --- /dev/null +++ b/src/core/operations/ROT13BruteForce.mjs @@ -0,0 +1,102 @@ +/** + * @author MikeCAT + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; + +/** + * ROT13 Brute Force operation. + */ +class ROT13BruteForce extends Operation { + + /** + * ROT13BruteForce constructor + */ + constructor() { + super(); + + this.name = "ROT13 Brute Force"; + this.module = "Default"; + this.description = "Try all meaningful amounts for ROT13.

Optionally you can enter your known plaintext (crib) to filter the result."; + this.infoURL = "https://wikipedia.org/wiki/ROT13"; + this.inputType = "byteArray"; + this.outputType = "string"; + this.args = [ + { + name: "Rotate lower case chars", + type: "boolean", + value: true + }, + { + name: "Rotate upper case chars", + type: "boolean", + value: true + }, + { + name: "Rotate numbers", + type: "boolean", + value: false + }, + { + "name": "Sample length", + "type": "number", + "value": 100 + }, + { + "name": "Sample offset", + "type": "number", + "value": 0 + }, + { + "name": "Print amount", + "type": "boolean", + "value": true + }, + { + "name": "Crib (known plaintext string)", + "type": "string", + "value": "" + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [rotateLower, rotateUpper, rotateNum, sampleLength, sampleOffset, printAmount, crib] = args; + const sample = input.slice(sampleOffset, sampleOffset + sampleLength); + const cribLower = crib.toLowerCase(); + const lowerStart = "a".charCodeAt(0), upperStart = "A".charCodeAt(0), numStart = "0".charCodeAt(0); + const result = []; + for (let amount = 1; amount < 26; amount++) { + const rotated = sample.slice(); + for (let i = 0; i < rotated.length; i++) { + if (rotateLower && lowerStart <= rotated[i] && rotated[i] < lowerStart + 26) { + rotated[i] = (rotated[i] - lowerStart + amount) % 26 + lowerStart; + } else if (rotateUpper && upperStart <= rotated[i] && rotated[i] < upperStart + 26) { + rotated[i] = (rotated[i] - upperStart + amount) % 26 + upperStart; + } else if (rotateNum && numStart <= rotated[i] && rotated[i] < numStart + 10) { + rotated[i] = (rotated[i] - numStart + amount) % 10 + numStart; + } + } + const rotatedString = Utils.byteArrayToUtf8(rotated); + if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) { + const rotatedStringPrintable = Utils.printable(rotatedString, false); + if (printAmount) { + const amountStr = "Amount = " + (" " + amount).slice(-2) + ": "; + result.push(amountStr + rotatedStringPrintable); + } else { + result.push(rotatedStringPrintable); + } + } + } + return result.join("\n"); + } +} + +export default ROT13BruteForce; diff --git a/src/core/operations/ROT47BruteForce.mjs b/src/core/operations/ROT47BruteForce.mjs new file mode 100644 index 00000000..5fce5259 --- /dev/null +++ b/src/core/operations/ROT47BruteForce.mjs @@ -0,0 +1,82 @@ +/** + * @author MikeCAT + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; + +/** + * ROT47 Brute Force operation. + */ +class ROT47BruteForce extends Operation { + + /** + * ROT47BruteForce constructor + */ + constructor() { + super(); + + this.name = "ROT47 Brute Force"; + this.module = "Default"; + this.description = "Try all meaningful amounts for ROT47.

Optionally you can enter your known plaintext (crib) to filter the result."; + this.infoURL = "https://wikipedia.org/wiki/ROT13#Variants"; + this.inputType = "byteArray"; + this.outputType = "string"; + this.args = [ + { + "name": "Sample length", + "type": "number", + "value": 100 + }, + { + "name": "Sample offset", + "type": "number", + "value": 0 + }, + { + "name": "Print amount", + "type": "boolean", + "value": true + }, + { + "name": "Crib (known plaintext string)", + "type": "string", + "value": "" + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [sampleLength, sampleOffset, printAmount, crib] = args; + const sample = input.slice(sampleOffset, sampleOffset + sampleLength); + const cribLower = crib.toLowerCase(); + const result = []; + for (let amount = 1; amount < 94; amount++) { + const rotated = sample.slice(); + for (let i = 0; i < rotated.length; i++) { + if (33 <= rotated[i] && rotated[i] <= 126) { + rotated[i] = (rotated[i] - 33 + amount) % 94 + 33; + } + } + const rotatedString = Utils.byteArrayToUtf8(rotated); + if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) { + const rotatedStringPrintable = Utils.printable(rotatedString, false); + if (printAmount) { + const amountStr = "Amount = " + (" " + amount).slice(-2) + ": "; + result.push(amountStr + rotatedStringPrintable); + } else { + result.push(rotatedStringPrintable); + } + } + } + return result.join("\n"); + } +} + +export default ROT47BruteForce; From 671ae6558fbf773d72bb7519fde7ce1ce203c514 Mon Sep 17 00:00:00 2001 From: Peter Jacobs Date: Fri, 29 Oct 2021 01:31:55 -0500 Subject: [PATCH 21/72] Added 'LZString Decompress' and 'LZString Compress' operations --- package-lock.json | 23 +++++---- package.json | 1 + src/core/config/Categories.json | 4 +- src/core/lib/LZString.mjs | 21 ++++++++ src/core/operations/LZStringCompress.mjs | 55 +++++++++++++++++++++ src/core/operations/LZStringDecompress.mjs | 56 ++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/LZString.mjs | 33 +++++++++++++ 8 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 src/core/lib/LZString.mjs create mode 100644 src/core/operations/LZStringCompress.mjs create mode 100644 src/core/operations/LZStringDecompress.mjs create mode 100644 tests/operations/tests/LZString.mjs diff --git a/package-lock.json b/package-lock.json index 6fa9016e..d579a3d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2295,9 +2295,9 @@ "dev": true }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -8731,6 +8731,11 @@ "yallist": "^4.0.0" } }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -9014,9 +9019,9 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -12667,9 +12672,9 @@ "dev": true }, "tar": { - "version": "6.1.10", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.10.tgz", - "integrity": "sha512-kvvfiVvjGMxeUNB6MyYv5z7vhfFRwbwCXJAeL0/lnbrttBVqcMOnpHUf0X42LrPMR8mMpgapkJMchFH4FSHzNA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { "chownr": "^2.0.0", diff --git a/package.json b/package.json index 78a8696b..cf4ceba6 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "lodash": "^4.17.21", "loglevel": "^1.7.1", "loglevel-message-prefix": "^3.0.0", + "lz-string": "^1.4.4", "markdown-it": "^12.2.0", "moment": "^2.29.1", "moment-timezone": "^0.5.33", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 09ee8d15..fcd4f6af 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -313,7 +313,9 @@ "Bzip2 Decompress", "Bzip2 Compress", "Tar", - "Untar" + "Untar", + "LZString Compress", + "LZString Decompress" ] }, { diff --git a/src/core/lib/LZString.mjs b/src/core/lib/LZString.mjs new file mode 100644 index 00000000..c4919a87 --- /dev/null +++ b/src/core/lib/LZString.mjs @@ -0,0 +1,21 @@ +/** + * lz-string exports. + * + * @author crespyl [peter@crespyl.net] + * @copyright Peter Jacobs 2021 + * @license Apache-2.0 + */ + +import LZString from "lz-string"; + +export const COMPRESSION_OUTPUT_FORMATS = ["default", "UTF16", "Base64"]; +export const COMPRESSION_FUNCTIONS = { + "default": LZString.compress, + "UTF16": LZString.compressToUTF16, + "Base64": LZString.compressToBase64, +}; +export const DECOMPRESSION_FUNCTIONS = { + "default": LZString.decompress, + "UTF16": LZString.decompressFromUTF16, + "Base64": LZString.decompressFromBase64, +}; diff --git a/src/core/operations/LZStringCompress.mjs b/src/core/operations/LZStringCompress.mjs new file mode 100644 index 00000000..11d5710a --- /dev/null +++ b/src/core/operations/LZStringCompress.mjs @@ -0,0 +1,55 @@ +/** + * @author crespyl [peter@crespyl.net] + * @copyright Peter Jacobs 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +import {COMPRESSION_OUTPUT_FORMATS, COMPRESSION_FUNCTIONS} from "../lib/LZString.mjs"; + +/** + * LZString Compress operation + */ +class LZStringCompress extends Operation { + + /** + * LZStringCompress constructor + */ + constructor() { + super(); + + this.name = "LZString Compress"; + this.module = "Compression"; + this.description = "Compress the input with lz-string."; + this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Compression Format", + type: "option", + defaultIndex: 0, + value: COMPRESSION_OUTPUT_FORMATS + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const compress = COMPRESSION_FUNCTIONS[args[0]]; + if (compress) { + return compress(input); + } else { + throw new OperationError("Unable to find compression function"); + } + } + +} + +export default LZStringCompress; diff --git a/src/core/operations/LZStringDecompress.mjs b/src/core/operations/LZStringDecompress.mjs new file mode 100644 index 00000000..87d0d85b --- /dev/null +++ b/src/core/operations/LZStringDecompress.mjs @@ -0,0 +1,56 @@ +/** + * @author crespyl [peter@crespyl.net] + * @copyright Peter Jacobs 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +import {COMPRESSION_OUTPUT_FORMATS, DECOMPRESSION_FUNCTIONS} from "../lib/LZString.mjs"; + +/** + * LZString Decompress operation + */ +class LZStringDecompress extends Operation { + + /** + * LZStringDecompress constructor + */ + constructor() { + super(); + + this.name = "LZString Decompress"; + this.module = "Compression"; + this.description = "Decompresses data that was compressed with lz-string."; + this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Compression Format", + type: "option", + defaultIndex: 0, + value: COMPRESSION_OUTPUT_FORMATS + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const decompress = DECOMPRESSION_FUNCTIONS[args[0]]; + if (decompress) { + return decompress(input); + } else { + throw new OperationError("Unable to find decompression function"); + } + } + + +} + +export default LZStringDecompress; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 9add20b9..27f0fbb6 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -107,6 +107,7 @@ import "./tests/CBORDecode.mjs"; import "./tests/JA3Fingerprint.mjs"; import "./tests/JA3SFingerprint.mjs"; import "./tests/HASSH.mjs"; +import "./tests/LZString.mjs"; // Cannot test operations that use the File type yet diff --git a/tests/operations/tests/LZString.mjs b/tests/operations/tests/LZString.mjs new file mode 100644 index 00000000..69e47bdd --- /dev/null +++ b/tests/operations/tests/LZString.mjs @@ -0,0 +1,33 @@ +/** + * LZString tests. + * + * @author crespyl [peter@crespyl.net] + * @copyright Peter Jacobs 2021 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "LZString Compress To Base64", + input: "hello world", + expectedOutput: "BYUwNmD2AEDukCcwBMg=", + recipeConfig: [ + { + "op": "LZString Compress", + "args": ["Base64"] + } + ], + }, + { + name: "LZString Decompress From Base64", + input: "BYUwNmD2AEDukCcwBMg=", + expectedOutput: "hello world", + recipeConfig: [ + { + "op": "LZString Decompress", + "args": ["Base64"] + } + ], + } +]); From 578a61d33122d935557777b4dea38a6a27789a56 Mon Sep 17 00:00:00 2001 From: Robin Scholtes Date: Mon, 17 Jan 2022 23:37:24 +1300 Subject: [PATCH 22/72] add cetacean cipher encoder and decoder operations, tests. Update .gitignore to exclude idea generated files --- .gitignore | 3 + src/core/config/Categories.json | 2 + src/core/operations/CetaceanCipherDecode.mjs | 64 +++++++++++++++++++ src/core/operations/CetaceanCipherEncode.mjs | 54 ++++++++++++++++ tests/operations/index.mjs | 2 + .../operations/tests/CetaceanCipherDecode.mjs | 22 +++++++ .../operations/tests/CetaceanCipherEncode.mjs | 22 +++++++ 7 files changed, 169 insertions(+) create mode 100644 src/core/operations/CetaceanCipherDecode.mjs create mode 100644 src/core/operations/CetaceanCipherEncode.mjs create mode 100644 tests/operations/tests/CetaceanCipherDecode.mjs create mode 100644 tests/operations/tests/CetaceanCipherEncode.mjs diff --git a/.gitignore b/.gitignore index 40682646..a2aa99a3 100755 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ src/node/index.mjs **/*.DS_Store tests/browser/output/* +# ide +.idea +*.iml diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 09ee8d15..8f05d4c9 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -75,6 +75,8 @@ "Blowfish Decrypt", "DES Encrypt", "DES Decrypt", + "Cetacean Cipher Encode", + "Cetacean Cipher Decode", "Triple DES Encrypt", "Triple DES Decrypt", "RC2 Encrypt", diff --git a/src/core/operations/CetaceanCipherDecode.mjs b/src/core/operations/CetaceanCipherDecode.mjs new file mode 100644 index 00000000..a79b98c5 --- /dev/null +++ b/src/core/operations/CetaceanCipherDecode.mjs @@ -0,0 +1,64 @@ +/** + * @author dolphinOnKeys [robin@weird.io] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Cetacean Cipher Decode operation + */ +class CetaceanCipherDecode extends Operation { + + /** + * CetaceanCipherDecode constructor + */ + constructor() { + super(); + + this.name = "Cetacean Cipher Decode"; + this.module = "Ciphers"; + this.description = "Decode Cetacean Cipher input.

e.g. EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe becomes hi"; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + + this.checks = [ + { + pattern: "^(?:[eE]{16,})(?: [eE]{16,})*$", + flags: "", + args: [] + } + ] + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const binaryArray = []; + for ( const char of input ) { + if ( char === ' ' ) { + binaryArray.push(...[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]); + } else { + binaryArray.push( char === 'e' ? 1 : 0 ); + } + } + + const byteArray = []; + + for ( let i = 0; i < binaryArray.length; i += 16 ) { + byteArray.push(binaryArray.slice(i, i + 16).join('')) + } + + return byteArray.map( byte => + String.fromCharCode(parseInt( byte , 2 ) + ) + ).join(''); + } +} + +export default CetaceanCipherDecode; diff --git a/src/core/operations/CetaceanCipherEncode.mjs b/src/core/operations/CetaceanCipherEncode.mjs new file mode 100644 index 00000000..e32e4f81 --- /dev/null +++ b/src/core/operations/CetaceanCipherEncode.mjs @@ -0,0 +1,54 @@ +/** + * @author dolphinOnKeys [robin@weird.io] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Cetacean Cipher Encode operation + */ +class CetaceanCipherEncode extends Operation { + + /** + * CetaceanCipherEncode constructor + */ + constructor() { + super(); + + this.name = "Cetacean Cipher Encode"; + this.module = "Ciphers"; + this.description = "Converts any input into Cetacean Cipher.

e.g. hi becomes EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe\""; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + let result = []; + let charArray = input.split(''); + + charArray.map( ( character ) => { + if ( character === ' ' ) { + result.push( character ); + } else { + const binaryArray = this.encodeToBinary( character ).split(''); + result.push( binaryArray.map(( str ) => str === '1' ? 'e' : 'E' ).join('')); + } + }); + + return result.join(''); + } + + encodeToBinary( char, padding = 16 ) { + return char.charCodeAt(0).toString(2).padStart( padding, '0'); + } +} + +export default CetaceanCipherEncode; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 9add20b9..5200e3a1 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -26,6 +26,8 @@ import "./tests/Base62.mjs"; import "./tests/BitwiseOp.mjs"; import "./tests/ByteRepr.mjs"; import "./tests/CartesianProduct.mjs"; +import "./tests/CetaceanCipherEncode.mjs"; +import "./tests/CetaceanCipherDecode.mjs"; import "./tests/CharEnc.mjs"; import "./tests/ChangeIPFormat.mjs"; import "./tests/Charts.mjs"; diff --git a/tests/operations/tests/CetaceanCipherDecode.mjs b/tests/operations/tests/CetaceanCipherDecode.mjs new file mode 100644 index 00000000..e834dc1e --- /dev/null +++ b/tests/operations/tests/CetaceanCipherDecode.mjs @@ -0,0 +1,22 @@ +/** + * CetaceanCipher Encode tests + * + * @author dolphinOnKeys + * @copyright Crown Copyright 2022 + * @licence Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Cetacean Cipher Decode", + input: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee", + expectedOutput: "a b c で", + recipeConfig: [ + { + op: "Cetacean Cipher Decode", + args: [] + }, + ], + } +]); diff --git a/tests/operations/tests/CetaceanCipherEncode.mjs b/tests/operations/tests/CetaceanCipherEncode.mjs new file mode 100644 index 00000000..bef76388 --- /dev/null +++ b/tests/operations/tests/CetaceanCipherEncode.mjs @@ -0,0 +1,22 @@ +/** + * CetaceanCipher Encode tests + * + * @author dolphinOnKeys + * @copyright Crown Copyright 2022 + * @licence Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Cetacean Cipher Encode", + input: "a b c で", + expectedOutput: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee", + recipeConfig: [ + { + op: "Cetacean Cipher Encode", + args: [] + }, + ], + } +]); From e712af33b78764fceb90f40a17ffb800f13fcd38 Mon Sep 17 00:00:00 2001 From: Thomas Leplus Date: Mon, 11 Apr 2022 18:44:14 -0700 Subject: [PATCH 23/72] Adding ROT8000 --- src/core/config/Categories.json | 4 +- src/core/operations/ROT8000.mjs | 105 ++++++++++++++++++++++++++++++ tests/browser/ops.js | 1 + tests/operations/tests/Rotate.mjs | 33 ++++++++++ 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/ROT8000.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 9540f8a3..f9e47aac 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -87,6 +87,7 @@ "SM4 Decrypt", "ROT13", "ROT47", + "ROT8000", "XOR", "XOR Brute Force", "Vigenère Encode", @@ -176,7 +177,8 @@ "Bit shift right", "Rotate left", "Rotate right", - "ROT13" + "ROT13", + "ROT8000" ] }, { diff --git a/src/core/operations/ROT8000.mjs b/src/core/operations/ROT8000.mjs new file mode 100644 index 00000000..1f039de0 --- /dev/null +++ b/src/core/operations/ROT8000.mjs @@ -0,0 +1,105 @@ +/** + * @author Daniel Temkin [http://danieltemkin.com] + * @author Thomas Leplus [https://www.leplus.org] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * ROT8000 operation. + */ +class ROT8000 extends Operation { + + /** + * ROT8000 constructor + */ + constructor() { + super(); + this.name = "ROT8000"; + this.module = "Default"; + this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet."; + this.infoURL = "https://github.com/rottytooth/rot8000"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + // Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js + // these come from the valid-code-point-transitions.json file generated from the c# proj + // this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000 + const validCodePoints = JSON.parse('{"33":true,"127":false,"161":true,"5760":false,"5761":true,"8192":false,"8203":true,"8232":false,"8234":true,"8239":false,"8240":true,"8287":false,"8288":true,"12288":false,"12289":true,"55296":false,"57344":true}'); + const bmpSize = 0x10000; + const rotList = {}; // the mapping of char to rotated char + const hiddenBlocks = []; + let startBlock = 0; + for (const key in validCodePoints) { + if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) { + if (validCodePoints[key] === true) + hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 }); + else + startBlock = parseInt(key, 10); + } + } + const validIntList = []; // list of all valid chars + let currValid = false; + for (let i = 0; i < bmpSize; i++) { + if (validCodePoints[i] !== undefined) { + currValid = validCodePoints[i]; + } + if (currValid) validIntList.push(i); + } + const rotateNum = Object.keys(validIntList).length / 2; + // go through every valid char and find its match + for (let i = 0; i < validIntList.length; i++) { + rotList[String.fromCharCode(validIntList[i])] = + String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]); + } + let output = ""; + for (let count = 0; count < input.length; count++) { + // if it is not in the mappings list, just add it directly (no rotation) + if (rotList[input[count]] === undefined) { + output += input[count]; + continue; + } + // otherwise, rotate it and add it to the string + output += rotList[input[count]]; + } + return output; + } + + /** + * Highlight ROT8000 + * + * @param {Object[]} pos + * @param {number} pos[].start + * @param {number} pos[].end + * @param {Object[]} args + * @returns {Object[]} pos + */ + highlight(pos, args) { + return pos; + } + + /** + * Highlight ROT8000 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 ROT8000; diff --git a/tests/browser/ops.js b/tests/browser/ops.js index f2522a79..62436a89 100644 --- a/tests/browser/ops.js +++ b/tests/browser/ops.js @@ -246,6 +246,7 @@ module.exports = { // testOp(browser, "RIPEMD", "test input", "test_output"); // testOp(browser, "ROT13", "test input", "test_output"); // testOp(browser, "ROT47", "test input", "test_output"); + // testOp(browser, "ROT8000", "test input", "test_output"); // testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output"); // testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output"); // testOp(browser, "Randomize Colour Palette", "test input", "test_output"); diff --git a/tests/operations/tests/Rotate.mjs b/tests/operations/tests/Rotate.mjs index 85e31508..c12fa377 100644 --- a/tests/operations/tests/Rotate.mjs +++ b/tests/operations/tests/Rotate.mjs @@ -212,4 +212,37 @@ TestRegister.addTests([ }, ], }, + { + name: "ROT8000: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + op: "ROT8000", + args: [] + }, + ], + }, + { + name: "ROT8000: normal", + input: "The Quick Brown Fox Jumped Over The Lazy Dog.", + expectedOutput: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷", + recipeConfig: [ + { + op: "ROT8000", + args: [] + }, + ], + }, + { + name: "ROT8000: backward", + input: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.", + recipeConfig: [ + { + op: "ROT8000", + args: [] + }, + ], + }, ]); From 1fea9a25a50b9f95a8168ce1767062b55349baaa Mon Sep 17 00:00:00 2001 From: sec65 Date: Sun, 5 Jun 2022 17:22:42 +0200 Subject: [PATCH 24/72] reset loop counter after last run --- src/core/operations/ConditionalJump.mjs | 4 ++++ src/core/operations/Jump.mjs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/core/operations/ConditionalJump.mjs b/src/core/operations/ConditionalJump.mjs index ca8eea30..b0c65ddd 100644 --- a/src/core/operations/ConditionalJump.mjs +++ b/src/core/operations/ConditionalJump.mjs @@ -64,6 +64,7 @@ class ConditionalJump extends Operation { jmpIndex = getLabelIndex(label, state); if (state.numJumps >= maxJumps || jmpIndex === -1) { + state.numJumps = 0; return state; } @@ -74,6 +75,9 @@ class ConditionalJump extends Operation { state.progress = jmpIndex; state.numJumps++; } + else { + state.numJumps = 0; + } } return state; diff --git a/src/core/operations/Jump.mjs b/src/core/operations/Jump.mjs index f442faa0..26a2c922 100644 --- a/src/core/operations/Jump.mjs +++ b/src/core/operations/Jump.mjs @@ -52,6 +52,7 @@ class Jump extends Operation { const jmpIndex = getLabelIndex(label, state); if (state.numJumps >= maxJumps || jmpIndex === -1) { + state.numJumps = 0; return state; } From 3990ba774f9667c8a5bec4841af3f2fe10feaa80 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Sun, 5 Jun 2022 18:35:02 +0100 Subject: [PATCH 25/72] Implemented readelf-like functionality. --- src/core/config/Categories.json | 3 +- src/core/operations/ELFInfo.mjs | 916 +++++++++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/ELFInfo.mjs | 20 + 4 files changed, 939 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/ELFInfo.mjs create mode 100644 tests/operations/tests/ELFInfo.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index c15ec3d2..5c74c0c2 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -413,7 +413,8 @@ "Extract RGBA", "View Bit Plane", "Randomize Colour Palette", - "Extract LSB" + "Extract LSB", + "ELF Info" ] }, { diff --git a/src/core/operations/ELFInfo.mjs b/src/core/operations/ELFInfo.mjs new file mode 100644 index 00000000..6fa46c54 --- /dev/null +++ b/src/core/operations/ELFInfo.mjs @@ -0,0 +1,916 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Stream from "../lib/Stream.mjs"; +import Utils from "../Utils.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * ELF Info operation + */ +class ELFInfo extends Operation { + + /** + * ELFInfo constructor + */ + constructor() { + super(); + + this.name = "ELF Info"; + this.module = "Default"; + this.description = "Implements readelf-like functionality. This operation will extract the ELF Header, Program Headers, Section Headers and Symbol Table for an ELF file."; + this.infoURL = "https://www.wikipedia.org/wiki/Executable_and_Linkable_Format"; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + let phoff = 0; + let phEntries = 0; + let shoff = 0; + let shEntries = 0; + let shentSize = 0; + let entry = 0; + let format = 0; + let endianness = ""; + let shstrtab = 0; + + let namesOffset = 0; + + let symtabOffset = 0; + let symtabSize = 0; + let symtabEntSize = 0; + + let strtabOffset = 0; + const align = 30; + + /** + * This function reads characters until it hits a null terminator. + * + * @param {stream} stream + * @param {integer} namesOffset + * @param {integer} nameOffset + * @returns {string} + */ + function readString(stream, namesOffset, nameOffset) { + const preMove = stream.position; + stream.moveTo(namesOffset + nameOffset); + + let nameResult = ""; + let elem = 0; + while ((elem = stream.readInt(1, endianness)) !== 0) + nameResult += String.fromCharCode(elem); + stream.moveTo(preMove); + return nameResult; + } + + /** + * This function parses and extracts relevant information from the ELF Header. + * + * @param {stream} stream + * @returns {string} + */ + function elfHeader(stream) { + /** + * The ELF Header is comprised of the following structures depending on the binary's format. + * + * e_ident - The Magic Number 0x7F,0x45,0x4c,0x46 + * - Byte set to 1 or 2 to signify 32-bit or 64-bit format, respectively. + * - Byte set to 1 or 2 to signify little of big endianness, respectively. + * - Byte set to 1 for the version of ELF. + * - Byte identifying the target OS ABI. + * - Byte further identifying the OS ABI Version. + * - 7 Padding Bytes. + * e_type - 2 bytes identifying the object file type. + * e_machine - 2 bytes identifying the instruction set architecture. + * e_version - Byte set to 1 for the version of ELF. + * + * 32-bit: + * e_entry - 4 Bytes specifying the entry point. + * e_phoff - 4 Bytes specifying the offset of the Program Header Table. + * e_shoff - 4 Bytes specifying the offset of the Section Header Table. + * + * 64-bit: + * e_entry - 8 Bytes specifying the entry point. + * e_phoff - 8 Bytes specifying the offset of the Program Header Table. + * e_shoff - 8 Bytes specifying the offset of the Section Header Table. + * + * e_flags - 4 Bytes specifying processor specific flags. + * e_ehsize - 2 Bytes specifying the size of the ELF Header. + * e_phentsize - 2 Bytes specifying the size of a Program Header Table Entry. + * e_phnum - 2 Bytes specifying the number of entries in the Program Header Table. + * e_shentsize - 2 Bytes specifying the size of a Section Header Table Entry. + * e_shnum - 2 Bytes specifying the number of entries in the Section Header Table. + * e_shstrndx - 2 Bytes specifying the index of the section containing the section names in the Section Header Table. + */ + const ehResult = []; + + const magic = stream.getBytes(4); + if (magic.join("") !== [0x7f, 0x45, 0x4c, 0x46].join("")) + throw new OperationError("Invalid ELF"); + + ehResult.push("Magic:".padEnd(align) + `${Utils.byteArrayToChars(magic)}`); + + format = stream.readInt(1); + ehResult.push("Format:".padEnd(align) + `${format === 1 ? "32-bit" : "64-bit"}`); + + endianness = stream.readInt(1) === 1 ? "le" : "be"; + ehResult.push("Endianness:".padEnd(align) + `${endianness === 1 ? "Little" : "Big"}`); + + ehResult.push("Version:".padEnd(align) + `${stream.readInt(1).toString()}`); + + let ABI = ""; + switch (stream.readInt(1)) { + case 0x00: + ABI = "System V"; + break; + case 0x01: + ABI = "HP-UX"; + break; + case 0x02: + ABI = "NetBSD"; + break; + case 0x03: + ABI = "Linux"; + break; + case 0x04: + ABI = "GNU Hurd"; + break; + case 0x06: + ABI = "Solaris"; + break; + case 0x07: + ABI = "AIX"; + break; + case 0x08: + ABI = "IRIX"; + break; + case 0x09: + ABI = "FreeBSD"; + break; + case 0x0A: + ABI = "Tru64"; + break; + case 0x0B: + ABI = "Novell Modesto"; + break; + case 0x0C: + ABI = "OpenBSD"; + break; + case 0x0D: + ABI = "OpenVMS"; + break; + case 0x0E: + ABI = "NonStop Kernel"; + break; + case 0x0F: + ABI = "AROS"; + break; + case 0x10: + ABI = "Fenix OS"; + break; + case 0x11: + ABI = "CloudABI"; + break; + case 0x12: + ABI = "Stratus Technologies OpenVOS"; + break; + default: + break; + } + ehResult.push("ABI:".padEnd(align) + ABI); + + // Linux Kernel does not use ABI Version. + const abiVersion = stream.readInt(1).toString(); + if (ABI !== "Linux") + ehResult.push("ABI Version:".padEnd(align) + abiVersion); + + stream.moveForwardsBy(7); + + let eType = ""; + switch (stream.readInt(2, endianness)) { + case 0x0000: + eType = "Unknown"; + break; + case 0x0001: + eType = "Relocatable File"; + break; + case 0x0002: + eType = "Executable File"; + break; + case 0x0003: + eType = "Shared Object"; + break; + case 0x0004: + eType = "Core File"; + break; + case 0xFE00: + eType = "LOOS"; + break; + case 0xFEFF: + eType = "HIOS"; + break; + case 0xFF00: + eType = "LOPROC"; + break; + case 0xFFFF: + eType = "HIPROC"; + break; + default: + break; + } + ehResult.push("Type:".padEnd(align) + eType); + + let ISA = ""; + switch (stream.readInt(2, endianness)) { + case 0x0000: + ISA = "No specific instruction set"; + break; + case 0x0001: + ISA = "AT&T WE 32100"; + break; + case 0x0002: + ISA = "SPARC"; + break; + case 0x0003: + ISA = "x86"; + break; + case 0x0004: + ISA = "Motorola 68000 (M68k)"; + break; + case 0x0005: + ISA = "Motorola 88000 (M88k)"; + break; + case 0x0006: + ISA = "Intel MCU"; + break; + case 0x0007: + ISA = "Intel 80860"; + break; + case 0x0008: + ISA = "MIPS"; + break; + case 0x0009: + ISA = "IBM System/370"; + break; + case 0x000A: + ISA = "MIPS RS3000 Little-endian"; + break; + case 0x000B: + case 0x000C: + case 0x000D: + case 0x000E: + case 0x0018: + case 0x0019: + case 0x001A: + case 0x001B: + case 0x001C: + case 0x001D: + case 0x001E: + case 0x001F: + case 0x0020: + case 0x0021: + case 0x0022: + case 0x0023: + ISA = "Reserved for future use"; + break; + case 0x000F: + ISA = "Hewlett-Packard PA-RISC"; + break; + case 0x0011: + ISA = "Fujitsu VPP500"; + break; + case 0x0012: + ISA = "Enhanced instruction set SPARC"; + break; + case 0x0013: + ISA = "Intel 80960"; + break; + case 0x0014: + ISA = "PowerPC"; + break; + case 0x0015: + ISA = "PowerPC (64-bit)"; + break; + case 0x0016: + ISA = "S390, including S390"; + break; + case 0x0017: + ISA = "IBM SPU/SPC"; + break; + case 0x0024: + ISA = "NEC V800"; + break; + case 0x0025: + ISA = "Fujitsu FR20"; + break; + case 0x0026: + ISA = "TRW RH-32"; + break; + case 0x0027: + ISA = "Motorola RCE"; + break; + case 0x0028: + ISA = "ARM (up to ARMv7/Aarch32)"; + break; + case 0x0029: + ISA = "Digital Alpha"; + break; + case 0x002A: + ISA = "SuperH"; + break; + case 0x002B: + ISA = "SPARC Version 9"; + break; + case 0x002C: + ISA = "Siemens TriCore embedded processor"; + break; + case 0x002D: + ISA = "Argonaut RISC Core"; + break; + case 0x002E: + ISA = "Hitachi H8/300"; + break; + case 0x002F: + ISA = "Hitachi H8/300H"; + break; + case 0x0030: + ISA = "Hitachi H8S"; + break; + case 0x0031: + ISA = "Hitachi H8/500"; + break; + case 0x0032: + ISA = "IA-64"; + break; + case 0x0033: + ISA = "Standford MIPS-X"; + break; + case 0x0034: + ISA = "Motorola ColdFire"; + break; + case 0x0035: + ISA = "Motorola M68HC12"; + break; + case 0x0036: + ISA = "Fujitsu MMA Multimedia Accelerator"; + break; + case 0x0037: + ISA = "Siemens PCP"; + break; + case 0x0038: + ISA = "Sony nCPU embedded RISC processor"; + break; + case 0x0039: + ISA = "Denso NDR1 microprocessor"; + break; + case 0x003A: + ISA = "Motorola Star*Core processor"; + break; + case 0x003B: + ISA = "Toyota ME16 processor"; + break; + case 0x003C: + ISA = "STMicroelectronics ST100 processor"; + break; + case 0x003D: + ISA = "Advanced Logic Corp. TinyJ embedded processor family"; + break; + case 0x003E: + ISA = "AMD x86-64"; + break; + case 0x003F: + ISA = "Sony DSP Processor"; + break; + case 0x0040: + ISA = "Digital Equipment Corp. PDP-10"; + break; + case 0x0041: + ISA = "Digital Equipment Corp. PDP-11"; + break; + case 0x0042: + ISA = "Siemens FX66 microcontroller"; + break; + case 0x0043: + ISA = "STMicroelectronics ST9+ 8/16 bit microcontroller"; + break; + case 0x0044: + ISA = "STMicroelectronics ST7 8-bit microcontroller"; + break; + case 0x0045: + ISA = "Motorola MC68HC16 Microcontroller"; + break; + case 0x0046: + ISA = "Motorola MC68HC11 Microcontroller"; + break; + case 0x0047: + ISA = "Motorola MC68HC08 Microcontroller"; + break; + case 0x0048: + ISA = "Motorola MC68HC05 Microcontroller"; + break; + case 0x0049: + ISA = "Silicon Graphics SVx"; + break; + case 0x004A: + ISA = "STMicroelectronics ST19 8-bit microcontroller"; + break; + case 0x004B: + ISA = "Digital VAX"; + break; + case 0x004C: + ISA = "Axis Communications 32-bit embedded processor"; + break; + case 0x004D: + ISA = "Infineon Technologies 32-bit embedded processor"; + break; + case 0x004E: + ISA = "Element 14 64-bit DSP Processor"; + break; + case 0x004F: + ISA = "LSI Logic 16-bit DSP Processor"; + break; + case 0x0050: + ISA = "Donald Knuth's educational 64-bit processor"; + break; + case 0x0051: + ISA = "Harvard University machine-independent object files"; + break; + case 0x0052: + ISA = "SiTera Prism"; + break; + case 0x0053: + ISA = "Atmel AVR 8-bit microcontroller"; + break; + case 0x0054: + ISA = "Fujitsu FR30"; + break; + case 0x0055: + ISA = "Mitsubishi D10V"; + break; + case 0x0056: + ISA = "Mitsubishi D30V"; + break; + case 0x0057: + ISA = "NEC v850"; + break; + case 0x0058: + ISA = "Mitsubishi M32R"; + break; + case 0x0059: + ISA = "Matsushita MN10300"; + break; + case 0x005A: + ISA = "Matsushita MN10200"; + break; + case 0x005B: + ISA = "picoJava"; + break; + case 0x005C: + ISA = "OpenRISC 32-bit embedded processor"; + break; + case 0x005D: + ISA = "ARC Cores Tangent-A5"; + break; + case 0x005E: + ISA = "Tensilica Xtensa Architecture"; + break; + case 0x005F: + ISA = "Alphamosaic VideoCore processor"; + break; + case 0x0060: + ISA = "Thompson Multimedia General Purpose Processor"; + break; + case 0x0061: + ISA = "National Semiconductor 32000 series"; + break; + case 0x0062: + ISA = "Tenor Network TPC processor"; + break; + case 0x0063: + ISA = "Trebia SNP 1000 processor"; + break; + case 0x0064: + ISA = "STMicroelectronics (www.st.com) ST200 microcontroller"; + break; + case 0x008C: + ISA = "TMS320C6000 Family"; + break; + case 0x00AF: + ISA = "MCST Elbrus e2k"; + break; + case 0x00B7: + ISA = "ARM 64-bits (ARMv8/Aarch64)"; + break; + case 0x00F3: + ISA = "RISC-V"; + break; + case 0x00F7: + ISA = "Berkeley Packet Filter"; + break; + case 0x0101: + ISA = "WDC 65C816"; + break; + default: + ISA = "Unimplemented"; + break; + } + ehResult.push("Instruction Set Architecture:".padEnd(align) + ISA); + + ehResult.push("ELF Version:".padEnd(align) + `${stream.readInt(4, endianness)}`); + + const readSize = format === 1 ? 4 : 8; + entry = stream.readInt(readSize, endianness); + phoff = stream.readInt(readSize, endianness); + shoff = stream.readInt(readSize, endianness); + ehResult.push("Entry Point:".padEnd(align) + `0x${Utils.hex(entry)}`); + ehResult.push("Entry PHOFF:".padEnd(align) + `0x${Utils.hex(phoff)}`); + ehResult.push("Entry SHOFF:".padEnd(align) + `0x${Utils.hex(shoff)}`); + + const flags = stream.readInt(4, endianness); + ehResult.push("Flags:".padEnd(align) + `${Utils.bin(flags)}`); + + ehResult.push("ELF Header Size:".padEnd(align) + `${stream.readInt(2, endianness)} bytes`); + ehResult.push("Program Header Size:".padEnd(align) + `${stream.readInt(2, endianness)} bytes`); + phEntries = stream.readInt(2, endianness); + ehResult.push("Program Header Entries:".padEnd(align) + phEntries); + shentSize = stream.readInt(2, endianness); + ehResult.push("Section Header Size:".padEnd(align) + shentSize + " bytes"); + shEntries = stream.readInt(2, endianness); + ehResult.push("Section Header Entries:".padEnd(align) + shEntries); + shstrtab = stream.readInt(2, endianness); + ehResult.push("Section Header Names:".padEnd(align) + shstrtab); + + return ehResult.join("\n"); + } + + /** + * This function parses and extracts relevant information from a Program Header. + * + * @param {stream} stream + * @returns {string} + */ + function programHeader(stream) { + /** + * A Program Header is comprised of the following structures depending on the binary's format. + * + * p_type - 4 Bytes identifying the type of the segment. + * + * 32-bit: + * p_offset - 4 Bytes specifying the offset of the segment. + * p_vaddr - 4 Bytes specifying the virtual address of the segment in memory. + * p_paddr - 4 Bytes specifying the physical address of the segment in memory. + * p_filesz - 4 Bytes specifying the size in bytes of the segment in the file image. + * p_memsz - 4 Bytes specifying the size in bytes of the segment in memory. + * p_flags - 4 Bytes identifying the segment dependent flags. + * p_align - 4 Bytes set to 0 or 1 for alignment or no alignment, respectively. + * + * 64-bit: + * p_flags - 4 Bytes identifying segment dependent flags. + * p_offset - 8 Bytes specifying the offset of the segment. + * p_vaddr - 8 Bytes specifying the virtual address of the segment in memory. + * p_paddr - 8 Bytes specifying the physical address of the segment in memory. + * p_filesz - 8 Bytes specifying the size in bytes of the segment in the file image. + * p_memsz - 8 Bytes specifying the size in bytes of the segment in memory. + * p_align - 8 Bytes set to 0 or 1 for alignment or no alignment, respectively. + */ + + /** + * This function decodes the flags bitmask for the Program Header. + * + * @param {integer} flags + * @returns {string} + */ + function readFlags(flags) { + const result = []; + if (flags & 0x1) + result.push("Execute"); + if (flags & 0x2) + result.push("Write"); + if (flags & 0x4) + result.push("Read"); + if (flags & 0xf0000000) + result.push("Unspecified"); + return result.join(","); + } + + const phResult = []; + + let pType = ""; + const programHeaderType = stream.readInt(4, endianness); + switch (true) { + case (programHeaderType === 0x00000000): + pType = "Unused"; + break; + case (programHeaderType === 0x00000001): + pType = "Loadable Segment"; + break; + case (programHeaderType === 0x00000002): + pType = "Dynamic linking information"; + break; + case (programHeaderType === 0x00000003): + pType = "Interpreter Information"; + break; + case (programHeaderType === 0x00000004): + pType = "Auxiliary Information"; + break; + case (programHeaderType === 0x00000005): + pType = "Reserved"; + break; + case (programHeaderType === 0x00000006): + pType = "Program Header Table"; + break; + case (programHeaderType === 0x00000007): + pType = "Thread-Local Storage Template"; + break; + case (programHeaderType >= 0x60000000 && programHeaderType <= 0x6FFFFFFF): + pType = "Reserved Inclusive Range. OS Specific"; + break; + case (programHeaderType >= 0x70000000 && programHeaderType <= 0x7FFFFFFF): + pType = "Reserved Inclusive Range. Processor Specific"; + break; + default: + break; + + } + phResult.push("Program Header Type:".padEnd(align) + pType); + + if (format === 2) + phResult.push("Flags:".padEnd(align) + readFlags(stream.readInt(4, endianness))); + + const readSize = format === 1? 4 : 8; + phResult.push("Offset Of Segment:".padEnd(align) + `${stream.readInt(readSize, endianness)}`); + phResult.push("Virtual Address of Segment:".padEnd(align) + `${stream.readInt(readSize, endianness)}`); + phResult.push("Physical Address of Segment:".padEnd(align) + `${stream.readInt(readSize, endianness)}`); + phResult.push("Size of Segment:".padEnd(align) + `${stream.readInt(readSize, endianness)} bytes`); + phResult.push("Size of Segment in Memory:".padEnd(align) + `${stream.readInt(readSize, endianness)} bytes`); + + if (format === 1) + phResult.push("Flags:".padEnd(align) + readFlags(stream.readInt(4, endianness))); + + stream.moveForwardsBy(readSize); + + return phResult.join("\n"); + } + + /** + * This function parses and extracts relevant information from a Section Header. + * + * @param {stream} stream + * @returns {string} + */ + function sectionHeader(stream) { + /** + * A Section Header is comprised of the following structures depending on the binary's format. + * + * sh_name - 4 Bytes identifying the offset into the .shstrtab for the name of this section. + * sh_type - 4 Bytes identifying the type of this header. + * + * 32-bit: + * sh_flags - 4 Bytes identifying section specific flags. + * sh_addr - 4 Bytes identifying the virtual address of the section in memory. + * sh_offset - 4 Bytes identifying the offset of the section in the file. + * sh_size - 4 Bytes specifying the size in bytes of the section in the file image. + * sh_link - 4 Bytes identifying the index of an associated section. + * sh_info - 4 Bytes specifying extra information about the section. + * sh_addralign - 4 Bytes containing the alignment for the section. + * sh_entsize - 4 Bytes specifying the size, in bytes, of each entry in the section. + * + * 64-bit: + * sh_flags - 8 Bytes identifying section specific flags. + * sh_addr - 8 Bytes identifying the virtual address of the section in memory. + * sh_offset - 8 Bytes identifying the offset of the section in the file. + * sh_size - 8 Bytes specifying the size in bytes of the section in the file image. + * sh_link - 4 Bytes identifying the index of an associated section. + * sh_info - 4 Bytes specifying extra information about the section. + * sh_addralign - 8 Bytes containing the alignment for the section. + * sh_entsize - 8 Bytes specifying the size, in bytes, of each entry in the section. + */ + const shResult = []; + + const nameOffset = stream.readInt(4, endianness); + let type = ""; + const shType = stream.readInt(4, endianness); + switch (true) { + case (shType === 0x00000001): + type = "Program Data"; + break; + case (shType === 0x00000002): + type = "Symbol Table"; + break; + case (shType === 0x00000003): + type = "String Table"; + break; + case (shType === 0x00000004): + type = "Relocation Entries with Addens"; + break; + case (shType === 0x00000005): + type = "Symbol Hash Table"; + break; + case (shType === 0x00000006): + type = "Dynamic Linking Information"; + break; + case (shType === 0x00000007): + type = "Notes"; + break; + case (shType === 0x00000008): + type = "Program Space with No Data"; + break; + case (shType === 0x00000009): + type = "Relocation Entries with no Addens"; + break; + case (shType === 0x0000000A): + type = "Reserved"; + break; + case (shType === 0x0000000B): + type = "Dynamic Linker Symbol Table"; + break; + case (shType === 0x0000000E): + type = "Array of Constructors"; + break; + case (shType === 0x0000000F): + type = "Array of Destructors"; + break; + case (shType === 0x00000010): + type = "Array of pre-constructors"; + break; + case (shType === 0x00000011): + type = "Section group"; + break; + case (shType === 0x00000012): + type = "Extended section indices"; + break; + case (shType === 0x00000013): + type = "Number of defined types"; + break; + case (shType >= 0x60000000 && shType <= 0x6fffffff): + type = "OS-specific"; + break; + case (shType >= 0x70000000 && shType <= 0x7fffffff): + type = "Processor-specific"; + break; + case (shType >= 0x80000000 && shType <= 0x8fffffff): + type = "Application-specific"; + break; + default: + type = "Unused"; + break; + } + + shResult.push("Type:".padEnd(align) + type); + + let nameResult = ""; + if (type !== "Unused") { + nameResult = readString(stream, namesOffset, nameOffset); + shResult.push("Section Name: ".padEnd(align) + nameResult); + } + + const readSize = (format === 1) ? 4 : 8; + + const flags = stream.readInt(readSize, endianness); + const shFlags = []; + const bitMasks = [ + [0x00000001, "Writable"], + [0x00000002, "Alloc"], + [0x00000004, "Executable"], + [0x00000010, "Merge"], + [0x00000020, "Strings"], + [0x00000040, "SHT Info Link"], + [0x00000080, "Link Order"], + [0x00000100, "OS Specific Handling"], + [0x00000200, "Group"], + [0x00000400, "Thread Local Data"], + [0x0FF00000, "OS-Specific"], + [0xF0000000, "Processor Specific"], + [0x04000000, "Special Ordering (Solaris)"], + [0x08000000, "Excluded (Solaris)"] + ]; + bitMasks.forEach(elem => { + if (flags & elem[0]) + shFlags.push(elem[1]); + }); + shResult.push("Flags:".padEnd(align) + shFlags); + + const vaddr = stream.readInt(readSize, endianness); + shResult.push("Section Vaddr in memory:".padEnd(align) + vaddr); + + const shoffset = stream.readInt(readSize, endianness); + shResult.push("Offset of the section:".padEnd(align) + shoffset); + + const secSize = stream.readInt(readSize, endianness); + shResult.push("Section Size:".padEnd(align) + secSize); + + const associatedSection = stream.readInt(4, endianness); + shResult.push("Associated Section:".padEnd(align) + associatedSection); + + const extraInfo = stream.readInt(4, endianness); + shResult.push("Section Extra Information:".padEnd(align) + extraInfo); + + // Jump over alignment field. + stream.moveForwardsBy(readSize); + const entSize = stream.readInt(readSize, endianness); + switch (nameResult) { + case ".strtab": + strtabOffset = shoffset; + break; + case ".symtab": + symtabOffset = shoffset; + symtabSize = secSize; + symtabEntSize = entSize; + break; + default: + break; + } + return shResult.join("\n"); + } + + /** + * This function returns the offset of the Section Header Names Section. + * + * @param {stream} stream + */ + function getNamesOffset(stream) { + const preMove = stream.position; + stream.moveTo(shoff + (shentSize * shstrtab)); + if (format === 1) { + stream.moveForwardsBy(0x10); + namesOffset = stream.readInt(4, endianness); + } else { + stream.moveForwardsBy(0x18); + namesOffset = stream.readInt(8, endianness); + } + stream.position = preMove; + } + + /** + * This function returns a symbol's name from the string table. + * + * @param {stream} stream + * @returns {string} + */ + function getSymbols(stream) { + /** + * The Symbol Table is comprised of Symbol Table Entries whose structure depends on the binary's format. + * + * 32-bit: + * st_name - 4 Bytes specifying an index in the files symbol string table. + * st_value - 4 Bytes identifying the value associated with the symbol. + * st_size - 4 Bytes specifying the size associated with the symbol (this is not the size of the symbol). + * st_info - A byte specifying the type and binding of the symbol. + * st_other - A byte specifying the symbol's visibility. + * st_shndx - 2 Bytes identifying the section that this symbol is related to. + * + * 64-bit: + * st_name - 4 Bytes specifying an index in the files symbol string table. + * st_info - A byte specifying the type and binding of the symbol. + * st_other - A byte specifying the symbol's visibility. + * st_shndx - 2 Bytes identifying the section that this symbol is related to. + * st_value - 8 Bytes identifying the value associated with the symbol. + * st_size - 8 Bytes specifying the size associated with the symbol (this is not the size of the symbol). + */ + const nameOffset = stream.readInt(4, endianness); + stream.moveForwardsBy(format === 2 ? 20 : 12); + return readString(stream, strtabOffset, nameOffset); + } + + input = new Uint8Array(input); + const stream = new Stream(input); + const result = ["=".repeat(align) + " ELF Header " + "=".repeat(align)]; + result.push(elfHeader(stream) + "\n"); + + getNamesOffset(stream); + + result.push("=".repeat(align) + " Program Header " + "=".repeat(align)); + stream.moveTo(phoff); + for (let i = 0; i < phEntries; i++) + result.push(programHeader(stream) + "\n"); + + result.push("=".repeat(align) + " Section Header " + "=".repeat(align)); + stream.moveTo(shoff); + for (let i = 0; i < shEntries; i++) + result.push(sectionHeader(stream) + "\n"); + + result.push("=".repeat(align) + " Symbol Table " + "=".repeat(align)); + + stream.moveTo(symtabOffset); + let elem = ""; + for (let i = 0; i < (symtabSize / symtabEntSize); i++) + if ((elem = getSymbols(stream)) !== "") + result.push("Symbol Name:".padEnd(align) + elem); + + return result.join("\n"); + } + +} + +export default ELFInfo; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index cf32a5ab..b6beb081 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -113,6 +113,7 @@ import "./tests/JA3SFingerprint.mjs"; import "./tests/HASSH.mjs"; import "./tests/GetAllCasings.mjs"; import "./tests/SIGABA.mjs"; +import "./tests/ELFInfo.mjs"; // Cannot test operations that use the File type yet diff --git a/tests/operations/tests/ELFInfo.mjs b/tests/operations/tests/ELFInfo.mjs new file mode 100644 index 00000000..2afcda81 --- /dev/null +++ b/tests/operations/tests/ELFInfo.mjs @@ -0,0 +1,20 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + import TestRegister from "../../lib/TestRegister.mjs"; + + TestRegister.addTests([ + { + name: "ELF Info invalid ELF.", + input: "\x7f\x00\x00\x00", + expectedOutput: "Invalid ELF", + recipeConfig: [ + { + op: "ELF Info", + args: [], + }, + ], + }, + ]); From 1ab444bda2d40e87dd0db7a9d156556bd8bb965b Mon Sep 17 00:00:00 2001 From: n1073645 Date: Sun, 5 Jun 2022 18:40:46 +0100 Subject: [PATCH 26/72] Fix tabs in tests file. --- tests/operations/tests/ELFInfo.mjs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/operations/tests/ELFInfo.mjs b/tests/operations/tests/ELFInfo.mjs index 2afcda81..cabf1344 100644 --- a/tests/operations/tests/ELFInfo.mjs +++ b/tests/operations/tests/ELFInfo.mjs @@ -3,18 +3,18 @@ * @copyright Crown Copyright 2022 * @license Apache-2.0 */ - import TestRegister from "../../lib/TestRegister.mjs"; +import TestRegister from "../../lib/TestRegister.mjs"; - TestRegister.addTests([ - { - name: "ELF Info invalid ELF.", - input: "\x7f\x00\x00\x00", - expectedOutput: "Invalid ELF", - recipeConfig: [ - { - op: "ELF Info", - args: [], - }, - ], - }, - ]); +TestRegister.addTests([ + { + name: "ELF Info invalid ELF.", + input: "\x7f\x00\x00\x00", + expectedOutput: "Invalid ELF", + recipeConfig: [ + { + op: "ELF Info", + args: [], + }, + ], + }, +]); From 5349115b947bae9d66f6c1cd9d540da150a2dac7 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 8 Jun 2022 18:06:41 +0100 Subject: [PATCH 27/72] 'JSON Beautify' operation now supports formatting, collapsing and syntax highlighting. Closes #203. --- package-lock.json | 5 +- package.json | 1 + src/core/operations/JSONBeautify.mjs | 222 +++++++++++++++++++++--- src/web/stylesheets/index.css | 3 + src/web/stylesheets/operations/json.css | 78 +++++++++ tests/operations/tests/JSONBeautify.mjs | 36 ++-- 6 files changed, 304 insertions(+), 41 deletions(-) create mode 100644 src/web/stylesheets/operations/json.css diff --git a/package-lock.json b/package-lock.json index ff6dfe1f..cd04e5d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "js-crc": "^0.2.0", "js-sha3": "^0.8.0", "jsesc": "^3.0.2", + "json5": "^2.2.1", "jsonpath": "^1.1.1", "jsonwebtoken": "^8.5.1", "jsqr": "^1.4.0", @@ -9489,7 +9490,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -23014,8 +23014,7 @@ "json5": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "jsonpath": { "version": "1.1.1", diff --git a/package.json b/package.json index 47b4678d..72208f29 100644 --- a/package.json +++ b/package.json @@ -122,6 +122,7 @@ "js-crc": "^0.2.0", "js-sha3": "^0.8.0", "jsesc": "^3.0.2", + "json5": "^2.2.1", "jsonpath": "^1.1.1", "jsonwebtoken": "^8.5.1", "jsqr": "^1.4.0", diff --git a/src/core/operations/JSONBeautify.mjs b/src/core/operations/JSONBeautify.mjs index f53d86e6..923ae7dc 100644 --- a/src/core/operations/JSONBeautify.mjs +++ b/src/core/operations/JSONBeautify.mjs @@ -5,8 +5,10 @@ * @license Apache-2.0 */ -import vkbeautify from "vkbeautify"; +import JSON5 from "json5"; +import OperationError from "../errors/OperationError.mjs"; import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; /** * JSON Beautify operation @@ -21,19 +23,25 @@ class JSONBeautify extends Operation { this.name = "JSON Beautify"; this.module = "Code"; - this.description = "Indents and prettifies JavaScript Object Notation (JSON) code."; + this.description = "Indents and pretty prints JavaScript Object Notation (JSON) code.

Tags: json viewer, prettify, syntax highlighting"; this.inputType = "string"; this.outputType = "string"; + this.presentType = "html"; this.args = [ { - "name": "Indent string", - "type": "binaryShortString", - "value": " " + name: "Indent string", + type: "binaryShortString", + value: " " }, { - "name": "Sort Object Keys", - "type": "boolean", - "value": false + name: "Sort Object Keys", + type: "boolean", + value: false + }, + { + name: "Formatted", + type: "boolean", + value: true } ]; } @@ -44,35 +52,193 @@ class JSONBeautify extends Operation { * @returns {string} */ run(input, args) { - const [indentStr, sortBool] = args; - if (!input) return ""; - if (sortBool) { - input = JSON.stringify(JSONBeautify._sort(JSON.parse(input))); + + const [indentStr, sortBool] = args; + let json = null; + + try { + json = JSON5.parse(input); + } catch (err) { + throw new OperationError("Unable to parse input as JSON.\n" + err); } - return vkbeautify.json(input, indentStr); + + if (sortBool) json = sortKeys(json); + + return JSON.stringify(json, null, indentStr); } - /** - * Sort JSON representation of an object + * Adds various dynamic features to the JSON blob * - * @author Phillip Nordwall [phillip.nordwall@gmail.com] - * @private - * @param {object} o - * @returns {object} + * @param {string} data + * @param {Object[]} args + * @returns {html} */ - static _sort(o) { - if (Array.isArray(o)) { - return o.map(JSONBeautify._sort); - } else if ("[object Object]" === Object.prototype.toString.call(o)) { - return Object.keys(o).sort().reduce(function(a, k) { - a[k] = JSONBeautify._sort(o[k]); - return a; - }, {}); + present(data, args) { + const formatted = args[2]; + if (!formatted) return Utils.escapeHtml(data); + + const json = JSON5.parse(data); + const options = { + withLinks: true, + bigNumbers: true + }; + let html = '
'; + + if (isCollapsable(json)) { + const isArr = json instanceof Array; + html += '
' + + `` + + json2html(json, options) + + "
"; + } else { + html += json2html(json, options); } - return o; + + html += "
"; + return html; } } +/** + * Sort keys in a JSON object + * + * @author Phillip Nordwall [phillip.nordwall@gmail.com] + * @param {object} o + * @returns {object} + */ +function sortKeys(o) { + if (Array.isArray(o)) { + return o.map(sortKeys); + } else if ("[object Object]" === Object.prototype.toString.call(o)) { + return Object.keys(o).sort().reduce(function(a, k) { + a[k] = sortKeys(o[k]); + return a; + }, {}); + } + return o; +} + + +/** + * Check if arg is either an array with at least 1 element, or a dict with at least 1 key + * @returns {boolean} + */ +function isCollapsable(arg) { + return arg instanceof Object && Object.keys(arg).length > 0; +} + +/** + * Check if a string looks like a URL, based on protocol + * @returns {boolean} + */ +function isUrl(string) { + const protocols = ["http", "https", "ftp", "ftps"]; + for (let i = 0; i < protocols.length; i++) { + if (string.startsWith(protocols[i] + "://")) { + return true; + } + } + return false; +} + +/** + * Transform a json object into html representation + * + * Adapted for CyberChef by @n1474335 from jQuery json-viewer + * @author Alexandre Bodelot + * @link https://github.com/abodelot/jquery.json-viewer + * @license MIT + * + * @returns {string} + */ +function json2html(json, options) { + let html = ""; + if (typeof json === "string") { + // Escape tags and quotes + json = Utils.escapeHtml(json); + + if (options.withLinks && isUrl(json)) { + html += `${json}`; + } else { + // Escape double quotes in the rendered non-URL string. + json = json.replace(/"/g, "\\""); + html += `"${json}"`; + } + } else if (typeof json === "number" || typeof json === "bigint") { + html += `${json}`; + } else if (typeof json === "boolean") { + html += `${json}`; + } else if (json === null) { + html += 'null'; + } else if (json instanceof Array) { + if (json.length > 0) { + html += '[
    '; + for (let i = 0; i < json.length; i++) { + html += "
  1. "; + + // Add toggle button if item is collapsable + if (isCollapsable(json[i])) { + const isArr = json[i] instanceof Array; + html += '
    ' + + `` + + json2html(json[i], options) + + "
    "; + } else { + html += json2html(json[i], options); + } + + // Add comma if item is not last + if (i < json.length - 1) { + html += ','; + } + html += "
  2. "; + } + html += '
]'; + } else { + html += '[]'; + } + } else if (typeof json === "object") { + // Optional support different libraries for big numbers + // json.isLosslessNumber: package lossless-json + // json.toExponential(): packages bignumber.js, big.js, decimal.js, decimal.js-light, others? + if (options.bigNumbers && (typeof json.toExponential === "function" || json.isLosslessNumber)) { + html += `${json.toString()}`; + } else { + let keyCount = Object.keys(json).length; + if (keyCount > 0) { + html += '{
    '; + for (const key in json) { + if (Object.prototype.hasOwnProperty.call(json, key)) { + const safeKey = Utils.escapeHtml(key); + html += "
  • "; + + // Add toggle button if item is collapsable + if (isCollapsable(json[key])) { + const isArr = json[key] instanceof Array; + html += '
    ' + + `${safeKey}: ` + + json2html(json[key], options) + + "
    "; + } else { + html += safeKey + ': ' + json2html(json[key], options); + } + + // Add comma if item is not last + if (--keyCount > 0) { + html += ','; + } + html += "
  • "; + } + } + html += '
}'; + } else { + html += '{}'; + } + } + } + return html; +} + export default JSONBeautify; diff --git a/src/web/stylesheets/index.css b/src/web/stylesheets/index.css index ef35d54f..960c7006 100755 --- a/src/web/stylesheets/index.css +++ b/src/web/stylesheets/index.css @@ -34,3 +34,6 @@ @import "./layout/_operations.css"; @import "./layout/_recipe.css"; @import "./layout/_structure.css"; + +/* Operations */ +@import "./operations/json.css"; diff --git a/src/web/stylesheets/operations/json.css b/src/web/stylesheets/operations/json.css new file mode 100644 index 00000000..22c07128 --- /dev/null +++ b/src/web/stylesheets/operations/json.css @@ -0,0 +1,78 @@ +/** + * JSON styles + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + * + * Adapted for CyberChef by @n1474335 from jQuery json-viewer + * @author Alexandre Bodelot + * @link https://github.com/abodelot/jquery.json-viewer + * @license MIT + */ + +/* Root element */ +.json-document { + padding: .5em 1.5em; +} + +/* Syntax highlighting for JSON objects */ +ul.json-dict, ol.json-array { + list-style-type: none; + margin: 0 0 0 1px; + border-left: 1px dotted #ccc; + padding-left: 2em; +} +.json-string { + color: green; +} +.json-literal { + color: red; +} +.json-brace, +.json-bracket, +.json-colon, +.json-comma { + color: gray; +} + +/* Collapse */ +.json-details { + display: inline; +} +.json-details[open] { + display: contents; +} +.json-summary { + display: contents; +} + +/* Display object and array brackets when closed */ +.json-summary.json-obj::after { + color: gray; + content: "{ ... }" +} +.json-summary.json-arr::after { + color: gray; + content: "[ ... ]" +} +.json-details[open] > .json-summary.json-obj::after, +.json-details[open] > .json-summary.json-arr::after { + content: ""; +} + +/* Show arrows, even in inline mode */ +.json-summary::before { + content: "\25BC"; + color: #c0c0c0; + margin-left: -12px; + margin-right: 5px; + display: inline-block; + transform: rotate(-90deg); +} +.json-summary:hover::before { + color: #aaa; +} +.json-details[open] > .json-summary::before { + transform: rotate(0deg); +} diff --git a/tests/operations/tests/JSONBeautify.mjs b/tests/operations/tests/JSONBeautify.mjs index 11578678..211f96bb 100644 --- a/tests/operations/tests/JSONBeautify.mjs +++ b/tests/operations/tests/JSONBeautify.mjs @@ -16,7 +16,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, ], }, @@ -27,7 +27,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, ], }, @@ -38,8 +38,12 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, + { + op: "HTML To Text", + args: [] + } ], }, { @@ -49,7 +53,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, ], }, @@ -60,7 +64,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, ], }, @@ -71,7 +75,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, ], }, @@ -82,7 +86,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: ["\t", false], + args: ["\t", false, false], }, ], }, @@ -93,8 +97,12 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: [" ", false], + args: [" ", false, false], }, + { + op: "HTML To Text", + args: [] + } ], }, { @@ -104,8 +112,12 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: ["\t", false], + args: ["\t", false, false], }, + { + op: "HTML To Text", + args: [] + } ], }, { @@ -115,8 +127,12 @@ TestRegister.addTests([ recipeConfig: [ { op: "JSON Beautify", - args: ["\t", true], + args: ["\t", true, false], }, + { + op: "HTML To Text", + args: [] + } ], }, ]); From 7197a434c2969c5504208c9b3a045d326892a4da Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 8 Jun 2022 18:07:32 +0100 Subject: [PATCH 28/72] 9.38.8 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd04e5d4..a923a128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.38.7", + "version": "9.38.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.38.7", + "version": "9.38.8", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 72208f29..eac168ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.38.7", + "version": "9.38.8", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 2bf1ac6b9cba7545765fe88eff776fd8117a78a2 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 8 Jun 2022 18:59:27 +0100 Subject: [PATCH 29/72] 'Parse X.509 Certificate' Issuer and Subject name parsing improved. Closes #1365 --- src/core/lib/PublicKey.mjs | 34 +++++++------------- src/core/operations/ParseX509Certificate.mjs | 10 +++--- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/src/core/lib/PublicKey.mjs b/src/core/lib/PublicKey.mjs index 8c04cdd9..ea931d7e 100644 --- a/src/core/lib/PublicKey.mjs +++ b/src/core/lib/PublicKey.mjs @@ -9,35 +9,25 @@ import { toHex, fromHex } from "./Hex.mjs"; /** - * Formats Distinguished Name (DN) strings. + * Formats Distinguished Name (DN) objects to strings. * - * @param {string} dnStr + * @param {Object} dnObj * @param {number} indent * @returns {string} */ -export function formatDnStr(dnStr, indent) { - const fields = dnStr.substr(1).replace(/([^\\])\//g, "$1$1/").split(/[^\\]\//); - let output = "", - maxKeyLen = 0, - key, - value, - i, - str; +export function formatDnObj(dnObj, indent) { + let output = ""; - for (i = 0; i < fields.length; i++) { - if (!fields[i].length) continue; + const maxKeyLen = dnObj.array.reduce((max, item) => { + return item[0].type.length > max ? item[0].type.length : max; + }, 0); - key = fields[i].split("=")[0]; + for (let i = 0; i < dnObj.array.length; i++) { + if (!dnObj.array[i].length) continue; - maxKeyLen = key.length > maxKeyLen ? key.length : maxKeyLen; - } - - for (i = 0; i < fields.length; i++) { - if (!fields[i].length) continue; - - key = fields[i].split("=")[0]; - value = fields[i].split("=")[1]; - str = key.padEnd(maxKeyLen, " ") + " = " + value + "\n"; + const key = dnObj.array[i][0].type; + const value = dnObj.array[i][0].value; + const str = `${key.padEnd(maxKeyLen, " ")} = ${value}\n`; output += str.padStart(indent + str.length, " "); } diff --git a/src/core/operations/ParseX509Certificate.mjs b/src/core/operations/ParseX509Certificate.mjs index 2c123f45..aeb5f677 100644 --- a/src/core/operations/ParseX509Certificate.mjs +++ b/src/core/operations/ParseX509Certificate.mjs @@ -7,7 +7,7 @@ import r from "jsrsasign"; import { fromBase64 } from "../lib/Base64.mjs"; import { toHex } from "../lib/Hex.mjs"; -import { formatByteStr, formatDnStr } from "../lib/PublicKey.mjs"; +import { formatByteStr, formatDnObj } from "../lib/PublicKey.mjs"; import Operation from "../Operation.mjs"; import Utils from "../Utils.mjs"; @@ -76,8 +76,8 @@ class ParseX509Certificate extends Operation { } const sn = cert.getSerialNumberHex(), - issuer = cert.getIssuerString(), - subject = cert.getSubjectString(), + issuer = cert.getIssuer(), + subject = cert.getSubject(), pk = cert.getPublicKey(), pkFields = [], sig = cert.getSignatureValueHex(); @@ -170,10 +170,10 @@ class ParseX509Certificate extends Operation { extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0]; } catch (err) {} - const issuerStr = formatDnStr(issuer, 2), + const issuerStr = formatDnObj(issuer, 2), nbDate = formatDate(cert.getNotBefore()), naDate = formatDate(cert.getNotAfter()), - subjectStr = formatDnStr(subject, 2); + subjectStr = formatDnObj(subject, 2); return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)}) Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn}) From 8c71b0b8df2fcb5291c0d541b3d78542de29e8a8 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 8 Jun 2022 18:59:36 +0100 Subject: [PATCH 30/72] 9.38.9 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a923a128..9219965f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.38.8", + "version": "9.38.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.38.8", + "version": "9.38.9", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index eac168ea..3cd4e6a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.38.8", + "version": "9.38.9", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 64eae37788092b4f2f03861b9a2c749590fa3773 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Thu, 9 Jun 2022 10:02:38 +0100 Subject: [PATCH 31/72] Added tests for ELF-Info --- src/core/operations/ELFInfo.mjs | 2 +- tests/operations/tests/ELFInfo.mjs | 66 +++++ tests/samples/Executables.mjs | 375 +++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 tests/samples/Executables.mjs diff --git a/src/core/operations/ELFInfo.mjs b/src/core/operations/ELFInfo.mjs index 6fa46c54..9153e24f 100644 --- a/src/core/operations/ELFInfo.mjs +++ b/src/core/operations/ELFInfo.mjs @@ -125,7 +125,7 @@ class ELFInfo extends Operation { ehResult.push("Format:".padEnd(align) + `${format === 1 ? "32-bit" : "64-bit"}`); endianness = stream.readInt(1) === 1 ? "le" : "be"; - ehResult.push("Endianness:".padEnd(align) + `${endianness === 1 ? "Little" : "Big"}`); + ehResult.push("Endianness:".padEnd(align) + `${endianness === "le" ? "Little" : "Big"}`); ehResult.push("Version:".padEnd(align) + `${stream.readInt(1).toString()}`); diff --git a/tests/operations/tests/ELFInfo.mjs b/tests/operations/tests/ELFInfo.mjs index cabf1344..fad9a05c 100644 --- a/tests/operations/tests/ELFInfo.mjs +++ b/tests/operations/tests/ELFInfo.mjs @@ -4,6 +4,12 @@ * @license Apache-2.0 */ import TestRegister from "../../lib/TestRegister.mjs"; +import {ELF32_LE, ELF32_BE, ELF64_LE, ELF64_BE} from "../../samples/Executables.mjs"; + +const ELF32_LE_OUTPUT = "============================== ELF Header ==============================\nMagic: \x7fELF\nFormat: 32-bit\nEndianness: Little\nVersion: 1\nABI: System V\nABI Version: 0\nType: Executable File\nInstruction Set Architecture: x86\nELF Version: 1\nEntry Point: 0x8062150\nEntry PHOFF: 0x34\nEntry SHOFF: 0x54\nFlags: 00000000\nELF Header Size: 52 bytes\nProgram Header Size: 32 bytes\nProgram Header Entries: 1\nSection Header Size: 40 bytes\nSection Header Entries: 3\nSection Header Names: 0\n\n============================== Program Header ==============================\nProgram Header Type: Program Header Table\nOffset Of Segment: 52\nVirtual Address of Segment: 134512692\nPhysical Address of Segment: 134512692\nSize of Segment: 256 bytes\nSize of Segment in Memory: 256 bytes\nFlags: Execute,Read\n\n============================== Section Header ==============================\nType: String Table\nSection Name: .shstrab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 204\nSection Size: 28\nAssociated Section: 0\nSection Extra Information: 0\n\nType: Symbol Table\nSection Name: .symtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 230\nSection Size: 16\nAssociated Section: 0\nSection Extra Information: 0\n\nType: String Table\nSection Name: .strtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 245\nSection Size: 4\nAssociated Section: 0\nSection Extra Information: 0\n\n============================== Symbol Table ==============================\nSymbol Name: test"; +const ELF32_BE_OUTPUT = "============================== ELF Header ==============================\nMagic: \x7fELF\nFormat: 32-bit\nEndianness: Big\nVersion: 1\nABI: System V\nABI Version: 0\nType: Executable File\nInstruction Set Architecture: x86\nELF Version: 1\nEntry Point: 0x8062150\nEntry PHOFF: 0x34\nEntry SHOFF: 0x54\nFlags: 00000000\nELF Header Size: 52 bytes\nProgram Header Size: 32 bytes\nProgram Header Entries: 1\nSection Header Size: 40 bytes\nSection Header Entries: 3\nSection Header Names: 0\n\n============================== Program Header ==============================\nProgram Header Type: Program Header Table\nOffset Of Segment: 52\nVirtual Address of Segment: 134512692\nPhysical Address of Segment: 134512692\nSize of Segment: 256 bytes\nSize of Segment in Memory: 256 bytes\nFlags: Execute,Read\n\n============================== Section Header ==============================\nType: String Table\nSection Name: .shstrab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 204\nSection Size: 28\nAssociated Section: 0\nSection Extra Information: 0\n\nType: Symbol Table\nSection Name: .symtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 230\nSection Size: 16\nAssociated Section: 0\nSection Extra Information: 0\n\nType: String Table\nSection Name: .strtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 245\nSection Size: 4\nAssociated Section: 0\nSection Extra Information: 0\n\n============================== Symbol Table ==============================\nSymbol Name: test"; +const ELF64_LE_OUTPUT = "============================== ELF Header ==============================\nMagic: \x7fELF\nFormat: 64-bit\nEndianness: Little\nVersion: 1\nABI: System V\nABI Version: 0\nType: Executable File\nInstruction Set Architecture: AMD x86-64\nELF Version: 1\nEntry Point: 0x8062150\nEntry PHOFF: 0x40\nEntry SHOFF: 0x78\nFlags: 00000000\nELF Header Size: 64 bytes\nProgram Header Size: 56 bytes\nProgram Header Entries: 1\nSection Header Size: 64 bytes\nSection Header Entries: 3\nSection Header Names: 0\n\n============================== Program Header ==============================\nProgram Header Type: Program Header Table\nFlags: Execute,Read\nOffset Of Segment: 52\nVirtual Address of Segment: 134512692\nPhysical Address of Segment: 134512692\nSize of Segment: 256 bytes\nSize of Segment in Memory: 256 bytes\n\n============================== Section Header ==============================\nType: String Table\nSection Name: .shstrab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 312\nSection Size: 28\nAssociated Section: 0\nSection Extra Information: 0\n\nType: Symbol Table\nSection Name: .symtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 336\nSection Size: 16\nAssociated Section: 0\nSection Extra Information: 0\n\nType: String Table\nSection Name: .strtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 361\nSection Size: 4\nAssociated Section: 0\nSection Extra Information: 0\n\n============================== Symbol Table ==============================\nSymbol Name: test"; +const ELF64_BE_OUTPUT = "============================== ELF Header ==============================\nMagic: \x7fELF\nFormat: 64-bit\nEndianness: Big\nVersion: 1\nABI: System V\nABI Version: 0\nType: Executable File\nInstruction Set Architecture: AMD x86-64\nELF Version: 1\nEntry Point: 0x8062150\nEntry PHOFF: 0x40\nEntry SHOFF: 0x78\nFlags: 00000000\nELF Header Size: 64 bytes\nProgram Header Size: 56 bytes\nProgram Header Entries: 1\nSection Header Size: 64 bytes\nSection Header Entries: 3\nSection Header Names: 0\n\n============================== Program Header ==============================\nProgram Header Type: Program Header Table\nFlags: Execute,Read\nOffset Of Segment: 52\nVirtual Address of Segment: 134512692\nPhysical Address of Segment: 134512692\nSize of Segment: 256 bytes\nSize of Segment in Memory: 256 bytes\n\n============================== Section Header ==============================\nType: String Table\nSection Name: .shstrab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 312\nSection Size: 28\nAssociated Section: 0\nSection Extra Information: 0\n\nType: Symbol Table\nSection Name: .symtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 336\nSection Size: 16\nAssociated Section: 0\nSection Extra Information: 0\n\nType: String Table\nSection Name: .strtab\nFlags: \nSection Vaddr in memory: 0\nOffset of the section: 361\nSection Size: 4\nAssociated Section: 0\nSection Extra Information: 0\n\n============================== Symbol Table ==============================\nSymbol Name: test"; TestRegister.addTests([ { @@ -17,4 +23,64 @@ TestRegister.addTests([ }, ], }, + { + name: "ELF Info 32-bit ELF Little Endian.", + input: ELF32_LE, + expectedOutput: ELF32_LE_OUTPUT, + recipeConfig: [ + { + op: "From Hex", + args: ["None"], + }, + { + op: "ELF Info", + args: [], + }, + ], + }, + { + name: "ELF Info 32-bit ELF Big Endian.", + input: ELF32_BE, + expectedOutput: ELF32_BE_OUTPUT, + recipeConfig: [ + { + op: "From Hex", + args: ["None"], + }, + { + op: "ELF Info", + args: [], + }, + ], + }, + { + name: "ELF Info 64-bit ELF Little Endian.", + input: ELF64_LE, + expectedOutput: ELF64_LE_OUTPUT, + recipeConfig: [ + { + op: "From Hex", + args: ["None"], + }, + { + op: "ELF Info", + args: [], + }, + ], + }, + { + name: "ELF Info 64-bit ELF Big Endian.", + input: ELF64_BE, + expectedOutput: ELF64_BE_OUTPUT, + recipeConfig: [ + { + op: "From Hex", + args: ["None"], + }, + { + op: "ELF Info", + args: [], + }, + ], + }, ]); diff --git a/tests/samples/Executables.mjs b/tests/samples/Executables.mjs new file mode 100644 index 00000000..389836e2 --- /dev/null +++ b/tests/samples/Executables.mjs @@ -0,0 +1,375 @@ +/** + * Executables in various formats for use in tests. + * + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ + +/** + * ---------------ELF Header--------------- + * 7f454c46 - Magic: .ELF + * 01 - Format: 32 bit + * 01 - Endianness: Little + * 01 - ELF Version: 1 + * 00 - Target ABI: System V + * 00 - ABI Version: 0 + * 00000000000000 - Padding + * 0200 - File Type: Executable File + * 0300 - ISA: x86 + * 01000000 - ELF Version: 1 + * 50210608 - Entry Point: 0x8062150 + * 34000000 - PH Offset: 0x34 + * 54000000 - SH Offset: 0x54 + * 00000000 - Flags: 0 + * 3400 - ELF Header Size: 0x34 + * 2000 - PH Header Size: 0x20 + * 0100 - PH Entries: 1 + * 2800 - SH Size: 0x28 + * 0300 - SH Entries: 0x3 + * 0000 - SH Names Offset: 0x0 + * + * -------------Program Header------------- + * 06000000 - PH Type: Program Header Table + * 34000000 - Segment Offset: 0x34 + * 34800408 - VAddr of segment: 134512692 + * 34800408 - PAddr of segment: 134512692 + * 00010000 - Size of segment: 256 + * 00010000 - Size of segment: 256 + * 05000000 - Flags: Execute,Read + * 04000000 - Alignment + * + * --------------SH .shstrtab-------------- + * 00000000 - SH Name Offset: 0 + * 03000000 - SH Type: String Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * cc000000 - Section offset: 204 + * 1c000000 - Section size: 28 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 00000000 - Entry Size: 0 + * + * ---------------SH .symtab--------------- + * 09000000 - SH Name Offset: 9 + * 02000000 - SH Type: Symbol Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * e6000000 - Section offset: 230 + * 10000000 - Section size: 16 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 10000000 - Entry Size: 16 + * + * ---------------SH .strtab--------------- + * 11000000 - SH Name Offset: 17 + * 03000000 - SH Type: String Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * f5000000 - Section offset: 245 + * 04000000 - Section size: 4 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 00000000 - Entry Size: 0 + * + * ---------------.shstrtab--------------- + * 2e73687374726162002e73796d746162002e73747274616200 - .shstrab\0.symtab\0.strtab\0 + * + * ----------------.symtab---------------- + * 00000000 - Name Offset: 0 + * 00000000 - Value: 0 + * 00000000 - Size: 0 + * 00 - Info + * 00 - other + * 0000 - shdx + * + * ----------------.strtab---------------- + * 74657374 - test + */ +export const ELF32_LE = "7f454c46010101000000000000000000020003000100000050210608340000005400000000000000340020000100280003000000" + + "0600000034000000348004083480040800010000000100000500000004000000" + + "00000000030000000000000000000000cc0000001c00000000000000000000000000000000000000" + + "09000000020000000000000000000000e60000001000000000000000000000000000000010000000" + + "11000000030000000000000000000000f50000000400000000000000000000000000000000000000" + + "2e73687374726162002e73796d746162002e73747274616200" + + "00000000000000000000000000000000" + + "74657374"; + +/** + * ---------------ELF Header--------------- + * 7f454c46 - Magic: .ELF + * 01 - Format: 32 bit + * 02 - Endianness: Big + * 01 - ELF Version: 1 + * 00 - Target ABI: System V + * 00 - ABI Version: 0 + * 00000000000000 - Padding + * 0002 - File Type: Executable File + * 0003 - ISA: x86 + * 00000001 - ELF Version: 1 + * 08062150 - Entry Point: 0x8062150 + * 00000034 - PH Offset: 0x34 + * 00000054 - SH Offset: 0x54 + * 00000000 - Flags: 0 + * 0034 - ELF Header Size: 0x34 + * 0020 - PH Header Size: 0x20 + * 0001 - PH Entries: 1 + * 0028 - SH Size: 0x28 + * 0003 - SH Entries: 0x3 + * 0000 - SH Names Offset: 0x0 + * + * -------------Program Header------------- + * 00000006 - PH Type: Program Header Table + * 00000034 - Segment Offset: 0x34 + * 08048034 - VAddr of segment: 134512692 + * 08048034 - PAddr of segment: 134512692 + * 00000100 - Size of segment: 256 + * 00000100 - Size of segment: 256 + * 00000005 - Flags: Execute,Read + * 00000004 - Alignment + * + * --------------SH .shstrtab-------------- + * 00000000 - SH Name Offset: 0 + * 00000003 - SH Type: String Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * 000000cc - Section offset: 204 + * 0000001c - Section size: 28 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 00000000 - Entry Size: 0 + * + * ---------------SH .symtab--------------- + * 00000009 - SH Name Offset: 9 + * 00000002 - SH Type: Symbol Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * 000000e6 - Section offset: 230 + * 00000010 - Section size: 16 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 00000010 - Entry Size: 16 + * + * ---------------SH .strtab--------------- + * 00000011 - SH Name Offset: 17 + * 00000003 - SH Type: String Table + * 00000000 - Flags: + * 00000000 - VAddr of section: 0 + * 000000f5 - Section offset: 245 + * 00000004 - Section size: 4 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 00000000 - Alignment + * 00000000 - Entry Size: 0 + * + * ---------------.shstrtab--------------- + * 2e73687374726162002e73796d746162002e73747274616200 - .shstrab\0.symtab\0.strtab\0 + * + * ----------------.symtab---------------- + * 00000000 - Name Offset: 0 + * 00000000 - Value: 0 + * 00000000 - Size: 0 + * 00 - Info + * 00 - other + * 0000 - shdx + * + * ----------------.strtab---------------- + * 74657374 - test + */ +export const ELF32_BE = "7f454c46010201000000000000000000000200030000000108062150000000340000005400000000003400200001002800030000" + + "0000000600000034080480340804803400000100000001000000000500000004" + + "00000000000000030000000000000000000000cc0000001c00000000000000000000000000000000" + + "00000009000000020000000000000000000000e60000001000000000000000000000000000000010" + + "00000011000000030000000000000000000000f50000000400000000000000000000000000000000" + + "2e73687374726162002e73796d746162002e73747274616200" + + "00000000000000000000000000000000" + + "74657374"; + +/** + * ---------------ELF Header--------------- + * 7f454c46 - Magic: .ELF + * 02 - Format: 64 bit + * 01 - Endianness: Little + * 01 - ELF Version: 1 + * 00 - Target ABI: System V + * 00 - ABI Version: 0 + * 00000000000000 - Padding + * 0200 - File Type: Executable File + * 3e00 - ISA: AMD x86-64 + * 01000000 - ELF Version: 1 + * 5021060800000000 - Entry Point: 0x8062150 + * 4000000000000000 - PH Offset: 0x40 + * 7800000000000000 - SH Offset: 0x78 + * 00000000 - Flags: 0 + * 4000 - ELF Header Size: 0x40 + * 3800 - PH Header Size: 0x38 + * 0100 - PH Entries: 1 + * 4000 - SH Size: 0x40 + * 0300 - SH Entries: 0x3 + * 0000 - SH Names Offset: 0x0 + * + * -------------Program Header------------- + * 06000000 - PH Type: Program Header Table + * 05000000 - Flags: Execute,Read + * 3400000000000000 - Segment Offset: 0x34 + * 3480040800000000 - VAddr of segment: 134512692 + * 3480040800000000 - PAddr of segment: 134512692 + * 0001000000000000 - Size of segment: 256 + * 0001000000000000 - Size of segment: 256 + * 0400000000000000 - Alignment + * + * --------------SH .shstrtab-------------- + * 00000000 - SH Name Offset: 0 + * 03000000 - SH Type: String Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 3801000000000000 - Section offset: 312 + * 1c00000000000000 - Section size: 28 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 0000000000000000 - Entry Size: 0 + * + * ---------------SH .symtab--------------- + * 09000000 - SH Name Offset: 9 + * 02000000 - SH Type: Symbol Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 5001000000000000 - Section offset: 336 + * 1000000000000000 - Section size: 16 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 1800000000000000 - Entry Size: 24 + * + * ---------------SH .strtab--------------- + * 11000000 - SH Name Offset: 17 + * 03000000 - SH Type: String Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 6901000000000000 - Section offset: 361 + * 0400000000000000 - Section size: 4 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 0000000000000000 - Entry Size: 0 + * + * ---------------.shstrtab--------------- + * 2e73687374726162002e73796d746162002e73747274616200 - .shstrab\0.symtab\0.strtab\0 + * + * ----------------.symtab---------------- + * 00000000 - Name Offset: 0 + * 00 - Info + * 00 - other + * 0000 - shdx + * 0000000000000000 - Value: 0 + * 0000000000000000 - Size: 0 + * + * ----------------.strtab---------------- + * 74657374 - test + */ +export const ELF64_LE = "7f454c4602010100000000000000000002003e000100000050210608000000004000000000000000780000000000000000000000400038000100400003000000" + + "0600000005000000340000000000000034800408000000003480040800000000000100000000000000010000000000000400000000000000" + + "00000000030000000000000000000000000000000000000038010000000000001c00000000000000000000000000000000000000000000000000000000000000" + + "09000000020000000000000000000000000000000000000050010000000000001000000000000000000000000000000000000000000000001800000000000000" + + "11000000030000000000000000000000000000000000000069010000000000000400000000000000000000000000000000000000000000000000000000000000" + + "2e73687374726162002e73796d746162002e73747274616200" + + "000000000000000000000000000000000000000000000000" + + "74657374"; + +/** + * ---------------ELF Header--------------- + * 7f454c46 - Magic: .ELF + * 02 - Format: 64 bit + * 02 - Endianness: Big + * 01 - ELF Version: 1 + * 00 - Target ABI: System V + * 00 - ABI Version: 0 + * 00000000000000 - Padding + * 0002 - File Type: Executable File + * 003e - ISA: AMD x86-64 + * 00000001 - ELF Version: 1 + * 0000000008062150 - Entry Point: 0x8062150 + * 0000000000000040 - PH Offset: 0x40 + * 0000000000000078 - SH Offset: 0x78 + * 00000000 - Flags: 0 + * 0040 - ELF Header Size: 0x40 + * 0038 - PH Header Size: 0x38 + * 0001 - PH Entries: 1 + * 0040 - SH Size: 0x40 + * 0003 - SH Entries: 0x3 + * 0000 - SH Names Offset: 0x0 + * + * -------------Program Header------------- + * 00000006 - PH Type: Program Header Table + * 00000005 - Flags: Execute,Read + * 0000000000000034 - Segment Offset: 0x34 + * 0000000008048034 - VAddr of segment: 134512692 + * 0000000008048034 - PAddr of segment: 134512692 + * 0000000000000100 - Size of segment: 256 + * 0000000000000100 - Size of segment: 256 + * 0400000000000000 - Alignment + * + * --------------SH .shstrtab-------------- + * 00000000 - SH Name Offset: 0 + * 00000003 - SH Type: String Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 0000000000000138 - Section offset: 312 + * 000000000000001c - Section size: 28 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 0000000000000000 - Entry Size: 0 + * + * ---------------SH .symtab--------------- + * 00000009 - SH Name Offset: 9 + * 00000002 - SH Type: Symbol Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 0000000000000150 - Section offset: 336 + * 0000000000000010 - Section size: 16 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 0000000000000018 - Entry Size: 24 + * + * ---------------SH .strtab--------------- + * 00000011 - SH Name Offset: 17 + * 00000003 - SH Type: String Table + * 0000000000000000 - Flags: + * 0000000000000000 - VAddr of section: 0 + * 0000000000000169 - Section offset: 361 + * 0000000000000004 - Section size: 4 + * 00000000 - Associated: 0 + * 00000000 - Extra Info: 0 + * 0000000000000000 - Alignment + * 0000000000000000 - Entry Size: 0 + * + * ---------------.shstrtab--------------- + * 2e73687374726162002e73796d746162002e73747274616200 - .shstrab\0.symtab\0.strtab\0 + * + * ----------------.symtab---------------- + * 00000000 - Name Offset: 0 + * 00 - Info + * 00 - other + * 0000 - shdx + * 0000000000000000 - Value: 0 + * 0000000000000000 - Size: 0 + * + * ----------------.strtab---------------- + * 74657374 - test + */ +export const ELF64_BE = "7f454c460202010000000000000000000002003e0000000100000000080621500000000000000040000000000000007800000000004000380001004000030000" + + "0000000600000005000000000000003400000000080480340000000008048034000000000000010000000000000001000400000000000000" + + "0000000000000003000000000000000000000000000000000000000000000138000000000000001c000000000000000000000000000000000000000000000000" + + "00000009000000020000000000000000000000000000000000000000000001500000000000000010000000000000000000000000000000000000000000000018" + + "00000011000000030000000000000000000000000000000000000000000001690000000000000004000000000000000000000000000000000000000000000000" + + "2e73687374726162002e73796d746162002e73747274616200" + + "000000000000000000000000000000000000000000000000" + + "74657374"; From d3de91de851f185966010f0523d0adb31cb5fa64 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Thu, 9 Jun 2022 10:12:19 +0100 Subject: [PATCH 32/72] Modify stream library to support reading until a null byte --- src/core/lib/Stream.mjs | 6 ++++-- src/core/operations/ELFInfo.mjs | 5 +---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/core/lib/Stream.mjs b/src/core/lib/Stream.mjs index b2a183f4..18ce71c3 100644 --- a/src/core/lib/Stream.mjs +++ b/src/core/lib/Stream.mjs @@ -48,12 +48,14 @@ export default class Stream { * Interpret the following bytes as a string, stopping at the next null byte or * the supplied limit. * - * @param {number} numBytes + * @param {number} [numBytes=-1] * @returns {string} */ - readString(numBytes) { + readString(numBytes=-1) { if (this.position > this.length) return undefined; + if (numBytes === -1) numBytes = this.length - this.position; + let result = ""; for (let i = this.position; i < this.position + numBytes; i++) { const currentByte = this.bytes[i]; diff --git a/src/core/operations/ELFInfo.mjs b/src/core/operations/ELFInfo.mjs index 9153e24f..e5e63094 100644 --- a/src/core/operations/ELFInfo.mjs +++ b/src/core/operations/ELFInfo.mjs @@ -66,10 +66,7 @@ class ELFInfo extends Operation { const preMove = stream.position; stream.moveTo(namesOffset + nameOffset); - let nameResult = ""; - let elem = 0; - while ((elem = stream.readInt(1, endianness)) !== 0) - nameResult += String.fromCharCode(elem); + let nameResult = stream.readString(); stream.moveTo(preMove); return nameResult; } From 049690fea2a253b7ed513f194683d7f3b5d7fc32 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Thu, 9 Jun 2022 10:15:47 +0100 Subject: [PATCH 33/72] Linting modifications --- src/core/operations/ELFInfo.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/ELFInfo.mjs b/src/core/operations/ELFInfo.mjs index e5e63094..815d3cf1 100644 --- a/src/core/operations/ELFInfo.mjs +++ b/src/core/operations/ELFInfo.mjs @@ -66,7 +66,7 @@ class ELFInfo extends Operation { const preMove = stream.position; stream.moveTo(namesOffset + nameOffset); - let nameResult = stream.readString(); + const nameResult = stream.readString(); stream.moveTo(preMove); return nameResult; } From cc3033266c6a5e521ec2af00a50a491ada72cd65 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 9 Jun 2022 15:17:08 +0100 Subject: [PATCH 34/72] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ src/core/config/scripts/newMinorVersion.mjs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ad241ed..af8843e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.39.0] - 2022-06-09 +- Added 'ELF Info' operation [@n1073645] | [#1364] + ### [9.38.0] - 2022-05-30 - Added 'Parse TCP' operation [@n1474335] | [a895d1d] @@ -291,6 +294,7 @@ All major and minor version changes will be documented in this file. Details of +[9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0 [9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0 [9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0 [9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0 @@ -508,3 +512,4 @@ All major and minor version changes will be documented in this file. Details of [#1244]: https://github.com/gchq/CyberChef/pull/1244 [#1313]: https://github.com/gchq/CyberChef/pull/1313 [#1326]: https://github.com/gchq/CyberChef/pull/1326 +[#1364]: https://github.com/gchq/CyberChef/pull/1364 diff --git a/src/core/config/scripts/newMinorVersion.mjs b/src/core/config/scripts/newMinorVersion.mjs index e1a682f7..adfdf6f7 100644 --- a/src/core/config/scripts/newMinorVersion.mjs +++ b/src/core/config/scripts/newMinorVersion.mjs @@ -131,7 +131,7 @@ const getFeature = function() { // PR IDs prIDs.forEach(prID => { - changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n/, "$1" + prID + "\n\n"); + changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n"); }); fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData); From a3b846638fc70e9d6ac39ff71dc310d471659a50 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 9 Jun 2022 15:17:14 +0100 Subject: [PATCH 35/72] 9.39.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9219965f..c3383504 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.38.9", + "version": "9.39.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.38.9", + "version": "9.39.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 3cd4e6a8..ca558fda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.38.9", + "version": "9.39.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 2267569c8d5b7fddc16e66b94f1e9cfb0d5b9af0 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 9 Jun 2022 16:32:23 +0100 Subject: [PATCH 36/72] Fixed lint --- src/core/operations/ConditionalJump.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/operations/ConditionalJump.mjs b/src/core/operations/ConditionalJump.mjs index b0c65ddd..74bf1d21 100644 --- a/src/core/operations/ConditionalJump.mjs +++ b/src/core/operations/ConditionalJump.mjs @@ -74,8 +74,7 @@ class ConditionalJump extends Operation { if (!invert && strMatch || invert && !strMatch) { state.progress = jmpIndex; state.numJumps++; - } - else { + } else { state.numJumps = 0; } } From 54fdc05e3a6de7fc781d78aa3dff72d31d546949 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 9 Jun 2022 16:32:32 +0100 Subject: [PATCH 37/72] 9.39.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3383504..ffde1368 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.0", + "version": "9.39.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.0", + "version": "9.39.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index ca558fda..cea3fb19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.0", + "version": "9.39.1", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 191d7f11f745e73d3c3b13436651be33a3fd1396 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 10 Jun 2022 15:25:12 +0100 Subject: [PATCH 38/72] Improve the subsection description --- src/core/operations/Subsection.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/Subsection.mjs b/src/core/operations/Subsection.mjs index 86980e40..7b51cdb4 100644 --- a/src/core/operations/Subsection.mjs +++ b/src/core/operations/Subsection.mjs @@ -22,7 +22,7 @@ class Subsection extends Operation { this.name = "Subsection"; this.flowControl = true; this.module = "Default"; - this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.

You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on."; + this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.

You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.

Use the Merge operation to reset the effects of subsection."; this.infoURL = ""; this.inputType = "string"; this.outputType = "string"; From 906727f1337bc2a5dc330f10d4664fce683c584c Mon Sep 17 00:00:00 2001 From: John L Date: Tue, 14 Jun 2022 10:23:13 +0100 Subject: [PATCH 39/72] Base85 improvements --- src/core/operations/FromBase45.mjs | 16 ++++++++-- src/core/operations/FromBase85.mjs | 14 ++++++++- tests/lib/TestRegister.mjs | 13 +++++++- tests/operations/index.mjs | 1 + tests/operations/tests/Base85.mjs | 48 ++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 tests/operations/tests/Base85.mjs diff --git a/src/core/operations/FromBase45.mjs b/src/core/operations/FromBase45.mjs index 2625d782..8cb202bc 100644 --- a/src/core/operations/FromBase45.mjs +++ b/src/core/operations/FromBase45.mjs @@ -32,7 +32,12 @@ class FromBase45 extends Operation { name: "Alphabet", type: "string", value: ALPHABET - } + }, + { + name: "Remove non-alphabet chars", + type: "boolean", + value: true + }, ]; this.highlight = highlightFromBase45; @@ -46,10 +51,17 @@ class FromBase45 extends Operation { */ run(input, args) { if (!input) return []; - const alphabet = Utils.expandAlphRange(args[0]); + const alphabet = Utils.expandAlphRange(args[0]).join(""); + const removeNonAlphChars = args[1]; const res = []; + // Remove non-alphabet characters + if (removeNonAlphChars) { + const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g"); + input = input.replace(re, ""); + } + for (const triple of Utils.chunked(input, 3)) { triple.reverse(); let b = 0; diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index c874d5dc..31f00efc 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -32,6 +32,11 @@ class FromBase85 extends Operation { type: "editableOption", value: ALPHABET_OPTIONS }, + { + name: "Remove non-alphabet chars", + type: "boolean", + value: true + }, ]; } @@ -43,6 +48,7 @@ class FromBase85 extends Operation { run(input, args) { const alphabet = Utils.expandAlphRange(args[0]).join(""), encoding = alphabetName(alphabet), + removeNonAlphChars = args[1], result = []; if (alphabet.length !== 85 || @@ -50,6 +56,12 @@ class FromBase85 extends Operation { throw new OperationError("Alphabet must be of length 85"); } + // Remove non-alphabet characters + if (removeNonAlphChars) { + const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g"); + input = input.replace(re, ""); + } + if (input.length === 0) return []; const matches = input.match(/<~(.+?)~>/); @@ -69,7 +81,7 @@ class FromBase85 extends Operation { .map((chr, idx) => { const digit = alphabet.indexOf(chr); if (digit < 0 || digit > 84) { - throw `Invalid character '${chr}' at index ${idx}`; + throw `Invalid character '${chr}' at index ${i + idx}`; } return digit; }); diff --git a/tests/lib/TestRegister.mjs b/tests/lib/TestRegister.mjs index 452f3f55..69e86088 100644 --- a/tests/lib/TestRegister.mjs +++ b/tests/lib/TestRegister.mjs @@ -84,7 +84,18 @@ class TestRegister { if (result.error) { if (test.expectedError) { - ret.status = "passing"; + if (result.error.displayStr === test.expectedOutput) { + ret.status = "passing"; + } else { + console.log(result); + ret.status = "failing"; + ret.output = [ + "Expected", + "\t" + test.expectedOutput.replace(/\n/g, "\n\t"), + "Received", + "\t" + result.error.displayStr.replace(/\n/g, "\n\t"), + ].join("\n"); + } } else { ret.status = "erroring"; ret.output = result.error.displayStr; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index b6beb081..d198c408 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -24,6 +24,7 @@ import "./tests/Base45.mjs"; import "./tests/Base58.mjs"; import "./tests/Base64.mjs"; import "./tests/Base62.mjs"; +import "./tests/Base85.mjs"; import "./tests/BitwiseOp.mjs"; import "./tests/ByteRepr.mjs"; import "./tests/CartesianProduct.mjs"; diff --git a/tests/operations/tests/Base85.mjs b/tests/operations/tests/Base85.mjs new file mode 100644 index 00000000..2cf022f9 --- /dev/null +++ b/tests/operations/tests/Base85.mjs @@ -0,0 +1,48 @@ +/** + * Base85 tests + * + * @author john19696 + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +// Example from Wikipedia +const wpExample = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure." +// Escape newline, quote & backslash +const wpOutput = "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKFCj@.4Gp$d7F!,L7@<6@)/0JDEF@3BB/F*&OCAfu2/AKYi(\ +DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF-FD5W8ARlolDIal(\ +DIdu\ +D.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c"; + +TestRegister.addTests([ + { + name: "To Base85", + input: wpExample, + expectedOutput: wpOutput, + recipeConfig: [ + { "op": "To Base85", + "args": ["!-u"] } + ] + }, + { + name: "From Base85", + input: wpOutput + "\n", + expectedOutput: wpExample, + recipeConfig: [ + { "op": "From Base85", + "args": ["!-u", true] } + ] + }, + { + name: "From Base85", + input: wpOutput + "v", + expectedError: true, + expectedOutput: "From Base85 - Invalid character 'v' at index 337", + recipeConfig: [ + { "op": "From Base85", + "args": ["!-u", false] } + ] + }, +]); \ No newline at end of file From 00d754d46695d0f8278e093dc63b75c126de7831 Mon Sep 17 00:00:00 2001 From: John L Date: Tue, 14 Jun 2022 15:57:04 +0100 Subject: [PATCH 40/72] lint fixes --- tests/operations/tests/Base85.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/operations/tests/Base85.mjs b/tests/operations/tests/Base85.mjs index 2cf022f9..8e1d0a23 100644 --- a/tests/operations/tests/Base85.mjs +++ b/tests/operations/tests/Base85.mjs @@ -7,8 +7,8 @@ */ import TestRegister from "../../lib/TestRegister.mjs"; -// Example from Wikipedia -const wpExample = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure." +// Example from Wikipedia +const wpExample = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; // Escape newline, quote & backslash const wpOutput = "9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKFCj@.4Gp$d7F!,L7@<6@)/0JDEF@3BB/F*&OCAfu2/AKYi(\ @@ -45,4 +45,4 @@ TestRegister.addTests([ "args": ["!-u", false] } ] }, -]); \ No newline at end of file +]); From 1735d9c091dee9412e3880264ef27ec1993e377f Mon Sep 17 00:00:00 2001 From: John L Date: Wed, 15 Jun 2022 15:07:39 +0100 Subject: [PATCH 41/72] remove logging --- tests/lib/TestRegister.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/lib/TestRegister.mjs b/tests/lib/TestRegister.mjs index 69e86088..634e3b62 100644 --- a/tests/lib/TestRegister.mjs +++ b/tests/lib/TestRegister.mjs @@ -87,7 +87,6 @@ class TestRegister { if (result.error.displayStr === test.expectedOutput) { ret.status = "passing"; } else { - console.log(result); ret.status = "failing"; ret.output = [ "Expected", From fc91469807afab441a49418a758cafea59cbd984 Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 17 Jun 2022 09:17:28 +0100 Subject: [PATCH 42/72] Added nesting to Merge/Fork/Subsection --- src/core/operations/Fork.mjs | 13 +++- src/core/operations/Merge.mjs | 10 ++- src/core/operations/Subsection.mjs | 11 ++- tests/operations/index.mjs | 1 + tests/operations/tests/Fork.mjs | 17 ++++- tests/operations/tests/Subsection.mjs | 102 ++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 tests/operations/tests/Subsection.mjs diff --git a/src/core/operations/Fork.mjs b/src/core/operations/Fork.mjs index 6e961990..3d4c596a 100644 --- a/src/core/operations/Fork.mjs +++ b/src/core/operations/Fork.mjs @@ -65,12 +65,21 @@ class Fork extends Operation { if (input) inputs = input.split(splitDelim); + // Set to 1 as if we are here, then there is one, the current one. + let numOp = 1; // Create subOpList for each tranche to operate on - // (all remaining operations unless we encounter a Merge) + // all remaining operations unless we encounter a Merge for (i = state.progress + 1; i < opList.length; i++) { if (opList[i].name === "Merge" && !opList[i].disabled) { - break; + numOp--; + if (numOp === 0 || opList[i].ingValues[0]) + break; + else + // Not this Fork's Merge. + subOpList.push(opList[i]); } else { + if (opList[i].name === "Fork" || opList[i].name === "Subsection") + numOp++; subOpList.push(opList[i]); } } diff --git a/src/core/operations/Merge.mjs b/src/core/operations/Merge.mjs index 07123aee..573e62e0 100644 --- a/src/core/operations/Merge.mjs +++ b/src/core/operations/Merge.mjs @@ -20,10 +20,16 @@ class Merge extends Operation { this.name = "Merge"; this.flowControl = true; this.module = "Default"; - this.description = "Consolidate all branches back into a single trunk. The opposite of Fork."; + this.description = "Consolidate all branches back into a single trunk. The opposite of Fork. Unticking the Merge All checkbox will only consolidate all branches up to the nearest Fork/Subsection."; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + name: "Merge All", + type: "boolean", + value: true, + } + ]; } /** diff --git a/src/core/operations/Subsection.mjs b/src/core/operations/Subsection.mjs index 86980e40..1093917b 100644 --- a/src/core/operations/Subsection.mjs +++ b/src/core/operations/Subsection.mjs @@ -67,12 +67,21 @@ class Subsection extends Operation { subOpList = []; if (input && section !== "") { + // Set to 1 as if we are here, then there is one, the current one. + let numOp = 1; // Create subOpList for each tranche to operate on // all remaining operations unless we encounter a Merge for (let i = state.progress + 1; i < opList.length; i++) { if (opList[i].name === "Merge" && !opList[i].disabled) { - break; + numOp--; + if (numOp === 0 || opList[i].ingValues[0]) + break; + else + // Not this subsection's Merge. + subOpList.push(opList[i]); } else { + if (opList[i].name === "Fork" || opList[i].name === "Subsection") + numOp++; subOpList.push(opList[i]); } } diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index b6beb081..1e9dbbb1 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -114,6 +114,7 @@ import "./tests/HASSH.mjs"; import "./tests/GetAllCasings.mjs"; import "./tests/SIGABA.mjs"; import "./tests/ELFInfo.mjs"; +import "./tests/Subsection.mjs"; // Cannot test operations that use the File type yet diff --git a/tests/operations/tests/Fork.mjs b/tests/operations/tests/Fork.mjs index d7ee918c..05fde17e 100644 --- a/tests/operations/tests/Fork.mjs +++ b/tests/operations/tests/Fork.mjs @@ -31,7 +31,7 @@ TestRegister.addTests([ }, { op: "Merge", - args: [], + args: [true], }, ], }, @@ -50,7 +50,7 @@ TestRegister.addTests([ }, { op: "Merge", - args: [], + args: [true], }, ], }, @@ -66,5 +66,16 @@ TestRegister.addTests([ {"op": "Label", "args": ["skipReturn"]}, {"op": "To Base64", "args": ["A-Za-z0-9+/="]} ] - } + }, + { + name: "Fork, Partial Merge", + input: "Hello World", + expectedOutput: "48656c6c6f 576f726c64", + recipeConfig: [ + { "op": "Fork", "args": [" ", " ", false] }, + { "op": "Fork", "args": ["l", "l", false] }, + { "op": "Merge", "args": [false] }, + { "op": "To Hex", "args": ["None", 0] }, + ] + }, ]); diff --git a/tests/operations/tests/Subsection.mjs b/tests/operations/tests/Subsection.mjs new file mode 100644 index 00000000..6a181985 --- /dev/null +++ b/tests/operations/tests/Subsection.mjs @@ -0,0 +1,102 @@ +/** + * Subsection Tests. + * + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2022 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Subsection: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + "op": "Subsection", + "args": ["", true, true, false], + }, + ], + }, + { + name: "Subsection, Full Merge: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + "op": "Subsection", + "args": ["", true, true, false], + }, + { + "op": "Merge", + "args": [true], + }, + ], + }, + { + name: "Subsection, Partial Merge: nothing", + input: "", + expectedOutput: "", + recipeConfig: [ + { + "op": "Subsection", + "args": ["", true, true, false], + }, + { + "op": "Merge", + "args": [false], + }, + ], + }, + { + name: "Subsection, Full Merge: Base64 with Hex", + input: "SGVsbG38675629ybGQ=", + expectedOutput: "Hello World", + recipeConfig: [ + { + "op": "Subsection", + "args": ["386756", true, true, false], + }, + { + "op": "From Hex", + "args": ["Auto"], + }, + { + "op": "Merge", + "args": [true], + }, + { + "op": "From Base64", + "args": ["A-Za-z0-9+/=", true, false], + }, + ], + }, + { + name: "Subsection, Partial Merge: Base64 with Hex surrounded by binary data.", + input: "000000000SGVsbG38675629ybGQ=0000000000", + expectedOutput: "000000000Hello World0000000000", + recipeConfig: [ + { + "op": "Subsection", + "args": ["SGVsbG38675629ybGQ=", true, true, false], + }, + { + "op": "Subsection", + "args": ["386756", true, true, false], + }, + { + "op": "From Hex", + "args": ["Auto"], + }, + { + "op": "Merge", + "args": [false], + }, + { + "op": "From Base64", + "args": ["A-Za-z0-9+/=", true, false], + }, + ], + }, +]); From 8917eabfd16086f949069a449f7a7ab6f5969ffc Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 17 Jun 2022 09:56:36 +0100 Subject: [PATCH 43/72] Implemented webp extractor --- src/core/lib/FileSignatures.mjs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/core/lib/FileSignatures.mjs b/src/core/lib/FileSignatures.mjs index 7b77f2d9..4cba4bc7 100644 --- a/src/core/lib/FileSignatures.mjs +++ b/src/core/lib/FileSignatures.mjs @@ -70,7 +70,7 @@ export const FILE_SIGNATURES = { 10: 0x42, 11: 0x50 }, - extractor: null + extractor: extractWEBP }, { name: "Camera Image File Format", @@ -3032,6 +3032,30 @@ export function extractPNG(bytes, offset) { } +/** + * WEBP extractor. + * + * @param {Uint8Array} bytes + * @param {number} offset + * @returns {Uint8Array} + */ +export function extractWEBP(bytes, offset) { + const stream = new Stream(bytes.slice(offset)); + + // Move to file size offset. + stream.moveForwardsBy(4); + + // Read file size field. + const fileSize = stream.readInt(4, "le"); + + // Move to end of file. + // There is no need to minus 8 from the size as the size factors in the offset. + stream.moveForwardsBy(fileSize); + + return stream.carve(); +} + + /** * BMP extractor. * From 42c911838d9f29c7156aad5d52af4d58058859bf Mon Sep 17 00:00:00 2001 From: n1073645 Date: Fri, 17 Jun 2022 11:18:49 +0100 Subject: [PATCH 44/72] Add min size to Extract Files --- src/core/operations/ExtractFiles.mjs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/core/operations/ExtractFiles.mjs b/src/core/operations/ExtractFiles.mjs index fce23a9a..8c313f59 100644 --- a/src/core/operations/ExtractFiles.mjs +++ b/src/core/operations/ExtractFiles.mjs @@ -38,7 +38,7 @@ class ExtractFiles extends Operation {
  • ${supportedExts.join("
  • ")}
  • - `; + Minimum File Size can be used to prune small false positives.`; this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving"; this.inputType = "ArrayBuffer"; this.outputType = "List"; @@ -54,6 +54,11 @@ class ExtractFiles extends Operation { name: "Ignore failed extractions", type: "boolean", value: true + }, + { + name: "Minimum File Size", + type: "number", + value: 0 } ]); } @@ -66,6 +71,7 @@ class ExtractFiles extends Operation { run(input, args) { const bytes = new Uint8Array(input), categories = [], + minSize = args.pop(1), ignoreFailedExtractions = args.pop(1); args.forEach((cat, i) => { @@ -80,7 +86,9 @@ class ExtractFiles extends Operation { const errors = []; detectedFiles.forEach(detectedFile => { try { - files.push(extractFile(bytes, detectedFile.fileDetails, detectedFile.offset)); + let file; + if ((file = extractFile(bytes, detectedFile.fileDetails, detectedFile.offset)).size >= minSize) + files.push(file); } catch (err) { if (!ignoreFailedExtractions && err.message.indexOf("No extraction algorithm available") < 0) { errors.push( From c4414bd910e84c3185af19a234ab90f744dfee94 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 13:53:19 +0100 Subject: [PATCH 45/72] Fixed dropdown toggle height --- src/web/stylesheets/components/_operation.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/stylesheets/components/_operation.css b/src/web/stylesheets/components/_operation.css index 39f53a07..7d45a9e2 100755 --- a/src/web/stylesheets/components/_operation.css +++ b/src/web/stylesheets/components/_operation.css @@ -186,7 +186,7 @@ div.toggle-string { } .ingredients .dropdown-toggle-split { - height: 41px !important; + height: 40px !important; } .boolean-arg { From fc95d82c49794375cb7f533f883576fb42126e8e Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 14:49:40 +0100 Subject: [PATCH 46/72] Tweaked Extract Files minimum size --- src/core/operations/ExtractFiles.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/operations/ExtractFiles.mjs b/src/core/operations/ExtractFiles.mjs index 8c313f59..4c6fd1df 100644 --- a/src/core/operations/ExtractFiles.mjs +++ b/src/core/operations/ExtractFiles.mjs @@ -58,7 +58,7 @@ class ExtractFiles extends Operation { { name: "Minimum File Size", type: "number", - value: 0 + value: 100 } ]); } @@ -86,8 +86,8 @@ class ExtractFiles extends Operation { const errors = []; detectedFiles.forEach(detectedFile => { try { - let file; - if ((file = extractFile(bytes, detectedFile.fileDetails, detectedFile.offset)).size >= minSize) + const file = extractFile(bytes, detectedFile.fileDetails, detectedFile.offset); + if (file.size >= minSize) files.push(file); } catch (err) { if (!ignoreFailedExtractions && err.message.indexOf("No extraction algorithm available") < 0) { From 50f0f708052ff684e3c1134fdee887e00b5e71b0 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 14:49:50 +0100 Subject: [PATCH 47/72] 9.39.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ffde1368..62b4627e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.1", + "version": "9.39.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.1", + "version": "9.39.2", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index cea3fb19..8f392c43 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.1", + "version": "9.39.2", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From a9657ac5c7af0101e011086afae4e2fbc28baa46 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 14:51:08 +0100 Subject: [PATCH 48/72] 9.39.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 62b4627e..a56add40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.2", + "version": "9.39.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.2", + "version": "9.39.3", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 8f392c43..38144a24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.2", + "version": "9.39.3", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 65aeae9c1e9414665dc898fe4036972f10c3376c Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 14:53:07 +0100 Subject: [PATCH 49/72] 9.39.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a56add40..db1ff36e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.3", + "version": "9.39.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.3", + "version": "9.39.4", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 38144a24..29d617bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.3", + "version": "9.39.4", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 4b018bf421422600bf114a9053558a4dd13dfb85 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 14:55:32 +0100 Subject: [PATCH 50/72] 9.39.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index db1ff36e..88d50c51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.4", + "version": "9.39.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.4", + "version": "9.39.5", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 29d617bc..2416f720 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.4", + "version": "9.39.5", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 2f097e5dfcc03b577478b622c3ae17bffcc64e61 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:15:53 +0100 Subject: [PATCH 51/72] Tidied up Base85 issues --- src/core/operations/FromBase85.mjs | 11 ++++------- tests/lib/TestRegister.mjs | 7 +++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/operations/FromBase85.mjs b/src/core/operations/FromBase85.mjs index 01024f1a..f9b37c74 100644 --- a/src/core/operations/FromBase85.mjs +++ b/src/core/operations/FromBase85.mjs @@ -85,6 +85,10 @@ class FromBase85 extends Operation { throw new OperationError("Alphabet must be of length 85"); } + // Remove delimiters if present + const matches = input.match(/^<~(.+?)~>$/); + if (matches !== null) input = matches[1]; + // Remove non-alphabet characters if (removeNonAlphChars) { const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g"); @@ -93,13 +97,6 @@ class FromBase85 extends Operation { if (input.length === 0) return []; - input = input.replace(/\s+/g, ""); - - if (encoding === "Standard") { - const matches = input.match(/<~(.+?)~>/); - if (matches !== null) input = matches[1]; - } - let i = 0; let block, blockBytes; while (i < input.length) { diff --git a/tests/lib/TestRegister.mjs b/tests/lib/TestRegister.mjs index 634e3b62..8b687fcc 100644 --- a/tests/lib/TestRegister.mjs +++ b/tests/lib/TestRegister.mjs @@ -12,6 +12,7 @@ import Chef from "../../src/core/Chef.mjs"; import Utils from "../../src/core/Utils.mjs"; import cliProgress from "cli-progress"; +import log from "loglevel"; /** * Object to store and run the list of tests. @@ -50,6 +51,9 @@ class TestRegister { * Runs all the tests in the register. */ async runTests () { + // Turn off logging to avoid messy errors + log.setLevel("silent", false); + const progBar = new cliProgress.SingleBar({ format: formatter, stopOnComplete: true @@ -128,6 +132,9 @@ class TestRegister { progBar.increment(); } + // Turn logging back on + log.setLevel("info", false); + return testResults; } From 1fb1d9cbb75c49f171112f061a2ab4dc4cd140bd Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:16:00 +0100 Subject: [PATCH 52/72] 9.39.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88d50c51..0efed1ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.5", + "version": "9.39.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.5", + "version": "9.39.6", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 2416f720..d370000d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.5", + "version": "9.39.6", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 7d4e5545715ed6b279e3d6860ae537fd70c986c4 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:26:33 +0100 Subject: [PATCH 53/72] Tweaks to P-List Viewer operation --- src/core/config/Categories.json | 2 +- src/core/operations/PLISTViewer.mjs | 33 +++++++++-------------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 240ddbc3..a2c85ea3 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -457,7 +457,7 @@ "Frequency distribution", "Index of Coincidence", "Chi Square", - "PLIST Viewer", + "P-list Viewer", "Disassemble x86", "Pseudo-Random Number Generator", "Generate UUID", diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs index b8a90c5b..67a42359 100644 --- a/src/core/operations/PLISTViewer.mjs +++ b/src/core/operations/PLISTViewer.mjs @@ -7,36 +7,23 @@ import Operation from "../Operation.mjs"; /** - * PLIST Viewer operation + * P-list Viewer operation */ -class PLISTViewer extends Operation { +class PlistViewer extends Operation { /** - * PLISTViewer constructor + * PlistViewer constructor */ constructor() { super(); - this.name = "PLIST Viewer"; - this.module = "Other"; - this.description = "Converts PLISTXML file into a human readable format."; - this.infoURL = ""; + this.name = "P-list Viewer"; + this.module = "Default"; + this.description = "In the macOS, iOS, NeXTSTEP, and GNUstep programming frameworks, property list files are files that store serialized objects. Property list files use the filename extension .plist, and thus are often referred to as p-list files.

    This operation displays plist files in a human readable format."; + this.infoURL = "https://wikipedia.org/wiki/Property_list"; this.inputType = "string"; this.outputType = "string"; - this.args = [ - /* Example arguments. See the project wiki for full details. - { - name: "First arg", - type: "string", - value: "Don't Panic" - }, - { - name: "Second arg", - type: "number", - value: 42 - } - */ - ]; + this.args = []; } /** @@ -46,7 +33,7 @@ class PLISTViewer extends Operation { */ run(input, args) { - // Regexes are designed to transform the xml format into a reasonably more readable string format. + // Regexes are designed to transform the xml format into a more readable string format. input = input.slice(input.indexOf("/g, "plist => ") .replace(//g, "{") @@ -143,4 +130,4 @@ class PLISTViewer extends Operation { } } -export default PLISTViewer; +export default PlistViewer; From c9d29c89bb29e379254745af03ff7268797391df Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:27:01 +0100 Subject: [PATCH 54/72] 9.40.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0efed1ea..34863028 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.39.6", + "version": "9.40.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.39.6", + "version": "9.40.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index d370000d..375c2c2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.39.6", + "version": "9.40.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 94700dab897c898f55b474be0b1832180ee47dec Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:28:39 +0100 Subject: [PATCH 55/72] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af8843e5..22506911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.40.0] - 2022-07-08 +- Added 'P-list Viewer' operation [@n1073645] | [#906] + ### [9.39.0] - 2022-06-09 - Added 'ELF Info' operation [@n1073645] | [#1364] @@ -294,6 +297,7 @@ All major and minor version changes will be documented in this file. Details of +[9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0 [9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0 [9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0 [9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0 @@ -491,6 +495,7 @@ All major and minor version changes will be documented in this file. Details of [#674]: https://github.com/gchq/CyberChef/pull/674 [#683]: https://github.com/gchq/CyberChef/pull/683 [#865]: https://github.com/gchq/CyberChef/pull/865 +[#906]: https://github.com/gchq/CyberChef/pull/906 [#912]: https://github.com/gchq/CyberChef/pull/912 [#917]: https://github.com/gchq/CyberChef/pull/917 [#934]: https://github.com/gchq/CyberChef/pull/934 From 6cccc2c786ef8dd24547930e3f567157e176b06d Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:36:30 +0100 Subject: [PATCH 56/72] Tidied Caesar Box Cipher --- src/core/operations/CaesarBoxCipher.mjs | 2 +- tests/operations/tests/CaesarBoxCipher.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/operations/CaesarBoxCipher.mjs b/src/core/operations/CaesarBoxCipher.mjs index 9c835b4b..680db900 100644 --- a/src/core/operations/CaesarBoxCipher.mjs +++ b/src/core/operations/CaesarBoxCipher.mjs @@ -19,7 +19,7 @@ class CaesarBoxCipher extends Operation { this.name = "Caesar Box Cipher"; this.module = "Ciphers"; - this.description = "Caesar Box Encryption uses a box, a rectangle (or a square), or at least a size W caracterizing its width."; + this.description = "Caesar Box is a transposition cipher used in the Roman Empire, in which letters of the message are written in rows in a square (or a rectangle) and then, read by column."; this.infoURL = "https://www.dcode.fr/caesar-box-cipher"; this.inputType = "string"; this.outputType = "string"; diff --git a/tests/operations/tests/CaesarBoxCipher.mjs b/tests/operations/tests/CaesarBoxCipher.mjs index 3ccdae66..a7b36ef0 100644 --- a/tests/operations/tests/CaesarBoxCipher.mjs +++ b/tests/operations/tests/CaesarBoxCipher.mjs @@ -1,5 +1,5 @@ /** - * Base58 tests. + * Caesar Box Cipher tests. * * @author n1073645 [n1073645@gmail.com] * From 74bb8d92dc379d256a3974ae2b346c6555c7e94e Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:36:36 +0100 Subject: [PATCH 57/72] 9.41.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34863028..42139c37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.40.0", + "version": "9.41.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.40.0", + "version": "9.41.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 375c2c2e..06043fd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.40.0", + "version": "9.41.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 98a95c8bbfc0233835dde1716be0db4b0dec5b23 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:38:12 +0100 Subject: [PATCH 58/72] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22506911..82730071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.41.0] - 2022-07-08 +- Added 'Caesar Box Cipher' operation [@n1073645] | [#1066] + ### [9.40.0] - 2022-07-08 - Added 'P-list Viewer' operation [@n1073645] | [#906] @@ -297,6 +300,7 @@ All major and minor version changes will be documented in this file. Details of +[9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0 [9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0 [9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0 [9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0 @@ -511,6 +515,7 @@ All major and minor version changes will be documented in this file. Details of [#1045]: https://github.com/gchq/CyberChef/pull/1045 [#1049]: https://github.com/gchq/CyberChef/pull/1049 [#1065]: https://github.com/gchq/CyberChef/pull/1065 +[#1066]: https://github.com/gchq/CyberChef/pull/1066 [#1083]: https://github.com/gchq/CyberChef/pull/1083 [#1189]: https://github.com/gchq/CyberChef/pull/1189 [#1242]: https://github.com/gchq/CyberChef/pull/1242 From a6aa40db976e5c9532b62e2845d4e6d3d79cdc3b Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:47:35 +0100 Subject: [PATCH 59/72] Tidied LS47 operations --- src/core/lib/LS47.mjs | 6 +++--- src/core/operations/LS47Decrypt.mjs | 5 ++--- src/core/operations/LS47Encrypt.mjs | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/core/lib/LS47.mjs b/src/core/lib/LS47.mjs index 6696aafc..ac7ca839 100644 --- a/src/core/lib/LS47.mjs +++ b/src/core/lib/LS47.mjs @@ -102,10 +102,10 @@ function checkKey(key) { counts[letters.charAt(i)] = 0; for (const elem of letters) { if (letters.indexOf(elem) === -1) - throw new OperationError("Letter " + elem + " not in LS47!"); + throw new OperationError("Letter " + elem + " not in LS47"); counts[elem]++; if (counts[elem] > 1) - throw new OperationError("Letter duplicated in the key!"); + throw new OperationError("Letter duplicated in the key"); } } @@ -120,7 +120,7 @@ function findPos (key, letter) { const index = key.indexOf(letter); if (index >= 0 && index < 49) return [Math.floor(index/7), index%7]; - throw new OperationError("Letter " + letter + " is not in the key!"); + throw new OperationError("Letter " + letter + " is not in the key"); } /** diff --git a/src/core/operations/LS47Decrypt.mjs b/src/core/operations/LS47Decrypt.mjs index cb92cd27..d5764d7f 100644 --- a/src/core/operations/LS47Decrypt.mjs +++ b/src/core/operations/LS47Decrypt.mjs @@ -20,8 +20,8 @@ class LS47Decrypt extends Operation { this.name = "LS47 Decrypt"; this.module = "Crypto"; - this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.\nThe LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\nA LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; - this.infoURL = "https://gitea.blesmrt.net/exa/ls47/src/branch/master"; + this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.
    The LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()
    An LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; + this.infoURL = "https://github.com/exaexa/ls47"; this.inputType = "string"; this.outputType = "string"; this.args = [ @@ -44,7 +44,6 @@ class LS47Decrypt extends Operation { * @returns {string} */ run(input, args) { - this.paddingSize = parseInt(args[1], 10); LS47.initTiles(); diff --git a/src/core/operations/LS47Encrypt.mjs b/src/core/operations/LS47Encrypt.mjs index 51283844..02f7d994 100644 --- a/src/core/operations/LS47Encrypt.mjs +++ b/src/core/operations/LS47Encrypt.mjs @@ -20,8 +20,8 @@ class LS47Encrypt extends Operation { this.name = "LS47 Encrypt"; this.module = "Crypto"; - this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.\nThe LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()\nA LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; - this.infoURL = "https://gitea.blesmrt.net/exa/ls47/src/branch/master"; + this.description = "This is a slight improvement of the ElsieFour cipher as described by Alan Kaminsky. We use 7x7 characters instead of original (barely fitting) 6x6, to be able to encrypt some structured information. We also describe a simple key-expansion algorithm, because remembering passwords is popular. Similar security considerations as with ElsieFour hold.
    The LS47 alphabet consists of following characters: _abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()
    A LS47 key is a permutation of the alphabet that is then represented in a 7x7 grid used for the encryption or decryption."; + this.infoURL = "https://github.com/exaexa/ls47"; this.inputType = "string"; this.outputType = "string"; this.args = [ @@ -49,7 +49,6 @@ class LS47Encrypt extends Operation { * @returns {string} */ run(input, args) { - this.paddingSize = parseInt(args[1], 10); LS47.initTiles(); From b828b50ccc2e0e4096cef212d4932d0ba3c65ec3 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:47:42 +0100 Subject: [PATCH 60/72] 9.42.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42139c37..24730227 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.41.0", + "version": "9.42.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.41.0", + "version": "9.42.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 06043fd6..a24c996f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.41.0", + "version": "9.42.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 2ffce23c67bda3a4ccf1f1665234c78b1addfe20 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 15:52:00 +0100 Subject: [PATCH 61/72] Updated CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82730071..0dcf5b17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.42.0] - 2022-07-08 +- Added 'LS47 Encrypt' and 'LS47 Decrypt' operations [@n1073645] | [#951] + ### [9.41.0] - 2022-07-08 - Added 'Caesar Box Cipher' operation [@n1073645] | [#1066] @@ -300,6 +303,7 @@ All major and minor version changes will be documented in this file. Details of +[9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0 [9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0 [9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0 [9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0 @@ -504,6 +508,7 @@ All major and minor version changes will be documented in this file. Details of [#917]: https://github.com/gchq/CyberChef/pull/917 [#934]: https://github.com/gchq/CyberChef/pull/934 [#948]: https://github.com/gchq/CyberChef/pull/948 +[#951]: https://github.com/gchq/CyberChef/pull/951 [#952]: https://github.com/gchq/CyberChef/pull/952 [#965]: https://github.com/gchq/CyberChef/pull/965 [#966]: https://github.com/gchq/CyberChef/pull/966 From eb5663a1eddd7f9400ced8cddcc40caf200a0eac Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:02:24 +0100 Subject: [PATCH 62/72] Tidied ROT brute forcing ops --- src/core/operations/ROT13BruteForce.mjs | 26 ++++++++++++------------- src/core/operations/ROT47BruteForce.mjs | 26 ++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/core/operations/ROT13BruteForce.mjs b/src/core/operations/ROT13BruteForce.mjs index bdf9d40a..aefe2ab7 100644 --- a/src/core/operations/ROT13BruteForce.mjs +++ b/src/core/operations/ROT13BruteForce.mjs @@ -40,28 +40,28 @@ class ROT13BruteForce extends Operation { value: false }, { - "name": "Sample length", - "type": "number", - "value": 100 + name: "Sample length", + type: "number", + value: 100 }, { - "name": "Sample offset", - "type": "number", - "value": 0 + name: "Sample offset", + type: "number", + value: 0 }, { - "name": "Print amount", - "type": "boolean", - "value": true + name: "Print amount", + type: "boolean", + value: true }, { - "name": "Crib (known plaintext string)", - "type": "string", - "value": "" + name: "Crib (known plaintext string)", + type: "string", + value: "" } ]; } - + /** * @param {byteArray} input * @param {Object[]} args diff --git a/src/core/operations/ROT47BruteForce.mjs b/src/core/operations/ROT47BruteForce.mjs index 5fce5259..5f346e00 100644 --- a/src/core/operations/ROT47BruteForce.mjs +++ b/src/core/operations/ROT47BruteForce.mjs @@ -25,28 +25,28 @@ class ROT47BruteForce extends Operation { this.outputType = "string"; this.args = [ { - "name": "Sample length", - "type": "number", - "value": 100 + name: "Sample length", + type: "number", + value: 100 }, { - "name": "Sample offset", - "type": "number", - "value": 0 + name: "Sample offset", + type: "number", + value: 0 }, { - "name": "Print amount", - "type": "boolean", - "value": true + name: "Print amount", + type: "boolean", + value: true }, { - "name": "Crib (known plaintext string)", - "type": "string", - "value": "" + name: "Crib (known plaintext string)", + type: "string", + value: "" } ]; } - + /** * @param {byteArray} input * @param {Object[]} args From dfd9afc2c42712bfc231b27ee57fadaf39006ea4 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:02:35 +0100 Subject: [PATCH 63/72] 9.43.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24730227..489598a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.42.0", + "version": "9.43.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.42.0", + "version": "9.43.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index a24c996f..5b816668 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.42.0", + "version": "9.43.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From f97ce18ff97648e4a20be36b48b6ad462ca07290 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:03:42 +0100 Subject: [PATCH 64/72] Updated CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dcf5b17..9cbe89ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.43.0] - 2022-07-08 +- Added 'ROT13 Brute Force' and 'ROT47 Brute Force' operations [@mikecat] | [#1264] + ### [9.42.0] - 2022-07-08 - Added 'LS47 Encrypt' and 'LS47 Decrypt' operations [@n1073645] | [#951] @@ -303,6 +306,7 @@ All major and minor version changes will be documented in this file. Details of +[9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0 [9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0 [9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0 [9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0 @@ -430,6 +434,7 @@ All major and minor version changes will be documented in this file. Details of [@t-8ch]: https://github.com/t-8ch [@hettysymes]: https://github.com/hettysymes [@swesven]: https://github.com/swesven +[@mikecat]: https://github.com/mikecat [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513 @@ -528,3 +533,5 @@ All major and minor version changes will be documented in this file. Details of [#1313]: https://github.com/gchq/CyberChef/pull/1313 [#1326]: https://github.com/gchq/CyberChef/pull/1326 [#1364]: https://github.com/gchq/CyberChef/pull/1364 +[#1264]: https://github.com/gchq/CyberChef/pull/1264 + From a7fc455e05cb461d574d2647a262bb4db39f863c Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:24:47 +0100 Subject: [PATCH 65/72] 9.44.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5fcbc00c..80c49ca8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.43.0", + "version": "9.44.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.43.0", + "version": "9.44.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index dd37cb00..05a8d6a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.43.0", + "version": "9.44.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From f1d318f2295b19be107dfe09c656b3fadc96c445 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:25:59 +0100 Subject: [PATCH 66/72] Updated CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cbe89ed..9f0e9159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.44.0] - 2022-07-08 +- Added 'LZString Compress' and 'LZString Decompress' operations [@crespyl] | [#1266] + ### [9.43.0] - 2022-07-08 - Added 'ROT13 Brute Force' and 'ROT47 Brute Force' operations [@mikecat] | [#1264] @@ -306,6 +309,7 @@ All major and minor version changes will be documented in this file. Details of +[9.44.0]: https://github.com/gchq/CyberChef/releases/tag/v9.44.0 [9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0 [9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0 [9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0 @@ -435,6 +439,7 @@ All major and minor version changes will be documented in this file. Details of [@hettysymes]: https://github.com/hettysymes [@swesven]: https://github.com/swesven [@mikecat]: https://github.com/mikecat +[@crespyl]: https://github.com/crespyl [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513 @@ -534,4 +539,5 @@ All major and minor version changes will be documented in this file. Details of [#1326]: https://github.com/gchq/CyberChef/pull/1326 [#1364]: https://github.com/gchq/CyberChef/pull/1364 [#1264]: https://github.com/gchq/CyberChef/pull/1264 +[#1266]: https://github.com/gchq/CyberChef/pull/1266 From 25086386c64cd8c880034653c331b9b8c280e47b Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:33:16 +0100 Subject: [PATCH 67/72] Tidied ROT8000 --- src/core/operations/ROT8000.mjs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core/operations/ROT8000.mjs b/src/core/operations/ROT8000.mjs index 1f039de0..322ceaa3 100644 --- a/src/core/operations/ROT8000.mjs +++ b/src/core/operations/ROT8000.mjs @@ -20,7 +20,7 @@ class ROT8000 extends Operation { this.name = "ROT8000"; this.module = "Default"; this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet."; - this.infoURL = "https://github.com/rottytooth/rot8000"; + this.infoURL = "https://rot8000.com/info"; this.inputType = "string"; this.outputType = "string"; this.args = []; @@ -35,7 +35,25 @@ class ROT8000 extends Operation { // Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js // these come from the valid-code-point-transitions.json file generated from the c# proj // this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000 - const validCodePoints = JSON.parse('{"33":true,"127":false,"161":true,"5760":false,"5761":true,"8192":false,"8203":true,"8232":false,"8234":true,"8239":false,"8240":true,"8287":false,"8288":true,"12288":false,"12289":true,"55296":false,"57344":true}'); + const validCodePoints = { + "33": true, + "127": false, + "161": true, + "5760": false, + "5761": true, + "8192": false, + "8203": true, + "8232": false, + "8234": true, + "8239": false, + "8240": true, + "8287": false, + "8288": true, + "12288": false, + "12289": true, + "55296": false, + "57344": true + }; const bmpSize = 0x10000; const rotList = {}; // the mapping of char to rotated char const hiddenBlocks = []; From 6a10e94bfd902b52e3af04e79d47524b7ddf29e1 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:33:33 +0100 Subject: [PATCH 68/72] 9.45.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 80c49ca8..6b3a5d60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.44.0", + "version": "9.45.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.44.0", + "version": "9.45.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 05a8d6a1..2bd3ca72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.44.0", + "version": "9.45.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 683bd3e5db089a83794e9884c0c3d89a309acbef Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 16:34:21 +0100 Subject: [PATCH 69/72] Updated CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f0e9159..28a07ec7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.45.0] - 2022-07-08 +- Added 'ROT8000' operation [@thomasleplus] | [#1250] + ### [9.44.0] - 2022-07-08 - Added 'LZString Compress' and 'LZString Decompress' operations [@crespyl] | [#1266] @@ -309,6 +312,7 @@ All major and minor version changes will be documented in this file. Details of +[9.45.0]: https://github.com/gchq/CyberChef/releases/tag/v9.45.0 [9.44.0]: https://github.com/gchq/CyberChef/releases/tag/v9.44.0 [9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0 [9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0 @@ -440,6 +444,7 @@ All major and minor version changes will be documented in this file. Details of [@swesven]: https://github.com/swesven [@mikecat]: https://github.com/mikecat [@crespyl]: https://github.com/crespyl +[@thomasleplus]: https://github.com/thomasleplus [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513 @@ -540,4 +545,5 @@ All major and minor version changes will be documented in this file. Details of [#1364]: https://github.com/gchq/CyberChef/pull/1364 [#1264]: https://github.com/gchq/CyberChef/pull/1264 [#1266]: https://github.com/gchq/CyberChef/pull/1266 +[#1250]: https://github.com/gchq/CyberChef/pull/1250 From 4200ed4eb9881a4065a9cae0765cfbf56b365f61 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 17:16:35 +0100 Subject: [PATCH 70/72] Tidied Cetacean ciphers --- package-lock.json | 11 ++++++++- src/core/config/Categories.json | 4 ++-- src/core/operations/CetaceanCipherDecode.mjs | 23 +++++++++--------- src/core/operations/CetaceanCipherEncode.mjs | 25 +++++++++----------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b3a5d60..cb17b30e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "lodash": "^4.17.21", "loglevel": "^1.8.0", "loglevel-message-prefix": "^3.0.0", + "lz-string": "^1.4.4", "markdown-it": "^13.0.1", "moment": "^2.29.3", "moment-timezone": "^0.5.34", @@ -10120,6 +10121,14 @@ "node": ">=10" } }, + "node_modules/lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -23564,7 +23573,7 @@ "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" + "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==" }, "make-dir": { "version": "3.1.0", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 19ab89d3..8ac60048 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -77,8 +77,6 @@ "Blowfish Decrypt", "DES Encrypt", "DES Decrypt", - "Cetacean Cipher Encode", - "Cetacean Cipher Decode", "Triple DES Encrypt", "Triple DES Decrypt", "LS47 Encrypt", @@ -114,6 +112,8 @@ "Atbash Cipher", "CipherSaber2 Encrypt", "CipherSaber2 Decrypt", + "Cetacean Cipher Encode", + "Cetacean Cipher Decode", "Substitute", "Derive PBKDF2 key", "Derive EVP key", diff --git a/src/core/operations/CetaceanCipherDecode.mjs b/src/core/operations/CetaceanCipherDecode.mjs index a79b98c5..a50fe6b7 100644 --- a/src/core/operations/CetaceanCipherDecode.mjs +++ b/src/core/operations/CetaceanCipherDecode.mjs @@ -20,7 +20,7 @@ class CetaceanCipherDecode extends Operation { this.name = "Cetacean Cipher Decode"; this.module = "Ciphers"; this.description = "Decode Cetacean Cipher input.

    e.g. EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe becomes hi"; - this.infoURL = ""; + this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins"; this.inputType = "string"; this.outputType = "string"; @@ -30,7 +30,7 @@ class CetaceanCipherDecode extends Operation { flags: "", args: [] } - ] + ]; } /** @@ -40,24 +40,23 @@ class CetaceanCipherDecode extends Operation { */ run(input, args) { const binaryArray = []; - for ( const char of input ) { - if ( char === ' ' ) { - binaryArray.push(...[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]); + for (const char of input) { + if (char === " ") { + binaryArray.push(...[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]); } else { - binaryArray.push( char === 'e' ? 1 : 0 ); + binaryArray.push(char === "e" ? 1 : 0); } } const byteArray = []; - for ( let i = 0; i < binaryArray.length; i += 16 ) { - byteArray.push(binaryArray.slice(i, i + 16).join('')) + for (let i = 0; i < binaryArray.length; i += 16) { + byteArray.push(binaryArray.slice(i, i + 16).join("")); } - return byteArray.map( byte => - String.fromCharCode(parseInt( byte , 2 ) - ) - ).join(''); + return byteArray.map(byte => + String.fromCharCode(parseInt(byte, 2)) + ).join(""); } } diff --git a/src/core/operations/CetaceanCipherEncode.mjs b/src/core/operations/CetaceanCipherEncode.mjs index e32e4f81..ec5f76d6 100644 --- a/src/core/operations/CetaceanCipherEncode.mjs +++ b/src/core/operations/CetaceanCipherEncode.mjs @@ -5,6 +5,7 @@ */ import Operation from "../Operation.mjs"; +import {toBinary} from "../lib/Binary.mjs"; /** * Cetacean Cipher Encode operation @@ -19,8 +20,8 @@ class CetaceanCipherEncode extends Operation { this.name = "Cetacean Cipher Encode"; this.module = "Ciphers"; - this.description = "Converts any input into Cetacean Cipher.

    e.g. hi becomes EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe\""; - this.infoURL = ""; + this.description = "Converts any input into Cetacean Cipher.

    e.g. hi becomes EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe"; + this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins"; this.inputType = "string"; this.outputType = "string"; } @@ -31,23 +32,19 @@ class CetaceanCipherEncode extends Operation { * @returns {string} */ run(input, args) { - let result = []; - let charArray = input.split(''); + const result = []; + const charArray = input.split(""); - charArray.map( ( character ) => { - if ( character === ' ' ) { - result.push( character ); + charArray.map(character => { + if (character === " ") { + result.push(character); } else { - const binaryArray = this.encodeToBinary( character ).split(''); - result.push( binaryArray.map(( str ) => str === '1' ? 'e' : 'E' ).join('')); + const binaryArray = toBinary(character.charCodeAt(0), "None", 16).split(""); + result.push(binaryArray.map(str => str === "1" ? "e" : "E").join("")); } }); - return result.join(''); - } - - encodeToBinary( char, padding = 16 ) { - return char.charCodeAt(0).toString(2).padStart( padding, '0'); + return result.join(""); } } From 85496684d8f184e134a9a38f7c6fbf235ba611fa Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 17:17:23 +0100 Subject: [PATCH 71/72] 9.46.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb17b30e..e1712692 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cyberchef", - "version": "9.45.0", + "version": "9.46.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cyberchef", - "version": "9.45.0", + "version": "9.46.0", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 2bd3ca72..48d6f693 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cyberchef", - "version": "9.45.0", + "version": "9.46.0", "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.", "author": "n1474335 ", "homepage": "https://gchq.github.io/CyberChef", From 037590f83128fb856f2e590f133201a39d2c7d2a Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 8 Jul 2022 17:18:20 +0100 Subject: [PATCH 72/72] Updated CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28a07ec7..f5d0712d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of ## Details +### [9.46.0] - 2022-07-08 +- Added 'Cetacean Cipher Encode' and 'Cetacean Cipher Decode' operations [@valdelaseras] | [#1308] + ### [9.45.0] - 2022-07-08 - Added 'ROT8000' operation [@thomasleplus] | [#1250] @@ -312,6 +315,7 @@ All major and minor version changes will be documented in this file. Details of +[9.46.0]: https://github.com/gchq/CyberChef/releases/tag/v9.46.0 [9.45.0]: https://github.com/gchq/CyberChef/releases/tag/v9.45.0 [9.44.0]: https://github.com/gchq/CyberChef/releases/tag/v9.44.0 [9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0 @@ -445,6 +449,7 @@ All major and minor version changes will be documented in this file. Details of [@mikecat]: https://github.com/mikecat [@crespyl]: https://github.com/crespyl [@thomasleplus]: https://github.com/thomasleplus +[@valdelaseras]: https://github.com/valdelaseras [8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7 [9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513 @@ -546,4 +551,5 @@ All major and minor version changes will be documented in this file. Details of [#1264]: https://github.com/gchq/CyberChef/pull/1264 [#1266]: https://github.com/gchq/CyberChef/pull/1266 [#1250]: https://github.com/gchq/CyberChef/pull/1250 +[#1308]: https://github.com/gchq/CyberChef/pull/1308