Compare commits

...
41 Commits
Author SHA1 Message Date
n1474335 1f57f1f000 9.50.11 2022-11-25 12:28:33 +00:00
n1474335 468071ee98 Tidied JSDoc comment 2022-11-25 12:28:26 +00:00
n1474335 23403f55a5 Merge branch 'master' of https://github.com/DidierStevens/CyberChef 2022-11-25 12:26:53 +00:00
n1474335 c25cf44d92 9.50.10 2022-11-25 12:25:15 +00:00
n1474335 e5644b5712 Merge branch 'master' of https://github.com/samgbell/CyberChef 2022-11-25 12:23:14 +00:00
n1474335 9321b79d81 9.50.9 2022-11-25 12:21:51 +00:00
n1474335 e97d535ff8 Merge branch 'fix-option-in-parse-asn1-hex-string' of https://github.com/mikecat/CyberChef 2022-11-25 12:21:42 +00:00
n1474335 7589361e58 9.50.8 2022-11-25 12:19:31 +00:00
n1474335 f15ef81693 Merge branch 'put-required-margin' of https://github.com/mikecat/CyberChef 2022-11-25 12:19:22 +00:00
n1474335 d5f4968664 9.50.7 2022-11-25 12:18:33 +00:00
n1474335 74e9edbccf Merge branch 'user-friendly-parse-x509-certificate' of https://github.com/mikecat/CyberChef 2022-11-25 12:15:29 +00:00
n1474335 51229d85cb 9.50.6 2022-11-25 12:11:17 +00:00
n1474335 b979b051cb Merge branch 'triple-des-with-16byte-key' of https://github.com/mikecat/CyberChef 2022-11-25 12:08:58 +00:00
n1474335 17cf154bc2 9.50.5 2022-11-25 12:07:07 +00:00
n1474335 c7f6954b97 Merge branch 'view-bit-plane-use-bytelength-not-length' of https://github.com/mikecat/CyberChef 2022-11-25 12:07:01 +00:00
n1474335 9ccc1613cf 9.50.4 2022-11-25 12:05:32 +00:00
n1474335 9730ce1f6a Merge branch 'fix-windows-filetime' of https://github.com/mikecat/CyberChef 2022-11-25 12:05:22 +00:00
n1474335 55a7981547 9.50.3 2022-11-25 12:03:57 +00:00
n1474335 2d99c365dd Merge branch 'fix-reverse-character' of https://github.com/mikecat/CyberChef 2022-11-25 12:02:46 +00:00
n1474335 59d8be511a 9.50.2 2022-11-25 12:00:32 +00:00
n1474335 8349ffc001 Merge branch 'from-hex-use-delimiter-as-delimiter' of https://github.com/mikecat/CyberChef 2022-11-25 11:59:25 +00:00
n1474335 c1368c4ecb 9.50.1 2022-11-25 11:55:53 +00:00
n1474335 c6935e040d Updated newMinorVersion script 2022-11-25 11:55:48 +00:00
n1474335 f79c3ae91a Merge branch 'use-lowercase-for-asn1' of https://github.com/mikecat/CyberChef 2022-11-25 11:55:19 +00:00
n1474335 bc27cd2772 9.50.0 2022-11-25 11:51:34 +00:00
n1474335 2b02c44ca4 Updated CHANGELOG 2022-11-25 11:51:22 +00:00
n1474335 59fe8d1c4b Simplified 'Shuffle' operation to work in the same way as 'Sort' and 'Unique' 2022-11-25 11:50:27 +00:00
n1474335 9a5d62c4c3 Merge branch 'shuffle-operation' of https://github.com/mikecat/CyberChef 2022-11-25 11:24:47 +00:00
MikeCAT 39143fa6a1 add Shuffle operation 2022-11-11 22:26:41 +09:00
MikeCAT 1e83e0e935 convert hex string to lower before parsing as ASN.1 2022-11-03 21:43:24 +09:00
MikeCAT 2255c5b360 allow 16-byte keys for Triple DES 2022-11-03 01:12:01 +09:00
MikeCAT c046cf5695 have "From Hex" treat the delimiter as delimiter, not what to erase 2022-11-03 00:21:20 +09:00
MikeCAT 3086c25079 improve treatment of Hex(little endian) for Windows Filetime converter 2022-11-02 23:14:48 +09:00
MikeCAT 3700780d14 improve "Reverse" operation
* Make "Character" option actually reverse characters
* Add new option "Byte" that behaves as previous "Character" option
2022-11-02 22:37:09 +09:00
MikeCAT 58b1fb8de5 ViewBitPlane.mjs: use byteLength instead of length to check validity of ArrayBuffer 2022-11-02 08:29:26 +09:00
Didier Stevens cb023089bb Operation Sort: added value Length to option Order 2022-10-30 15:33:11 +01:00
MikeCAT 5a507aa1ba have "Parse X.509 certificate" emit user-friendly message on certificate load error 2022-10-30 08:25:31 +09:00
MikeCAT d5ffbbb14c ParseASN1HexString.mjs: fix the name of option to use 2022-10-28 21:33:56 +09:00
MikeCAT fa30f597ad GenerateQRCode.mjs: set default margin to 4 modules 2022-10-27 20:02:49 +09:00
samgbell 8e57354307 Fixing some eslint and JSDoc issues 2022-10-13 12:03:22 +02:00
samgbell 126debf44e Adding Markdown format for To Table operation 2022-10-13 11:52:19 +02:00
22 changed files with 291 additions and 44 deletions

No files matched your search

+5
View File
@@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.50.0] - 2022-11-25
- Added 'Shuffle' operation [@mikecat] | [#1472]
### [9.49.0] - 2022-11-11
- Added 'LZ4 Compress' and 'LZ4 Decompress' operations [@n1474335] | [31a7f83]
@@ -324,6 +327,7 @@ All major and minor version changes will be documented in this file. Details of
[9.50.0]: https://github.com/gchq/CyberChef/releases/tag/v9.50.0
[9.49.0]: https://github.com/gchq/CyberChef/releases/tag/v9.49.0
[9.48.0]: https://github.com/gchq/CyberChef/releases/tag/v9.48.0
[9.47.0]: https://github.com/gchq/CyberChef/releases/tag/v9.47.0
@@ -568,4 +572,5 @@ All major and minor version changes will be documented in this file. Details of
[#1308]: https://github.com/gchq/CyberChef/pull/1308
[#1421]: https://github.com/gchq/CyberChef/pull/1421
[#1427]: https://github.com/gchq/CyberChef/pull/1427
[#1472]: https://github.com/gchq/CyberChef/pull/1472
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "cyberchef",
"version": "9.49.2",
"version": "9.50.11",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cyberchef",
"version": "9.49.2",
"version": "9.50.11",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.49.2",
"version": "9.50.11",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
+1
View File
@@ -249,6 +249,7 @@
"To Table",
"Reverse",
"Sort",
"Shuffle",
"Unique",
"Split",
"Filter",
+1 -1
View File
@@ -136,7 +136,7 @@ const getFeature = function() {
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
console.log("Written CHANGELOG.md");
console.log("Written CHANGELOG.md\nCommit changes and then run `npm version minor`.");
}
});
};
+8 -4
View File
@@ -105,13 +105,17 @@ export function fromHex(data, delim="Auto", byteLen=2) {
throw new OperationError("Byte length must be a positive integer");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
data = data.replace(delimRegex, "");
const delimRegex = delim === "Auto" ? /[^a-f\d]|0x/gi : Utils.regexRep(delim);
data = data.split(delimRegex);
} else {
data = [data];
}
const output = [];
for (let i = 0; i < data.length; i += byteLen) {
output.push(parseInt(data.substr(i, byteLen), 16));
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < data[i].length; j += byteLen) {
output.push(parseInt(data[i].substr(j, byteLen), 16));
}
}
return output;
}
+12
View File
@@ -103,3 +103,15 @@ export function hexadecimalSort(a, b) {
return a.localeCompare(b);
}
/**
* Comparison operation for sorting by length
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function lengthSort(a, b) {
return a.length - b.length;
}
+1 -1
View File
@@ -44,7 +44,7 @@ class GenerateQRCode extends Operation {
{
"name": "Margin (num modules)",
"type": "number",
"value": 2,
"value": 4,
"min": 0
},
{
+2 -2
View File
@@ -45,8 +45,8 @@ class ParseASN1HexString extends Operation {
*/
run(input, args) {
const [index, truncateLen] = args;
return r.ASN1HEX.dump(input.replace(/\s/g, ""), {
"ommitLongOctet": truncateLen
return r.ASN1HEX.dump(input.replace(/\s/g, "").toLowerCase(), {
"ommit_long_octet": truncateLen
}, index);
}
+22 -16
View File
@@ -57,23 +57,29 @@ class ParseX509Certificate extends Operation {
const cert = new r.X509(),
inputFormat = args[0];
switch (inputFormat) {
case "DER Hex":
input = input.replace(/\s/g, "");
cert.readCertHex(input);
break;
case "PEM":
cert.readCertPEM(input);
break;
case "Base64":
cert.readCertHex(toHex(fromBase64(input, null, "byteArray"), ""));
break;
case "Raw":
cert.readCertHex(toHex(Utils.strToByteArray(input), ""));
break;
default:
throw "Undefined input format";
let undefinedInputFormat = false;
try {
switch (inputFormat) {
case "DER Hex":
input = input.replace(/\s/g, "").toLowerCase();
cert.readCertHex(input);
break;
case "PEM":
cert.readCertPEM(input);
break;
case "Base64":
cert.readCertHex(toHex(fromBase64(input, null, "byteArray"), ""));
break;
case "Raw":
cert.readCertHex(toHex(Utils.strToByteArray(input), ""));
break;
default:
undefinedInputFormat = true;
}
} catch (e) {
throw "Certificate load error (non-certificate input?)";
}
if (undefinedInputFormat) throw "Undefined input format";
const sn = cert.getSerialNumberHex(),
issuer = cert.getIssuer(),
+21 -1
View File
@@ -5,6 +5,7 @@
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
/**
* Reverse operation
@@ -26,7 +27,8 @@ class Reverse extends Operation {
{
"name": "By",
"type": "option",
"value": ["Character", "Line"]
"value": ["Byte", "Character", "Line"],
"defaultIndex": 1
}
];
}
@@ -57,6 +59,24 @@ class Reverse extends Operation {
result.push(0x0a);
}
return result.slice(0, input.length);
} else if (args[0] === "Character") {
const inputString = Utils.byteArrayToUtf8(input);
let result = "";
for (let i = inputString.length - 1; i >= 0; i--) {
const c = inputString.charCodeAt(i);
if (i > 0 && 0xdc00 <= c && c <= 0xdfff) {
const c2 = inputString.charCodeAt(i - 1);
if (0xd800 <= c2 && c2 <= 0xdbff) {
// surrogates
result += inputString.charAt(i - 1);
result += inputString.charAt(i);
i--;
continue;
}
}
result += inputString.charAt(i);
}
return Utils.strToUtf8ByteArray(result);
} else {
return input.reverse();
}
+78
View File
@@ -0,0 +1,78 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
/**
* Shuffle operation
*/
class Shuffle extends Operation {
/**
* Shuffle constructor
*/
constructor() {
super();
this.name = "Shuffle";
this.module = "Default";
this.description = "Randomly reorders input elements.";
this.infoURL = "https://wikipedia.org/wiki/Shuffling";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Delimiter",
type: "option",
value: INPUT_DELIM_OPTIONS
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const delim = Utils.charRep(args[0]);
if (input.length === 0) return input;
// return a random number in [0, 1)
const rng = (typeof crypto) !== "undefined" && crypto.getRandomValues ? (function() {
const buf = new Uint32Array(2);
return function() {
// generate 53-bit random integer: 21 + 32 bits
crypto.getRandomValues(buf);
const value = (buf[0] >>> (32 - 21)) * ((1 << 30) * 4) + buf[1];
return value / ((1 << 23) * (1 << 30));
};
})() : Math.random;
// return a random integer in [0, max)
const randint = function(max) {
return Math.floor(rng() * max);
};
// Split input into shuffleable sections
const toShuffle = input.split(delim);
// shuffle elements
for (let i = toShuffle.length - 1; i > 0; i--) {
const idx = randint(i + 1);
const tmp = toShuffle[idx];
toShuffle[idx] = toShuffle[i];
toShuffle[i] = tmp;
}
return toShuffle.join(delim);
}
}
export default Shuffle;
+4 -2
View File
@@ -7,7 +7,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
import {caseInsensitiveSort, ipSort, numericSort, hexadecimalSort} from "../lib/Sort.mjs";
import {caseInsensitiveSort, ipSort, numericSort, hexadecimalSort, lengthSort} from "../lib/Sort.mjs";
/**
* Sort operation
@@ -39,7 +39,7 @@ class Sort extends Operation {
{
"name": "Order",
"type": "option",
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric", "Numeric (hexadecimal)"]
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric", "Numeric (hexadecimal)", "Length"]
}
];
}
@@ -65,6 +65,8 @@ class Sort extends Operation {
sorted = sorted.sort(numericSort);
} else if (order === "Numeric (hexadecimal)") {
sorted = sorted.sort(hexadecimalSort);
} else if (order === "Length") {
sorted = sorted.sort(lengthSort);
}
if (sortReverse) sorted.reverse();
+58 -2
View File
@@ -20,7 +20,7 @@ class ToTable extends Operation {
this.name = "To Table";
this.module = "Default";
this.description = "Data can be split on different characters and rendered as an HTML or ASCII table with an optional header row.<br><br>Supports the CSV (Comma Separated Values) file format by default. Change the cell delimiter argument to <code>\\t</code> to support TSV (Tab Separated Values) or <code>|</code> for PSV (Pipe Separated Values).<br><br>You can enter as many delimiters as you like. Each character will be treat as a separate possible delimiter.";
this.description = "Data can be split on different characters and rendered as an HTML, ASCII or Markdown table with an optional header row.<br><br>Supports the CSV (Comma Separated Values) file format by default. Change the cell delimiter argument to <code>\\t</code> to support TSV (Tab Separated Values) or <code>|</code> for PSV (Pipe Separated Values).<br><br>You can enter as many delimiters as you like. Each character will be treat as a separate possible delimiter.";
this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
this.inputType = "string";
this.outputType = "html";
@@ -43,7 +43,7 @@ class ToTable extends Operation {
{
"name": "Format",
"type": "option",
"value": ["ASCII", "HTML"]
"value": ["ASCII", "HTML", "Markdown"]
}
];
}
@@ -66,6 +66,9 @@ class ToTable extends Operation {
case "ASCII":
return asciiOutput(tableData);
case "HTML":
return htmlOutput(tableData);
case "Markdown":
return markdownOutput(tableData);
default:
return htmlOutput(tableData);
}
@@ -183,6 +186,59 @@ class ToTable extends Operation {
return output;
}
}
/**
* Outputs an array of data as a Markdown table.
*
* @param {string[][]} tableData
* @returns {string}
*/
function markdownOutput(tableData) {
const headerDivider = "-";
const verticalBorder = "|";
let output = "";
const longestCells = [];
// Find longestCells value per column to pad cells equally.
tableData.forEach(function(row, index) {
row.forEach(function(cell, cellIndex) {
if (longestCells[cellIndex] === undefined || cell.length > longestCells[cellIndex]) {
longestCells[cellIndex] = cell.length;
}
});
});
// Ignoring the checkbox, as current Mardown renderer in CF doesn't handle table without headers
const row = tableData.shift();
output += outputRow(row, longestCells);
let rowOutput = verticalBorder;
row.forEach(function(cell, index) {
rowOutput += " " + headerDivider + " " + verticalBorder;
});
output += rowOutput += "\n";
// Add the rest of the table rows.
tableData.forEach(function(row, index) {
output += outputRow(row, longestCells);
});
return output;
/**
* Outputs a row of correctly padded cells.
*/
function outputRow(row, longestCells) {
let rowOutput = verticalBorder;
row.forEach(function(cell, index) {
rowOutput += " " + cell + " ".repeat(longestCells[index] - cell.length) + " " + verticalBorder;
});
rowOutput += "\n";
return rowOutput;
}
}
}
}
+3 -2
View File
@@ -70,7 +70,7 @@ class TripleDESDecrypt extends Operation {
inputType = args[3],
outputType = args[4];
if (key.length !== 24) {
if (key.length !== 24 && key.length !== 16) {
throw new OperationError(`Invalid key length: ${key.length} bytes
Triple DES uses a key length of 24 bytes (192 bits).
@@ -85,7 +85,8 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
input = Utils.convertToByteString(input, inputType);
const decipher = forge.cipher.createDecipher("3DES-" + mode, key);
const decipher = forge.cipher.createDecipher("3DES-" + mode,
key.length === 16 ? key + key.substring(0, 8) : key);
/* Allow for a "no padding" mode */
if (noPadding) {
+3 -2
View File
@@ -69,7 +69,7 @@ class TripleDESEncrypt extends Operation {
inputType = args[3],
outputType = args[4];
if (key.length !== 24) {
if (key.length !== 24 && key.length !== 16) {
throw new OperationError(`Invalid key length: ${key.length} bytes
Triple DES uses a key length of 24 bytes (192 bits).
@@ -84,7 +84,8 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
input = Utils.convertToByteString(input, inputType);
const cipher = forge.cipher.createCipher("3DES-" + mode, key);
const cipher = forge.cipher.createCipher("3DES-" + mode,
key.length === 16 ? key + key.substring(0, 8) : key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(input));
cipher.finish();
@@ -79,6 +79,9 @@ class UNIXTimestampToWindowsFiletime extends Operation {
flipped += result.charAt(i);
flipped += result.charAt(i + 1);
}
if (result.length % 2 !== 0) {
flipped += "0" + result.charAt(0);
}
result = flipped;
}
+1 -1
View File
@@ -90,7 +90,7 @@ class ViewBitPlane extends Operation {
* @returns {html}
*/
present(data) {
if (!data.length) return "";
if (!data.byteLength) return "";
const type = isImage(data);
return `<img src="data:${type};base64,${toBase64(data)}">`;
@@ -52,7 +52,10 @@ class WindowsFiletimeToUNIXTimestamp extends Operation {
if (format === "Hex (little endian)") {
// Swap endianness
let result = "";
for (let i = input.length - 2; i >= 0; i -= 2) {
if (input.length % 2 !== 0) {
result += input.charAt(input.length - 1);
}
for (let i = input.length - input.length % 2 - 2; i >= 0; i -= 2) {
result += input.charAt(i);
result += input.charAt(i + 1);
}
+6 -6
View File
@@ -45,10 +45,10 @@ TestRegister.addApiTests([
const result = chef.ADD("sample input", {
key: {
string: "some key",
option: "Hex"
option: "utf8"
}
});
assert.equal(result.toString(), "aO[^ZS\u000eW\\^cb");
assert.equal(result.toString(), "\xe6\xd0\xda\xd5\x8c\xd0\x85\xe2\xe1\xdf\xe2\xd9");
}),
@@ -121,10 +121,10 @@ Tiger-128`;
const result = chef.AND("Scot-free", {
key: {
string: "Raining Cats and Dogs",
option: "Hex",
option: "utf8",
}
});
assert.strictEqual(result.toString(), "\u0000\"M$(D E");
assert.strictEqual(result.toString(), "Raid)fb A");
}),
it("atBash Cipher", () => {
@@ -371,10 +371,10 @@ color: white;
},
salt: {
string: "Market",
option: "Hex",
option: "utf8",
},
});
assert.strictEqual(result.toString(), "7c21a9f5063a4d62fb1050068245c181");
assert.strictEqual(result.toString(), "4930d5d200e80f18c96b5550d13c6af8");
}),
it("Derive PBKDF2 Key", () => {
+1
View File
@@ -124,6 +124,7 @@ import "./tests/UnescapeString.mjs";
import "./tests/LS47.mjs";
import "./tests/LZString.mjs";
import "./tests/NTLM.mjs";
import "./tests/Shuffle.mjs";
// Cannot test operations that use the File type yet
// import "./tests/SplitColourChannels.mjs";
+54
View File
@@ -0,0 +1,54 @@
/**
* @author mikecat
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
"name": "Shuffle empty",
"input": "",
"expectedOutput": "",
"recipeConfig": [
{
"op": "Shuffle",
"args": ["Comma"]
}
]
},
{
"name": "Shuffle bytes",
"input": "12345678",
"expectedOutput": "31 32 33 34 35 36 37 38",
"recipeConfig": [
{
"op": "Shuffle",
"args": ["Nothing (separate chars)"]
},
{
"op": "To Hex",
"args": ["Space", 0]
},
{
"op": "Sort",
"args": ["Space", false, "Alphabetical (case sensitive)"]
}
]
},
{
"name": "Shuffle lines",
"input": "1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf\n",
"expectedOutput": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\na\nb\nc\nd\ne\nf",
"recipeConfig": [
{
"op": "Shuffle",
"args": ["Line feed"]
},
{
"op": "Sort",
"args": ["Line feed", false, "Alphabetical (case sensitive)"]
}
]
}
]);