mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-22 07:46:16 -04:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d3138a7fdf
576 changed files with 37857 additions and 7535 deletions
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* A1Z26 Cipher Decode operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
|
||||
/**
|
||||
* A1Z26 Cipher Encode operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { bitOp, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs";
|
||||
|
||||
/**
|
||||
* ADD operation
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* AES Decrypt operation
|
||||
|
@ -71,8 +71,8 @@ class AESDecrypt extends Operation {
|
|||
* @throws {OperationError} if cannot decrypt input or invalid key length
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4],
|
||||
|
@ -91,7 +91,7 @@ The following algorithms will be used based on the size of the key:
|
|||
|
||||
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
||||
decipher.start({
|
||||
iv: iv,
|
||||
iv: iv.length === 0 ? "" : iv,
|
||||
tag: gcmTag
|
||||
});
|
||||
decipher.update(forge.util.createBuffer(input));
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* AES Encrypt operation
|
||||
|
@ -65,8 +65,8 @@ class AESEncrypt extends Operation {
|
|||
* @throws {OperationError} if invalid key length
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
const key = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, and, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { bitOp, and, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs";
|
||||
|
||||
/**
|
||||
* AND operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Add line numbers operation
|
||||
|
|
267
src/core/operations/AddTextToImage.mjs
Normal file
267
src/core/operations/AddTextToImage.mjs
Normal file
|
@ -0,0 +1,267 @@
|
|||
/**
|
||||
* @author j433866 [j433866@gmail.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
* Add Text To Image operation
|
||||
*/
|
||||
class AddTextToImage extends Operation {
|
||||
|
||||
/**
|
||||
* AddTextToImage constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Add Text To Image";
|
||||
this.module = "Image";
|
||||
this.description = "Adds text onto an image.<br><br>Text can be horizontally or vertically aligned, or the position can be manually specified.<br>Variants of the Roboto font face are available in any size or colour.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
name: "Text",
|
||||
type: "string",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
name: "Horizontal align",
|
||||
type: "option",
|
||||
value: ["None", "Left", "Center", "Right"]
|
||||
},
|
||||
{
|
||||
name: "Vertical align",
|
||||
type: "option",
|
||||
value: ["None", "Top", "Middle", "Bottom"]
|
||||
},
|
||||
{
|
||||
name: "X position",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Y position",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Size",
|
||||
type: "number",
|
||||
value: 32,
|
||||
min: 8
|
||||
},
|
||||
{
|
||||
name: "Font face",
|
||||
type: "option",
|
||||
value: [
|
||||
"Roboto",
|
||||
"Roboto Black",
|
||||
"Roboto Mono",
|
||||
"Roboto Slab"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Red",
|
||||
type: "number",
|
||||
value: 255,
|
||||
min: 0,
|
||||
max: 255
|
||||
},
|
||||
{
|
||||
name: "Green",
|
||||
type: "number",
|
||||
value: 255,
|
||||
min: 0,
|
||||
max: 255
|
||||
},
|
||||
{
|
||||
name: "Blue",
|
||||
type: "number",
|
||||
value: 255,
|
||||
min: 0,
|
||||
max: 255
|
||||
},
|
||||
{
|
||||
name: "Alpha",
|
||||
type: "number",
|
||||
value: 255,
|
||||
min: 0,
|
||||
max: 255
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const text = args[0],
|
||||
hAlign = args[1],
|
||||
vAlign = args[2],
|
||||
size = args[5],
|
||||
fontFace = args[6],
|
||||
red = args[7],
|
||||
green = args[8],
|
||||
blue = args[9],
|
||||
alpha = args[10];
|
||||
|
||||
let xPos = args[3],
|
||||
yPos = args[4];
|
||||
|
||||
if (!isImage(input)) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Adding text to image...");
|
||||
|
||||
const fontsMap = {};
|
||||
const fonts = [
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt")
|
||||
];
|
||||
|
||||
await Promise.all(fonts)
|
||||
.then(fonts => {
|
||||
fontsMap.Roboto = fonts[0];
|
||||
fontsMap["Roboto Black"] = fonts[1];
|
||||
fontsMap["Roboto Mono"] = fonts[2];
|
||||
fontsMap["Roboto Slab"] = fonts[3];
|
||||
});
|
||||
|
||||
|
||||
// Make Webpack load the png font images
|
||||
await Promise.all([
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"),
|
||||
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png")
|
||||
]);
|
||||
|
||||
const font = fontsMap[fontFace];
|
||||
|
||||
// LoadFont needs an absolute url, so append the font name to self.docURL
|
||||
const jimpFont = await jimp.loadFont(self.docURL + "/" + font.default);
|
||||
|
||||
jimpFont.pages.forEach(function(page) {
|
||||
if (page.bitmap) {
|
||||
// Adjust the RGB values of the image pages to change the font colour.
|
||||
const pageWidth = page.bitmap.width;
|
||||
const pageHeight = page.bitmap.height;
|
||||
for (let ix = 0; ix < pageWidth; ix++) {
|
||||
for (let iy = 0; iy < pageHeight; iy++) {
|
||||
const idx = (iy * pageWidth + ix) << 2;
|
||||
|
||||
const newRed = page.bitmap.data[idx] - (255 - red);
|
||||
const newGreen = page.bitmap.data[idx + 1] - (255 - green);
|
||||
const newBlue = page.bitmap.data[idx + 2] - (255 - blue);
|
||||
const newAlpha = page.bitmap.data[idx + 3] - (255 - alpha);
|
||||
|
||||
// Make sure the bitmap values don't go below 0 as that makes jimp very unhappy
|
||||
page.bitmap.data[idx] = (newRed > 0) ? newRed : 0;
|
||||
page.bitmap.data[idx + 1] = (newGreen > 0) ? newGreen : 0;
|
||||
page.bitmap.data[idx + 2] = (newBlue > 0) ? newBlue : 0;
|
||||
page.bitmap.data[idx + 3] = (newAlpha > 0) ? newAlpha : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Create a temporary image to hold the rendered text
|
||||
const textImage = new jimp(jimp.measureText(jimpFont, text), jimp.measureTextHeight(jimpFont, text));
|
||||
textImage.print(jimpFont, 0, 0, text);
|
||||
|
||||
// Scale the rendered text image to the correct size
|
||||
const scaleFactor = size / 72;
|
||||
if (size !== 1) {
|
||||
// Use bicubic for decreasing size
|
||||
if (size > 1) {
|
||||
textImage.scale(scaleFactor, jimp.RESIZE_BICUBIC);
|
||||
} else {
|
||||
textImage.scale(scaleFactor, jimp.RESIZE_BILINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
// If using the alignment options, calculate the pixel values AFTER the image has been scaled
|
||||
switch (hAlign) {
|
||||
case "Left":
|
||||
xPos = 0;
|
||||
break;
|
||||
case "Center":
|
||||
xPos = (image.getWidth() / 2) - (textImage.getWidth() / 2);
|
||||
break;
|
||||
case "Right":
|
||||
xPos = image.getWidth() - textImage.getWidth();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vAlign) {
|
||||
case "Top":
|
||||
yPos = 0;
|
||||
break;
|
||||
case "Middle":
|
||||
yPos = (image.getHeight() / 2) - (textImage.getHeight() / 2);
|
||||
break;
|
||||
case "Bottom":
|
||||
yPos = image.getHeight() - textImage.getHeight();
|
||||
break;
|
||||
}
|
||||
|
||||
// Blit the rendered text image onto the original source image
|
||||
image.blit(textImage, xPos, yPos);
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error adding text to image. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the blurred image using HTML for web apps
|
||||
*
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AddTextToImage;
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Adler-32 Checksum operation
|
||||
|
@ -22,13 +22,13 @@ class Adler32Checksum extends Operation {
|
|||
this.module = "Crypto";
|
||||
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Adler-32";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@ class Adler32Checksum extends Operation {
|
|||
const MOD_ADLER = 65521;
|
||||
let a = 1,
|
||||
b = 0;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a += input[i];
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Affine Cipher Decode operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { affineEncode } from "../lib/Ciphers";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { affineEncode } from "../lib/Ciphers.mjs";
|
||||
|
||||
/**
|
||||
* Affine Cipher Encode operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Analyse hash operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { affineEncode } from "../lib/Ciphers";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { affineEncode } from "../lib/Ciphers.mjs";
|
||||
|
||||
/**
|
||||
* Atbash Cipher operation
|
||||
|
|
79
src/core/operations/BLAKE2b.mjs
Normal file
79
src/core/operations/BLAKE2b.mjs
Normal file
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* @author h345983745
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import blakejs from "blakejs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
|
||||
/**
|
||||
* BLAKE2b operation
|
||||
*/
|
||||
class BLAKE2b extends Operation {
|
||||
|
||||
/**
|
||||
* BLAKE2b constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "BLAKE2b";
|
||||
this.module = "Hashing";
|
||||
this.description = `Performs BLAKE2b hashing on the input.
|
||||
<br><br> BLAKE2b is a flavour of the BLAKE cryptographic hash function that is optimized for 64-bit platforms and produces digests of any size between 1 and 64 bytes.
|
||||
<br><br> Supports the use of an optional key.`;
|
||||
this.infoURL = "https://wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2b_algorithm";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Size",
|
||||
"type": "option",
|
||||
"value": ["512", "384", "256", "160", "128"]
|
||||
}, {
|
||||
"name": "Output Encoding",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Base64", "Raw"]
|
||||
}, {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["UTF8", "Decimal", "Base64", "Hex", "Latin1"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} The input having been hashed with BLAKE2b in the encoding format specified.
|
||||
*/
|
||||
run(input, args) {
|
||||
const [outSize, outFormat] = args;
|
||||
let key = Utils.convertToByteArray(args[2].string || "", args[2].option);
|
||||
if (key.length === 0) {
|
||||
key = null;
|
||||
} else if (key.length > 64) {
|
||||
throw new OperationError(["Key cannot be greater than 64 bytes", "It is currently " + key.length + " bytes."].join("\n"));
|
||||
}
|
||||
|
||||
input = new Uint8Array(input);
|
||||
switch (outFormat) {
|
||||
case "Hex":
|
||||
return blakejs.blake2bHex(input, key, outSize / 8);
|
||||
case "Base64":
|
||||
return toBase64(blakejs.blake2b(input, key, outSize / 8));
|
||||
case "Raw":
|
||||
return Utils.arrayBufferToStr(blakejs.blake2b(input, key, outSize / 8).buffer);
|
||||
default:
|
||||
return new OperationError("Unsupported Output Type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BLAKE2b;
|
80
src/core/operations/BLAKE2s.mjs
Normal file
80
src/core/operations/BLAKE2s.mjs
Normal file
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* @author h345983745
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import blakejs from "blakejs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
|
||||
/**
|
||||
* BLAKE2s Operation
|
||||
*/
|
||||
class BLAKE2s extends Operation {
|
||||
|
||||
/**
|
||||
* BLAKE2s constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "BLAKE2s";
|
||||
this.module = "Hashing";
|
||||
this.description = `Performs BLAKE2s hashing on the input.
|
||||
<br><br>BLAKE2s is a flavour of the BLAKE cryptographic hash function that is optimized for 8- to 32-bit platforms and produces digests of any size between 1 and 32 bytes.
|
||||
<br><br>Supports the use of an optional key.`;
|
||||
this.infoURL = "https://wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Size",
|
||||
"type": "option",
|
||||
"value": ["256", "160", "128"]
|
||||
}, {
|
||||
"name": "Output Encoding",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Base64", "Raw"]
|
||||
},
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["UTF8", "Decimal", "Base64", "Hex", "Latin1"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string} The input having been hashed with BLAKE2s in the encoding format specified.
|
||||
*/
|
||||
run(input, args) {
|
||||
const [outSize, outFormat] = args;
|
||||
let key = Utils.convertToByteArray(args[2].string || "", args[2].option);
|
||||
if (key.length === 0) {
|
||||
key = null;
|
||||
} else if (key.length > 32) {
|
||||
throw new OperationError(["Key cannot be greater than 32 bytes", "It is currently " + key.length + " bytes."].join("\n"));
|
||||
}
|
||||
|
||||
input = new Uint8Array(input);
|
||||
switch (outFormat) {
|
||||
case "Hex":
|
||||
return blakejs.blake2sHex(input, key, outSize / 8);
|
||||
case "Base64":
|
||||
return toBase64(blakejs.blake2s(input, key, outSize / 8));
|
||||
case "Raw":
|
||||
return Utils.arrayBufferToStr(blakejs.blake2s(input, key, outSize / 8).buffer);
|
||||
default:
|
||||
return new OperationError("Unsupported Output Type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BLAKE2s;
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import bson from "bson";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* BSON deserialise operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import bson from "bson";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* BSON serialise operation
|
||||
|
|
107
src/core/operations/BaconCipherDecode.mjs
Normal file
107
src/core/operations/BaconCipherDecode.mjs
Normal file
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* @author Karsten Silkenbäumer [github.com/kassi]
|
||||
* @copyright Karsten Silkenbäumer 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {
|
||||
BACON_ALPHABETS,
|
||||
BACON_TRANSLATION_CASE, BACON_TRANSLATION_AMNZ, BACON_TRANSLATIONS, BACON_CLEARER_MAP, BACON_NORMALIZE_MAP,
|
||||
swapZeroAndOne
|
||||
} from "../lib/Bacon";
|
||||
|
||||
/**
|
||||
* Bacon Cipher Decode operation
|
||||
*/
|
||||
class BaconCipherDecode extends Operation {
|
||||
/**
|
||||
* BaconCipherDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bacon Cipher Decode";
|
||||
this.module = "Default";
|
||||
this.description = "Bacon's cipher or the Baconian cipher is a method of steganography devised by Francis Bacon in 1605. A message is concealed in the presentation of text, rather than its content.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bacon%27s_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Alphabet",
|
||||
"type": "option",
|
||||
"value": Object.keys(BACON_ALPHABETS)
|
||||
},
|
||||
{
|
||||
"name": "Translation",
|
||||
"type": "option",
|
||||
"value": BACON_TRANSLATIONS
|
||||
},
|
||||
{
|
||||
"name": "Invert Translation",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [alphabet, translation, invert] = args;
|
||||
const alphabetObject = BACON_ALPHABETS[alphabet];
|
||||
|
||||
// remove invalid characters
|
||||
input = input.replace(BACON_CLEARER_MAP[translation], "");
|
||||
|
||||
// normalize to unique alphabet
|
||||
if (BACON_NORMALIZE_MAP[translation] !== undefined) {
|
||||
input = input.replace(/./g, function (c) {
|
||||
return BACON_NORMALIZE_MAP[translation][c];
|
||||
});
|
||||
} else if (translation === BACON_TRANSLATION_CASE) {
|
||||
const codeA = "A".charCodeAt(0);
|
||||
const codeZ = "Z".charCodeAt(0);
|
||||
input = input.replace(/./g, function (c) {
|
||||
const code = c.charCodeAt(0);
|
||||
if (code >= codeA && code <= codeZ) {
|
||||
return "1";
|
||||
} else {
|
||||
return "0";
|
||||
}
|
||||
});
|
||||
} else if (translation === BACON_TRANSLATION_AMNZ) {
|
||||
const words = input.split(/\s+/);
|
||||
const letters = words.map(function (e) {
|
||||
if (e) {
|
||||
const code = e[0].toUpperCase().charCodeAt(0);
|
||||
return code >= "N".charCodeAt(0) ? "1" : "0";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
input = letters.join("");
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
input = swapZeroAndOne(input);
|
||||
}
|
||||
|
||||
// group into 5
|
||||
const inputArray = input.match(/(.{5})/g) || [];
|
||||
|
||||
let output = "";
|
||||
for (let i = 0; i < inputArray.length; i++) {
|
||||
const code = inputArray[i];
|
||||
const number = parseInt(code, 2);
|
||||
output += number < alphabetObject.alphabet.length ? alphabetObject.alphabet[number] : "?";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export default BaconCipherDecode;
|
101
src/core/operations/BaconCipherEncode.mjs
Normal file
101
src/core/operations/BaconCipherEncode.mjs
Normal file
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @author Karsten Silkenbäumer [github.com/kassi]
|
||||
* @copyright Karsten Silkenbäumer 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {
|
||||
BACON_ALPHABETS,
|
||||
BACON_TRANSLATIONS_FOR_ENCODING, BACON_TRANSLATION_AB,
|
||||
swapZeroAndOne
|
||||
} from "../lib/Bacon";
|
||||
|
||||
/**
|
||||
* Bacon Cipher Encode operation
|
||||
*/
|
||||
class BaconCipherEncode extends Operation {
|
||||
/**
|
||||
* BaconCipherEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bacon Cipher Encode";
|
||||
this.module = "Default";
|
||||
this.description = "Bacon's cipher or the Baconian cipher is a method of steganography devised by Francis Bacon in 1605. A message is concealed in the presentation of text, rather than its content.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bacon%27s_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Alphabet",
|
||||
"type": "option",
|
||||
"value": Object.keys(BACON_ALPHABETS)
|
||||
},
|
||||
{
|
||||
"name": "Translation",
|
||||
"type": "option",
|
||||
"value": BACON_TRANSLATIONS_FOR_ENCODING
|
||||
},
|
||||
{
|
||||
"name": "Keep extra characters",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Invert Translation",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [alphabet, translation, keep, invert] = args;
|
||||
|
||||
const alphabetObject = BACON_ALPHABETS[alphabet];
|
||||
const charCodeA = "A".charCodeAt(0);
|
||||
const charCodeZ = "Z".charCodeAt(0);
|
||||
|
||||
let output = input.replace(/./g, function (c) {
|
||||
const charCode = c.toUpperCase().charCodeAt(0);
|
||||
if (charCode >= charCodeA && charCode <= charCodeZ) {
|
||||
let code = charCode - charCodeA;
|
||||
if (alphabetObject.codes !== undefined) {
|
||||
code = alphabetObject.codes[code];
|
||||
}
|
||||
const bacon = ("00000" + code.toString(2)).substr(-5, 5);
|
||||
return bacon;
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
if (invert) {
|
||||
output = swapZeroAndOne(output);
|
||||
}
|
||||
if (!keep) {
|
||||
output = output.replace(/[^01]/g, "");
|
||||
const outputArray = output.match(/(.{5})/g) || [];
|
||||
output = outputArray.join(" ");
|
||||
}
|
||||
if (translation === BACON_TRANSLATION_AB) {
|
||||
output = output.replace(/[01]/g, function (c) {
|
||||
return {
|
||||
"0": "A",
|
||||
"1": "B"
|
||||
}[c];
|
||||
});
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
export default BaconCipherEncode;
|
|
@ -4,8 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Bcrypt operation
|
||||
|
@ -44,7 +45,7 @@ class Bcrypt extends Operation {
|
|||
|
||||
return await bcrypt.hash(input, salt, null, p => {
|
||||
// Progress callback
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
|
||||
});
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
|
||||
/**
|
||||
* Bcrypt compare operation
|
||||
|
@ -43,7 +45,7 @@ class BcryptCompare extends Operation {
|
|||
|
||||
const match = await bcrypt.compare(input, hash, null, p => {
|
||||
// Progress callback
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
|
||||
});
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Bifid Cipher Decode operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers.mjs";
|
||||
|
||||
/**
|
||||
* Bifid Cipher Encode operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Bit shift left operation
|
||||
|
@ -21,8 +21,8 @@ class BitShiftLeft extends Operation {
|
|||
this.module = "Default";
|
||||
this.description = "Shifts the bits in each byte towards the left by the specified amount.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bitwise_operation#Bit_shifts";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Amount",
|
||||
|
@ -33,16 +33,17 @@ class BitShiftLeft extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
const amount = args[0];
|
||||
input = new Uint8Array(input);
|
||||
|
||||
return input.map(b => {
|
||||
return (b << amount) & 0xff;
|
||||
});
|
||||
}).buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Bit shift right operation
|
||||
|
@ -21,8 +21,8 @@ class BitShiftRight extends Operation {
|
|||
this.module = "Default";
|
||||
this.description = "Shifts the bits in each byte towards the right by the specified amount.<br><br><i>Logical shifts</i> replace the leftmost bits with zeros.<br><i>Arithmetic shifts</i> preserve the most significant bit (MSB) of the original byte keeping the sign the same (positive or negative).";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bitwise_operation#Bit_shifts";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Amount",
|
||||
|
@ -38,18 +38,19 @@ class BitShiftRight extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
const amount = args[0],
|
||||
type = args[1],
|
||||
mask = type === "Logical shift" ? 0 : 0x80;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
return input.map(b => {
|
||||
return (b >>> amount) ^ (b & mask);
|
||||
});
|
||||
}).buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { Blowfish } from "../vendor/Blowfish";
|
||||
import { toBase64 } from "../lib/Base64";
|
||||
import { toHexFast } from "../lib/Hex";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { Blowfish } from "../vendor/Blowfish.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* Lookup table for Blowfish output types.
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { Blowfish } from "../vendor/Blowfish";
|
||||
import { toBase64 } from "../lib/Base64";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { Blowfish } from "../vendor/Blowfish.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
|
||||
/**
|
||||
* Lookup table for Blowfish output types.
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import { toBase64 } from "../lib/Base64";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||
|
||||
/**
|
||||
* Blur Image operation
|
||||
|
@ -25,8 +27,8 @@ class BlurImage extends Operation {
|
|||
this.module = "Image";
|
||||
this.description = "Applies a blur effect to the image.<br><br>Gaussian blur is much slower than fast blur, but produces better results.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Gaussian_blur";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
|
@ -44,7 +46,7 @@ class BlurImage extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
|
@ -57,24 +59,31 @@ class BlurImage extends Operation {
|
|||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(Buffer.from(input));
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
switch (blurType){
|
||||
switch (blurType) {
|
||||
case "Fast":
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Fast blurring image...");
|
||||
image.blur(blurAmount);
|
||||
break;
|
||||
case "Gaussian":
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Gaussian blurring image. This may take a while...");
|
||||
image.gaussian(blurAmount);
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Gaussian blurring image...");
|
||||
image = gaussianBlur(image, blurAmount);
|
||||
break;
|
||||
}
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error blurring image. (${err})`);
|
||||
}
|
||||
|
@ -83,18 +92,19 @@ class BlurImage extends Operation {
|
|||
/**
|
||||
* Displays the blurred image using HTML for web apps
|
||||
*
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.length) return "";
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(data);
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import {BombeMachine} from "../lib/Bombe";
|
||||
import {ROTORS, ROTORS_FOURTH, REFLECTORS, Reflector} from "../lib/Enigma";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import { BombeMachine } from "../lib/Bombe.mjs";
|
||||
import { ROTORS, ROTORS_FOURTH, REFLECTORS, Reflector } from "../lib/Enigma.mjs";
|
||||
|
||||
/**
|
||||
* Bombe operation
|
||||
|
@ -139,7 +140,7 @@ class Bombe extends Operation {
|
|||
const ciphertext = input.slice(offset);
|
||||
const reflector = new Reflector(reflectorstr);
|
||||
let update;
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
if (isWorkerEnvironment()) {
|
||||
update = this.updateStatus;
|
||||
} else {
|
||||
update = undefined;
|
||||
|
|
73
src/core/operations/Bzip2Compress.mjs
Normal file
73
src/core/operations/Bzip2Compress.mjs
Normal file
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @author Matt C [me@mitt.dev]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Bzip2 from "libbzip2-wasm";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Bzip2 Compress operation
|
||||
*/
|
||||
class Bzip2Compress extends Operation {
|
||||
|
||||
/**
|
||||
* Bzip2Compress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bzip2 Compress";
|
||||
this.module = "Compression";
|
||||
this.description = "Bzip2 is a compression library developed by Julian Seward (of GHC fame) that uses the Burrows-Wheeler algorithm. It only supports compressing single files and its compression is slow, however is more effective than Deflate (.gz & .zip).";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bzip2";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Block size (100s of kb)",
|
||||
type: "number",
|
||||
value: 9,
|
||||
min: 1,
|
||||
max: 9
|
||||
},
|
||||
{
|
||||
name: "Work factor",
|
||||
type: "number",
|
||||
value: 30
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {File}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [blockSize, workFactor] = args;
|
||||
if (input.byteLength <= 0) {
|
||||
throw new OperationError("Please provide an input.");
|
||||
}
|
||||
if (isWorkerEnvironment()) self.sendStatusMessage("Loading Bzip2...");
|
||||
return new Promise((resolve, reject) => {
|
||||
Bzip2().then(bzip2 => {
|
||||
if (isWorkerEnvironment()) self.sendStatusMessage("Compressing data...");
|
||||
const inpArray = new Uint8Array(input);
|
||||
const bzip2cc = bzip2.compressBZ2(inpArray, blockSize, workFactor);
|
||||
if (bzip2cc.error !== 0) {
|
||||
reject(new OperationError(bzip2cc.error_msg));
|
||||
} else {
|
||||
const output = bzip2cc.output;
|
||||
resolve(output.buffer.slice(output.byteOffset, output.byteLength + output.byteOffset));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bzip2Compress;
|
|
@ -1,12 +1,13 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @author Matt C [me@mitt.dev]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bzip2 from "../vendor/bzip2";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Bzip2 from "libbzip2-wasm";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Bzip2 Decompress operation
|
||||
|
@ -23,9 +24,15 @@ class Bzip2Decompress extends Operation {
|
|||
this.module = "Compression";
|
||||
this.description = "Decompresses data using the Bzip2 algorithm.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bzip2";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
name: "Use low-memory, slower decompression algorithm",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
"match": "^\\x42\\x5a\\x68",
|
||||
|
@ -40,15 +47,25 @@ class Bzip2Decompress extends Operation {
|
|||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const compressed = new Uint8Array(input);
|
||||
|
||||
try {
|
||||
const bzip2Reader = bzip2.array(compressed);
|
||||
return bzip2.simple(bzip2Reader);
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
async run(input, args) {
|
||||
const [small] = args;
|
||||
if (input.byteLength <= 0) {
|
||||
throw new OperationError("Please provide an input.");
|
||||
}
|
||||
if (isWorkerEnvironment()) self.sendStatusMessage("Loading Bzip2...");
|
||||
return new Promise((resolve, reject) => {
|
||||
Bzip2().then(bzip2 => {
|
||||
if (isWorkerEnvironment()) self.sendStatusMessage("Decompressing data...");
|
||||
const inpArray = new Uint8Array(input);
|
||||
const bzip2cc = bzip2.decompressBZ2(inpArray, small ? 1 : 0);
|
||||
if (bzip2cc.error !== 0) {
|
||||
reject(new OperationError(bzip2cc.error_msg));
|
||||
} else {
|
||||
const output = bzip2cc.output;
|
||||
resolve(output.buffer.slice(output.byteOffset, output.byteLength + output.byteOffset));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import JSCRC from "js-crc";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import JSCRC from "js-crc";
|
||||
|
||||
/**
|
||||
|
|
157
src/core/operations/CRC8Checksum.mjs
Normal file
157
src/core/operations/CRC8Checksum.mjs
Normal file
|
@ -0,0 +1,157 @@
|
|||
/**
|
||||
* @author mshwed [m@ttshwed.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
import { toHexFast } from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* CRC-8 Checksum operation
|
||||
*/
|
||||
class CRC8Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* CRC8Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CRC-8 Checksum";
|
||||
this.module = "Crypto";
|
||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Algorithm",
|
||||
"type": "option",
|
||||
"value": [
|
||||
"CRC-8",
|
||||
"CRC-8/CDMA2000",
|
||||
"CRC-8/DARC",
|
||||
"CRC-8/DVB-S2",
|
||||
"CRC-8/EBU",
|
||||
"CRC-8/I-CODE",
|
||||
"CRC-8/ITU",
|
||||
"CRC-8/MAXIM",
|
||||
"CRC-8/ROHC",
|
||||
"CRC-8/WCDMA"
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the pre-computed lookup table for byte division
|
||||
*
|
||||
* @param polynomial
|
||||
*/
|
||||
calculateCRC8LookupTable(polynomial) {
|
||||
const crc8Table = new Uint8Array(256);
|
||||
|
||||
let currentByte;
|
||||
for (let i = 0; i < 256; i++) {
|
||||
currentByte = i;
|
||||
for (let bit = 0; bit < 8; bit++) {
|
||||
if ((currentByte & 0x80) !== 0) {
|
||||
currentByte <<= 1;
|
||||
currentByte ^= polynomial;
|
||||
} else {
|
||||
currentByte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc8Table[i] = currentByte;
|
||||
}
|
||||
|
||||
return crc8Table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the CRC-8 Checksum from an input
|
||||
*
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {number} polynomial
|
||||
* @param {number} initializationValue
|
||||
* @param {boolean} inputReflection
|
||||
* @param {boolean} outputReflection
|
||||
* @param {number} xorOut
|
||||
*/
|
||||
calculateCRC8(input, polynomial, initializationValue, inputReflection, outputReflection, xorOut) {
|
||||
const crcSize = 8;
|
||||
const crcTable = this.calculateCRC8LookupTable(polynomial);
|
||||
|
||||
let crc = initializationValue !== 0 ? initializationValue : 0;
|
||||
let currentByte, position;
|
||||
|
||||
input = new Uint8Array(input);
|
||||
for (const inputByte of input) {
|
||||
currentByte = inputReflection ? this.reverseBits(inputByte, crcSize) : inputByte;
|
||||
|
||||
position = (currentByte ^ crc) & 255;
|
||||
crc = crcTable[position];
|
||||
}
|
||||
|
||||
crc = outputReflection ? this.reverseBits(crc, crcSize) : crc;
|
||||
|
||||
if (xorOut !== 0) crc = crc ^ xorOut;
|
||||
|
||||
return toHexFast(new Uint8Array([crc]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the bits for a given input byte.
|
||||
*
|
||||
* @param {number} input
|
||||
*/
|
||||
reverseBits(input, hashSize) {
|
||||
let reversedByte = 0;
|
||||
for (let i = hashSize - 1; i >= 0; i--) {
|
||||
reversedByte |= ((input & 1) << i);
|
||||
input >>= 1;
|
||||
}
|
||||
|
||||
return reversedByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const algorithm = args[0];
|
||||
|
||||
switch (algorithm) {
|
||||
case "CRC-8":
|
||||
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x0);
|
||||
case "CRC-8/CDMA2000":
|
||||
return this.calculateCRC8(input, 0x9B, 0xFF, false, false, 0x0);
|
||||
case "CRC-8/DARC":
|
||||
return this.calculateCRC8(input, 0x39, 0x0, true, true, 0x0);
|
||||
case "CRC-8/DVB-S2":
|
||||
return this.calculateCRC8(input, 0xD5, 0x0, false, false, 0x0);
|
||||
case "CRC-8/EBU":
|
||||
return this.calculateCRC8(input, 0x1D, 0xFF, true, true, 0x0);
|
||||
case "CRC-8/I-CODE":
|
||||
return this.calculateCRC8(input, 0x1D, 0xFD, false, false, 0x0);
|
||||
case "CRC-8/ITU":
|
||||
return this.calculateCRC8(input, 0x7, 0x0, false, false, 0x55);
|
||||
case "CRC-8/MAXIM":
|
||||
return this.calculateCRC8(input, 0x31, 0x0, true, true, 0x0);
|
||||
case "CRC-8/ROHC":
|
||||
return this.calculateCRC8(input, 0x7, 0xFF, true, true, 0x0);
|
||||
case "CRC-8/WCDMA":
|
||||
return this.calculateCRC8(input, 0x9B, 0x0, true, true, 0x0);
|
||||
default:
|
||||
throw new OperationError("Unknown checksum algorithm");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default CRC8Checksum;
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import vkbeautify from "vkbeautify";
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* CSS Beautify operation
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import vkbeautify from "vkbeautify";
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* CSS Minify operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import xmldom from "xmldom";
|
||||
import nwmatcher from "nwmatcher";
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* CSV to JSON operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import ctphjs from "ctph.js";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Set cartesian product operation
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import {fromHex} from "../lib/Hex";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {fromHex} from "../lib/Hex.mjs";
|
||||
|
||||
/**
|
||||
* Change IP format operation
|
||||
|
@ -29,12 +29,12 @@ class ChangeIPFormat extends Operation {
|
|||
{
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["Dotted Decimal", "Decimal", "Hex"]
|
||||
"value": ["Dotted Decimal", "Decimal", "Octal", "Hex"]
|
||||
},
|
||||
{
|
||||
"name": "Output format",
|
||||
"type": "option",
|
||||
"value": ["Dotted Decimal", "Decimal", "Hex"]
|
||||
"value": ["Dotted Decimal", "Decimal", "Octal", "Hex"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ class ChangeIPFormat extends Operation {
|
|||
if (lines[i] === "") continue;
|
||||
let baIp = [];
|
||||
let octets;
|
||||
let decimal;
|
||||
|
||||
if (inFormat === outFormat) {
|
||||
output += lines[i] + "\n";
|
||||
|
@ -70,11 +69,10 @@ class ChangeIPFormat extends Operation {
|
|||
}
|
||||
break;
|
||||
case "Decimal":
|
||||
decimal = lines[i].toString();
|
||||
baIp.push(decimal >> 24 & 255);
|
||||
baIp.push(decimal >> 16 & 255);
|
||||
baIp.push(decimal >> 8 & 255);
|
||||
baIp.push(decimal & 255);
|
||||
baIp = this.fromNumber(lines[i].toString(), 10);
|
||||
break;
|
||||
case "Octal":
|
||||
baIp = this.fromNumber(lines[i].toString(), 8);
|
||||
break;
|
||||
case "Hex":
|
||||
baIp = fromHex(lines[i]);
|
||||
|
@ -100,6 +98,10 @@ class ChangeIPFormat extends Operation {
|
|||
decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
|
||||
output += decIp.toString() + "\n";
|
||||
break;
|
||||
case "Octal":
|
||||
decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
|
||||
output += "0" + decIp.toString(8) + "\n";
|
||||
break;
|
||||
case "Hex":
|
||||
hexIp = "";
|
||||
for (j = 0; j < baIp.length; j++) {
|
||||
|
@ -115,6 +117,22 @@ class ChangeIPFormat extends Operation {
|
|||
return output.slice(0, output.length-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an array of IP address octets from a numerical value.
|
||||
* @param {string} value The value of the IP address
|
||||
* @param {number} radix The numeral system to be used
|
||||
* @returns {number[]}
|
||||
*/
|
||||
fromNumber(value, radix) {
|
||||
const decimal = parseInt(value, radix);
|
||||
const baIp = [];
|
||||
baIp.push(decimal >> 24 & 255);
|
||||
baIp.push(decimal >> 16 & 255);
|
||||
baIp.push(decimal >> 8 & 255);
|
||||
baIp.push(decimal & 255);
|
||||
return baIp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChangeIPFormat;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Chi Square operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
|
||||
/**
|
||||
|
@ -23,17 +23,18 @@ class CitrixCTX1Decode extends Operation {
|
|||
this.module = "Encodings";
|
||||
this.description = "Decodes strings in a Citrix CTX1 password format to plaintext.";
|
||||
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = new Uint8Array(input);
|
||||
if (input.length % 4 !== 0) {
|
||||
throw new OperationError("Incorrect hash length");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Comment operation
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
import ctphjs from "ctph.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Compare CTPH hashes operation
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
import ssdeepjs from "ssdeep.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Compare SSDEEP hashes operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Dish from "../Dish";
|
||||
import { getLabelIndex } from "../lib/FlowControl";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Dish from "../Dish.mjs";
|
||||
import { getLabelIndex } from "../lib/FlowControl.mjs";
|
||||
|
||||
/**
|
||||
* Conditional Jump operation
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
|
@ -25,8 +26,8 @@ class ContainImage extends Operation {
|
|||
this.module = "Image";
|
||||
this.description = "Scales an image to the specified width and height, maintaining the aspect ratio. The image may be letterboxed.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
|
@ -72,17 +73,22 @@ class ContainImage extends Operation {
|
|||
"Bezier"
|
||||
],
|
||||
defaultIndex: 1
|
||||
},
|
||||
{
|
||||
name: "Opaque background",
|
||||
type: "boolean",
|
||||
value: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [width, height, hAlign, vAlign, alg] = args;
|
||||
const [width, height, hAlign, vAlign, alg, opaqueBg] = args;
|
||||
|
||||
const resizeMap = {
|
||||
"Nearest Neighbour": jimp.RESIZE_NEAREST_NEIGHBOR,
|
||||
|
@ -107,16 +113,28 @@ class ContainImage extends Operation {
|
|||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(Buffer.from(input));
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Containing image...");
|
||||
image.contain(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
|
||||
if (opaqueBg) {
|
||||
const newImage = await jimp.read(width, height, 0x000000FF);
|
||||
newImage.blit(image, 0, 0);
|
||||
image = newImage;
|
||||
}
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error containing image. (${err})`);
|
||||
}
|
||||
|
@ -124,18 +142,19 @@ class ContainImage extends Operation {
|
|||
|
||||
/**
|
||||
* Displays the contained image using HTML for web apps
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.length) return "";
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(data);
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert area operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
|
||||
import Operation from "../Operation.mjs";
|
||||
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates.mjs";
|
||||
|
||||
/**
|
||||
* Convert co-ordinate format operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert data units operation
|
||||
|
@ -54,7 +54,7 @@ class ConvertDataUnits extends Operation {
|
|||
const DATA_UNITS = [
|
||||
"Bits (b)", "Nibbles", "Octets", "Bytes (B)",
|
||||
"[Binary bits (2^n)]", "Kibibits (Kib)", "Mebibits (Mib)", "Gibibits (Gib)", "Tebibits (Tib)", "Pebibits (Pib)", "Exbibits (Eib)", "Zebibits (Zib)", "Yobibits (Yib)", "[/Binary bits (2^n)]",
|
||||
"[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]",
|
||||
"[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (Kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]",
|
||||
"[Binary bytes (8 x 2^n)]", "Kibibytes (KiB)", "Mebibytes (MiB)", "Gibibytes (GiB)", "Tebibytes (TiB)", "Pebibytes (PiB)", "Exbibytes (EiB)", "Zebibytes (ZiB)", "Yobibytes (YiB)", "[/Binary bytes (8 x 2^n)]",
|
||||
"[Decimal bytes (8 x 10^n)]", "Kilobytes (KB)", "Megabytes (MB)", "Gigabytes (GB)", "Terabytes (TB)", "Petabytes (PB)", "Exabytes (EB)", "Zettabytes (ZB)", "Yottabytes (YB)", "[/Decimal bytes (8 x 10^n)]"
|
||||
];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert distance operation
|
||||
|
|
143
src/core/operations/ConvertImageFormat.mjs
Normal file
143
src/core/operations/ConvertImageFormat.mjs
Normal file
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* @author j433866 [j433866@gmail.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
* Convert Image Format operation
|
||||
*/
|
||||
class ConvertImageFormat extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertImageFormat constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert Image Format";
|
||||
this.module = "Image";
|
||||
this.description = "Converts an image between different formats. Supported formats:<br><ul><li>Joint Photographic Experts Group (JPEG)</li><li>Portable Network Graphics (PNG)</li><li>Bitmap (BMP)</li><li>Tagged Image File Format (TIFF)</li></ul><br>Note: GIF files are supported for input, but cannot be outputted.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Image_file_formats";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
name: "Output Format",
|
||||
type: "option",
|
||||
value: [
|
||||
"JPEG",
|
||||
"PNG",
|
||||
"BMP",
|
||||
"TIFF"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "JPEG Quality",
|
||||
type: "number",
|
||||
value: 80,
|
||||
min: 1,
|
||||
max: 100
|
||||
},
|
||||
{
|
||||
name: "PNG Filter Type",
|
||||
type: "option",
|
||||
value: [
|
||||
"Auto",
|
||||
"None",
|
||||
"Sub",
|
||||
"Up",
|
||||
"Average",
|
||||
"Paeth"
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "PNG Deflate Level",
|
||||
type: "number",
|
||||
value: 9,
|
||||
min: 0,
|
||||
max: 9
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const [format, jpegQuality, pngFilterType, pngDeflateLevel] = args;
|
||||
const formatMap = {
|
||||
"JPEG": jimp.MIME_JPEG,
|
||||
"PNG": jimp.MIME_PNG,
|
||||
"BMP": jimp.MIME_BMP,
|
||||
"TIFF": jimp.MIME_TIFF
|
||||
};
|
||||
|
||||
const pngFilterMap = {
|
||||
"Auto": jimp.PNG_FILTER_AUTO,
|
||||
"None": jimp.PNG_FILTER_NONE,
|
||||
"Sub": jimp.PNG_FILTER_SUB,
|
||||
"Up": jimp.PNG_FILTER_UP,
|
||||
"Average": jimp.PNG_FILTER_AVERAGE,
|
||||
"Paeth": jimp.PNG_FILTER_PATH // Incorrect spelling in Jimp library
|
||||
};
|
||||
|
||||
const mime = formatMap[format];
|
||||
|
||||
if (!isImage(input)) {
|
||||
throw new OperationError("Invalid file format.");
|
||||
}
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error opening image file. (${err})`);
|
||||
}
|
||||
try {
|
||||
switch (format) {
|
||||
case "JPEG":
|
||||
image.quality(jpegQuality);
|
||||
break;
|
||||
case "PNG":
|
||||
image.filterType(pngFilterMap[pngFilterType]);
|
||||
image.deflateLevel(pngDeflateLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(mime);
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error converting image format. (${err})`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the converted image using HTML for web apps
|
||||
*
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ConvertImageFormat;
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert mass operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Convert speed operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Count occurrences operation
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
|
@ -25,8 +26,8 @@ class CoverImage extends Operation {
|
|||
this.module = "Image";
|
||||
this.description = "Scales the image to the given width and height, keeping the aspect ratio. The image may be clipped.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
|
@ -77,7 +78,7 @@ class CoverImage extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
|
@ -107,16 +108,21 @@ class CoverImage extends Operation {
|
|||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(Buffer.from(input));
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Covering image...");
|
||||
image.cover(width, height, alignMap[hAlign] | alignMap[vAlign], resizeMap[alg]);
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error covering image. (${err})`);
|
||||
}
|
||||
|
@ -124,18 +130,19 @@ class CoverImage extends Operation {
|
|||
|
||||
/**
|
||||
* Displays the covered image using HTML for web apps
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.length) return "";
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(data);
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
|
@ -25,8 +26,8 @@ class CropImage extends Operation {
|
|||
this.module = "Image";
|
||||
this.description = "Crops an image to the specified region, or automatically crops edges.<br><br><b><u>Autocrop</u></b><br>Automatically crops same-colour borders from the image.<br><br><u>Autocrop tolerance</u><br>A percentage value for the tolerance of colour difference between pixels.<br><br><u>Only autocrop frames</u><br>Only crop real frames (all sides must have the same border)<br><br><u>Symmetric autocrop</u><br>Force autocrop to be symmetric (top/bottom and left/right are cropped by the same amount)<br><br><u>Autocrop keep border</u><br>The number of pixels of border to leave around the image.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Cropping_(image)";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ class CropImage extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
|
@ -98,12 +99,12 @@ class CropImage extends Operation {
|
|||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(Buffer.from(input));
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Cropping image...");
|
||||
if (autocrop) {
|
||||
image.autocrop({
|
||||
|
@ -116,8 +117,13 @@ class CropImage extends Operation {
|
|||
image.crop(xPos, yPos, width, height);
|
||||
}
|
||||
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error cropping image. (${err})`);
|
||||
}
|
||||
|
@ -125,18 +131,19 @@ class CropImage extends Operation {
|
|||
|
||||
/**
|
||||
* Displays the cropped image using HTML for web apps
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.length) return "";
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(data);
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
|
||||
/**
|
||||
|
@ -73,6 +73,12 @@ class DESDecrypt extends Operation {
|
|||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
||||
DES uses an IV length of 8 bytes (64 bits).
|
||||
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
|
||||
/**
|
||||
|
@ -73,6 +73,12 @@ class DESEncrypt extends Operation {
|
|||
DES uses a key length of 8 bytes (64 bits).
|
||||
Triple DES uses a key length of 24 bytes (192 bits).`);
|
||||
}
|
||||
if (iv.length !== 8 && mode !== "ECB") {
|
||||
throw new OperationError(`Invalid IV length: ${iv.length} bytes
|
||||
|
||||
DES uses an IV length of 8 bytes (64 bits).
|
||||
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* DNS over HTTPS operation
|
||||
|
@ -111,7 +111,7 @@ class DNSOverHTTPS extends Operation {
|
|||
* @returns {JSON}
|
||||
*/
|
||||
function extractData(data) {
|
||||
if (typeof(data) == "undefined"){
|
||||
if (typeof(data) == "undefined") {
|
||||
return [];
|
||||
} else {
|
||||
const dataValues = [];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Dechunk HTTP response operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Decode NetBIOS Name operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
|
||||
|
||||
/**
|
||||
* Decode text operation
|
||||
|
@ -30,7 +30,7 @@ class DecodeText extends Operation {
|
|||
"</ul>",
|
||||
].join("\n");
|
||||
this.infoURL = "https://wikipedia.org/wiki/Character_encoding";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
|
@ -42,13 +42,13 @@ class DecodeText extends Operation {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const format = IO_FORMAT[args[0]];
|
||||
return cptable.utils.decode(format, input);
|
||||
return cptable.utils.decode(format, new Uint8Array(input));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
61
src/core/operations/DefangIPAddresses.mjs
Normal file
61
src/core/operations/DefangIPAddresses.mjs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @author h345983745
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
|
||||
/**
|
||||
* Defang IP Addresses operation
|
||||
*/
|
||||
class DefangIPAddresses extends Operation {
|
||||
|
||||
/**
|
||||
* DefangIPAddresses constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Defang IP Addresses";
|
||||
this.module = "Default";
|
||||
this.description = "Takes a IPv4 or IPv6 address and 'Defangs' it, meaning the IP becomes invalid, removing the risk of accidentally utilising it as an IP address.";
|
||||
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = input.replace(IPV4_REGEX, x => {
|
||||
return x.replace(/\./g, "[.]");
|
||||
});
|
||||
|
||||
input = input.replace(IPV6_REGEX, x => {
|
||||
return x.replace(/:/g, "[:]");
|
||||
});
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
export default DefangIPAddresses;
|
||||
|
||||
|
||||
/**
|
||||
* IPV4 regular expression
|
||||
*/
|
||||
const IPV4_REGEX = new RegExp("(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?", "g");
|
||||
|
||||
|
||||
/**
|
||||
* IPV6 regular expression
|
||||
*/
|
||||
const IPV6_REGEX = new RegExp("((?=.*::)(?!.*::.+::)(::)?([\\dA-Fa-f]{1,4}:(:|\\b)|){5}|([\\dA-Fa-f]{1,4}:){6})((([\\dA-Fa-f]{1,4}((?!\\3)::|:\\b|(?![\\dA-Fa-f])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})", "g");
|
|
@ -5,8 +5,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {URL_REGEX, DOMAIN_REGEX} from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import {URL_REGEX, DOMAIN_REGEX} from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* DefangURL operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {detectFileType} from "../lib/FileType";
|
||||
import {FILE_SIGNATURES} from "../lib/FileSignatures";
|
||||
import Operation from "../Operation.mjs";
|
||||
import {detectFileType} from "../lib/FileType.mjs";
|
||||
import {FILE_SIGNATURES} from "../lib/FileSignatures.mjs";
|
||||
|
||||
// Concat all supported extensions into a single flat list
|
||||
const exts = [].concat.apply([], Object.keys(FILE_SIGNATURES).map(cat =>
|
||||
[].concat.apply([], FILE_SIGNATURES[cat].map(sig =>
|
||||
sig.extension.split(",")
|
||||
))
|
||||
)).unique().sort().join(", ");
|
||||
|
||||
/**
|
||||
* Detect File Type operation
|
||||
|
@ -21,7 +28,8 @@ class DetectFileType extends Operation {
|
|||
|
||||
this.name = "Detect File Type";
|
||||
this.module = "Default";
|
||||
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: 7z, amr, avi, bmp, bz2, class, cr2, crx, dex, dmg, doc, elf, eot, epub, exe, flac, flv, gif, gz, ico, iso, jpg, jxr, m4a, m4v, mid, mkv, mov, mp3, mp4, mpg, ogg, otf, pdf, png, ppt, ps, psd, rar, rtf, sqlite, swf, tar, tar.z, tif, ttf, utf8, vmdk, wav, webm, webp, wmv, woff, woff2, xls, xz, zip.";
|
||||
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: " +
|
||||
exts + ".";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_file_signatures";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
|
@ -52,18 +60,19 @@ class DetectFileType extends Operation {
|
|||
if (!types.length) {
|
||||
return "Unknown file type. Have you tried checking the entropy of this data to determine whether it might be encrypted or compressed?";
|
||||
} else {
|
||||
let output = "";
|
||||
|
||||
types.forEach(type => {
|
||||
output += "File extension: " + type.extension + "\n" +
|
||||
"MIME type: " + type.mime + "\n";
|
||||
const results = types.map(type => {
|
||||
let output = `File type: ${type.name}
|
||||
Extension: ${type.extension}
|
||||
MIME type: ${type.mime}\n`;
|
||||
|
||||
if (type.description && type.description.length) {
|
||||
output += "\nDescription: " + type.description + "\n";
|
||||
output += `Description: ${type.description}\n`;
|
||||
}
|
||||
|
||||
return output;
|
||||
});
|
||||
|
||||
return output;
|
||||
return results.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import * as JsDiff from "diff";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Diff operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import * as disassemble from "../vendor/DisassembleX86-64";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import * as disassemble from "../vendor/DisassembleX86-64.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Disassemble x86 operation
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { isImage } from "../lib/FileType";
|
||||
import { toBase64 } from "../lib/Base64";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
|
@ -25,14 +26,14 @@ class DitherImage extends Operation {
|
|||
this.module = "Image";
|
||||
this.description = "Apply a dither effect to an image.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Dither";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
|
@ -43,16 +44,22 @@ class DitherImage extends Operation {
|
|||
|
||||
let image;
|
||||
try {
|
||||
image = await jimp.read(Buffer.from(input));
|
||||
image = await jimp.read(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error loading image. (${err})`);
|
||||
}
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Applying dither to image...");
|
||||
image.dither565();
|
||||
const imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
return [...imageBuffer];
|
||||
|
||||
let imageBuffer;
|
||||
if (image.getMIME() === "image/gif") {
|
||||
imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||
} else {
|
||||
imageBuffer = await image.getBufferAsync(jimp.AUTO);
|
||||
}
|
||||
return imageBuffer.buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error applying dither to image. (${err})`);
|
||||
}
|
||||
|
@ -60,18 +67,19 @@ class DitherImage extends Operation {
|
|||
|
||||
/**
|
||||
* Displays the dithered image using HTML for web apps
|
||||
* @param {byteArray} data
|
||||
* @param {ArrayBuffer} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data) {
|
||||
if (!data.length) return "";
|
||||
if (!data.byteLength) return "";
|
||||
const dataArray = new Uint8Array(data);
|
||||
|
||||
const type = isImage(data);
|
||||
const type = isImage(dataArray);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
return `<img src="data:${type};base64,${toBase64(data)}">`;
|
||||
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
|
||||
import BigNumber from "bignumber.js";
|
||||
import Operation from "../Operation";
|
||||
import { div, createNumArray } from "../lib/Arithmetic";
|
||||
import { ARITHMETIC_DELIM_OPTIONS } from "../lib/Delim";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { div, createNumArray } from "../lib/Arithmetic.mjs";
|
||||
import { ARITHMETIC_DELIM_OPTIONS } from "../lib/Delim.mjs";
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Drop bytes operation
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Encode NetBIOS Name operation
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc.mjs";
|
||||
|
||||
/**
|
||||
* Encode text operation
|
||||
|
@ -31,7 +31,7 @@ class EncodeText extends Operation {
|
|||
].join("\n");
|
||||
this.infoURL = "https://wikipedia.org/wiki/Character_encoding";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Encoding",
|
||||
|
@ -44,13 +44,12 @@ class EncodeText extends Operation {
|
|||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
const format = IO_FORMAT[args[0]];
|
||||
let encoded = cptable.utils.encode(format, input);
|
||||
encoded = Array.from(encoded);
|
||||
return encoded;
|
||||
const encoded = cptable.utils.encode(format, input);
|
||||
return new Uint8Array(encoded).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import {ROTORS, LETTERS, ROTORS_FOURTH, REFLECTORS, Rotor, Reflector, Plugboard, EnigmaMachine} from "../lib/Enigma";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import {ROTORS, LETTERS, ROTORS_FOURTH, REFLECTORS, Rotor, Reflector, Plugboard, EnigmaMachine} from "../lib/Enigma.mjs";
|
||||
|
||||
/**
|
||||
* Enigma operation
|
||||
|
|
|
@ -4,8 +4,13 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import * as d3temp from "d3";
|
||||
import * as nodomtemp from "nodom";
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
const d3 = d3temp.default ? d3temp.default : d3temp;
|
||||
const nodom = nodomtemp.default ? nodomtemp.default: nodomtemp;
|
||||
|
||||
/**
|
||||
* Entropy operation
|
||||
|
@ -19,30 +24,45 @@ class Entropy extends Operation {
|
|||
super();
|
||||
|
||||
this.name = "Entropy";
|
||||
this.module = "Default";
|
||||
this.module = "Charts";
|
||||
this.description = "Shannon Entropy, in the context of information theory, is a measure of the rate at which information is produced by a source of data. It can be used, in a broad sense, to detect whether data is likely to be structured or unstructured. 8 is the maximum, representing highly unstructured, 'random' data. English language text usually falls somewhere between 3.5 and 5. Properly encrypted or compressed data should have an entropy of over 7.5.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Entropy_(information_theory)";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "number";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
this.args = [
|
||||
{
|
||||
"name": "Visualisation",
|
||||
"type": "option",
|
||||
"value": ["Shannon scale", "Histogram (Bar)", "Histogram (Line)", "Curve", "Image"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {Uint8Array} input
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
calculateShannonEntropy(input) {
|
||||
const prob = [],
|
||||
uniques = input.unique(),
|
||||
str = Utils.byteArrayToChars(input);
|
||||
let i;
|
||||
occurrences = new Array(256).fill(0);
|
||||
|
||||
for (i = 0; i < uniques.length; i++) {
|
||||
prob.push(str.count(Utils.chr(uniques[i])) / input.length);
|
||||
// Count occurrences of each byte in the input
|
||||
let i;
|
||||
for (i = 0; i < input.length; i++) {
|
||||
occurrences[input[i]]++;
|
||||
}
|
||||
|
||||
// Store probability list
|
||||
for (i = 0; i < occurrences.length; i++) {
|
||||
if (occurrences[i] > 0) {
|
||||
prob.push(occurrences[i] / input.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Shannon entropy
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
|
@ -54,44 +74,357 @@ class Entropy extends Operation {
|
|||
return -entropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the scanning entropy of the input
|
||||
*
|
||||
* @param {Uint8Array} inputBytes
|
||||
* @returns {Object}
|
||||
*/
|
||||
calculateScanningEntropy(inputBytes) {
|
||||
const entropyData = [];
|
||||
const binWidth = inputBytes.length < 256 ? 8 : 256;
|
||||
|
||||
for (let bytePos = 0; bytePos < inputBytes.length; bytePos += binWidth) {
|
||||
const block = inputBytes.slice(bytePos, bytePos+binWidth);
|
||||
entropyData.push(this.calculateShannonEntropy(block));
|
||||
}
|
||||
|
||||
return { entropyData, binWidth };
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {object} svg
|
||||
* @param {function} xScale
|
||||
* @param {function} yScale
|
||||
* @param {integer} svgHeight
|
||||
* @param {integer} svgWidth
|
||||
* @param {object} margins
|
||||
* @param {string} xTitle
|
||||
* @param {string} yTitle
|
||||
*/
|
||||
createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, title, xTitle, yTitle) {
|
||||
// Axes
|
||||
const yAxis = d3.axisLeft()
|
||||
.scale(yScale);
|
||||
|
||||
const xAxis = d3.axisBottom()
|
||||
.scale(xScale);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(0, ${svgHeight - margins.bottom})`)
|
||||
.call(xAxis);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(${margins.left},0)`)
|
||||
.call(yAxis);
|
||||
|
||||
// Axes labels
|
||||
svg.append("text")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y", 0 - margins.left)
|
||||
.attr("x", 0 - (svgHeight / 2))
|
||||
.attr("dy", "1em")
|
||||
.style("text-anchor", "middle")
|
||||
.text(yTitle);
|
||||
|
||||
svg.append("text")
|
||||
.attr("transform", `translate(${svgWidth / 2}, ${svgHeight - margins.bottom + 40})`)
|
||||
.style("text-anchor", "middle")
|
||||
.text(xTitle);
|
||||
|
||||
// Add title
|
||||
svg.append("text")
|
||||
.attr("transform", `translate(${svgWidth / 2}, ${margins.top - 10})`)
|
||||
.style("text-anchor", "middle")
|
||||
.text(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {Uint8Array} inputBytes
|
||||
* @returns {number[]}
|
||||
*/
|
||||
calculateByteFrequency(inputBytes) {
|
||||
const freq = new Array(256).fill(0);
|
||||
if (inputBytes.length === 0) return freq;
|
||||
|
||||
// Count occurrences of each byte in the input
|
||||
let i;
|
||||
for (i = 0; i < inputBytes.length; i++) {
|
||||
freq[inputBytes[i]]++;
|
||||
}
|
||||
|
||||
for (i = 0; i < freq.length; i++) {
|
||||
freq[i] = freq[i] / inputBytes.length;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the frequency of bytes in the input.
|
||||
*
|
||||
* @param {number[]} byteFrequency
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createByteFrequencyLineHistogram(byteFrequency) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(byteFrequency, d => d)])
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, byteFrequency.length - 1])
|
||||
.range([margins.left, svgWidth - margins.right]);
|
||||
|
||||
const line = d3.line()
|
||||
.x((_, i) => xScale(i))
|
||||
.y(d => yScale(d))
|
||||
.curve(d3.curveMonotoneX);
|
||||
|
||||
svg.append("path")
|
||||
.datum(byteFrequency)
|
||||
.attr("fill", "none")
|
||||
.attr("stroke", "steelblue")
|
||||
.attr("d", line);
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "", "Byte", "Byte Frequency");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte frequency histogram
|
||||
*
|
||||
* @param {number[]} byteFrequency
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createByteFrequencyBarHistogram(byteFrequency) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500,
|
||||
binWidth = 1;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yExtent = d3.extent(byteFrequency, d => d);
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain(yExtent)
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, byteFrequency.length - 1])
|
||||
.range([margins.left - binWidth, svgWidth - margins.right]);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(byteFrequency)
|
||||
.enter().append("rect")
|
||||
.attr("x", (_, i) => xScale(i) + binWidth)
|
||||
.attr("y", dataPoint => yScale(dataPoint))
|
||||
.attr("width", binWidth)
|
||||
.attr("height", dataPoint => yScale(yExtent[0]) - yScale(dataPoint))
|
||||
.attr("fill", "blue");
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "", "Byte", "Byte Frequency");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte frequency histogram
|
||||
*
|
||||
* @param {number[]} entropyData
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createEntropyCurve(entropyData) {
|
||||
const margins = { top: 30, right: 20, bottom: 50, left: 30 };
|
||||
|
||||
const svgWidth = 500,
|
||||
svgHeight = 500;
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(entropyData, d => d)])
|
||||
.range([svgHeight - margins.bottom, margins.top]);
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, entropyData.length])
|
||||
.range([margins.left, svgWidth - margins.right]);
|
||||
|
||||
const line = d3.line()
|
||||
.x((_, i) => xScale(i))
|
||||
.y(d => yScale(d))
|
||||
.curve(d3.curveMonotoneX);
|
||||
|
||||
if (entropyData.length > 0) {
|
||||
svg.append("path")
|
||||
.datum(entropyData)
|
||||
.attr("d", line);
|
||||
|
||||
svg.selectAll("path").attr("fill", "none").attr("stroke", "steelblue");
|
||||
}
|
||||
|
||||
this.createAxes(svg, xScale, yScale, svgHeight, svgWidth, margins, "Scanning Entropy", "Block", "Entropy");
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an image representation of the entropy
|
||||
*
|
||||
* @param {number[]} entropyData
|
||||
* @returns {HTML}
|
||||
*/
|
||||
createEntropyImage(entropyData) {
|
||||
const svgHeight = 100,
|
||||
svgWidth = 100,
|
||||
cellSize = 1,
|
||||
nodes = [];
|
||||
|
||||
for (let i = 0; i < entropyData.length; i++) {
|
||||
nodes.push({
|
||||
x: i % svgWidth,
|
||||
y: Math.floor(i / svgWidth),
|
||||
entropy: entropyData[i]
|
||||
});
|
||||
}
|
||||
|
||||
const document = new nodom.Document();
|
||||
let svg = document.createElement("svg");
|
||||
svg = d3.select(svg)
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("viewBox", `0 0 ${svgWidth} ${svgHeight}`);
|
||||
|
||||
const greyScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(entropyData, d => d)])
|
||||
.range(["#000000", "#FFFFFF"])
|
||||
.interpolate(d3.interpolateRgb);
|
||||
|
||||
svg
|
||||
.selectAll("rect")
|
||||
.data(nodes)
|
||||
.enter().append("rect")
|
||||
.attr("x", d => d.x * cellSize)
|
||||
.attr("y", d => d.y * cellSize)
|
||||
.attr("width", cellSize)
|
||||
.attr("height", cellSize)
|
||||
.style("fill", d => greyScale(d.entropy));
|
||||
|
||||
return svg._groups[0][0].outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy as a scale bar for web apps.
|
||||
*
|
||||
* @param {number} entropy
|
||||
* @returns {html}
|
||||
* @returns {HTML}
|
||||
*/
|
||||
present(entropy) {
|
||||
createShannonEntropyVisualization(entropy) {
|
||||
return `Shannon entropy: ${entropy}
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
|
||||
<br><script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
entropy = ${entropy},
|
||||
height = parentRect.height * 0.25;
|
||||
<br><script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
entropy = ${entropy},
|
||||
height = parentRect.height * 0.25;
|
||||
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = height > 150 ? 150 : height;
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = height > 150 ? 150 : height;
|
||||
|
||||
CanvasComponents.drawScaleBar(canvas, entropy, 8, [
|
||||
{
|
||||
label: "English text",
|
||||
min: 3.5,
|
||||
max: 5
|
||||
},{
|
||||
label: "Encrypted/compressed",
|
||||
min: 7.5,
|
||||
max: 8
|
||||
}
|
||||
]);
|
||||
</script>`;
|
||||
CanvasComponents.drawScaleBar(canvas, entropy, 8, [
|
||||
{
|
||||
label: "English text",
|
||||
min: 3.5,
|
||||
max: 5
|
||||
},{
|
||||
label: "Encrypted/compressed",
|
||||
min: 7.5,
|
||||
max: 8
|
||||
}
|
||||
]);
|
||||
</script>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {json}
|
||||
*/
|
||||
run(input, args) {
|
||||
const visualizationType = args[0];
|
||||
input = new Uint8Array(input);
|
||||
|
||||
switch (visualizationType) {
|
||||
case "Histogram (Bar)":
|
||||
case "Histogram (Line)":
|
||||
return this.calculateByteFrequency(input);
|
||||
case "Curve":
|
||||
case "Image":
|
||||
return this.calculateScanningEntropy(input).entropyData;
|
||||
case "Shannon scale":
|
||||
default:
|
||||
return this.calculateShannonEntropy(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy in a visualisation for web apps.
|
||||
*
|
||||
* @param {json} entropyData
|
||||
* @param {Object[]} args
|
||||
* @returns {html}
|
||||
*/
|
||||
present(entropyData, args) {
|
||||
const visualizationType = args[0];
|
||||
|
||||
switch (visualizationType) {
|
||||
case "Histogram (Bar)":
|
||||
return this.createByteFrequencyBarHistogram(entropyData);
|
||||
case "Histogram (Line)":
|
||||
return this.createByteFrequencyLineHistogram(entropyData);
|
||||
case "Curve":
|
||||
return this.createEntropyCurve(entropyData);
|
||||
case "Image":
|
||||
return this.createEntropyImage(entropyData);
|
||||
case "Shannon scale":
|
||||
default:
|
||||
return this.createShannonEntropyVisualization(entropyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Entropy;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
import jsesc from "jsesc";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Escape Unicode Characters operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Expand alphabet range operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract dates operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search, DOMAIN_REGEX } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract domains operation
|
||||
|
@ -20,7 +20,7 @@ class ExtractDomains extends Operation {
|
|||
|
||||
this.name = "Extract domains";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts domain names.<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.";
|
||||
this.description = "Extracts fully qualified domain names.<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import ExifParser from "exif-parser";
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Extract EXIF operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract email addresses operation
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract file paths operation
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import {scanForFileTypes, extractFile} from "../lib/FileType";
|
||||
import {FILE_SIGNATURES} from "../lib/FileSignatures";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {scanForFileTypes, extractFile} from "../lib/FileType.mjs";
|
||||
import {FILE_SIGNATURES} from "../lib/FileSignatures.mjs";
|
||||
|
||||
/**
|
||||
* Extract Files operation
|
||||
|
@ -23,7 +23,7 @@ class ExtractFiles extends Operation {
|
|||
|
||||
this.name = "Extract Files";
|
||||
this.module = "Default";
|
||||
this.description = "TODO";
|
||||
this.description = "Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:<ul><li>JPG</li><li>EXE</li><li>ZIP</li><li>PDF</li><li>PNG</li><li>BMP</li><li>FLV</li><li>RTF</li><li>DOCX, PPTX, XLSX</li><li>EPUB</li><li>GZIP</li><li>ZLIB</li><li>ELF, BIN, AXF, O, PRX, SO</li></ul>";
|
||||
this.infoURL = "https://forensicswiki.org/wiki/File_Carving";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "List<File>";
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract IP addresses operation
|
||||
|
|
114
src/core/operations/ExtractLSB.mjs
Normal file
114
src/core/operations/ExtractLSB.mjs
Normal file
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import { fromBinary } from "../lib/Binary.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
* Extract LSB operation
|
||||
*/
|
||||
class ExtractLSB extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractLSB constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract LSB";
|
||||
this.module = "Image";
|
||||
this.description = "Extracts the Least Significant Bit data from each pixel in an image. This is a common way to hide data in Steganography.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Bit_numbering#Least_significant_bit_in_digital_steganography";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
name: "Colour Pattern #1",
|
||||
type: "option",
|
||||
value: COLOUR_OPTIONS,
|
||||
},
|
||||
{
|
||||
name: "Colour Pattern #2",
|
||||
type: "option",
|
||||
value: ["", ...COLOUR_OPTIONS],
|
||||
},
|
||||
{
|
||||
name: "Colour Pattern #3",
|
||||
type: "option",
|
||||
value: ["", ...COLOUR_OPTIONS],
|
||||
},
|
||||
{
|
||||
name: "Colour Pattern #4",
|
||||
type: "option",
|
||||
value: ["", ...COLOUR_OPTIONS],
|
||||
},
|
||||
{
|
||||
name: "Pixel Order",
|
||||
type: "option",
|
||||
value: ["Row", "Column"],
|
||||
},
|
||||
{
|
||||
name: "Bit",
|
||||
type: "number",
|
||||
value: 0
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
async run(input, args) {
|
||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||
|
||||
const bit = 7 - args.pop(),
|
||||
pixelOrder = args.pop(),
|
||||
colours = args.filter(option => option !== "").map(option => COLOUR_OPTIONS.indexOf(option)),
|
||||
parsedImage = await jimp.read(input),
|
||||
width = parsedImage.bitmap.width,
|
||||
height = parsedImage.bitmap.height,
|
||||
rgba = parsedImage.bitmap.data;
|
||||
|
||||
if (bit < 0 || bit > 7) {
|
||||
throw new OperationError("Error: Bit argument must be between 0 and 7");
|
||||
}
|
||||
|
||||
let i, combinedBinary = "";
|
||||
|
||||
if (pixelOrder === "Row") {
|
||||
for (i = 0; i < rgba.length; i += 4) {
|
||||
for (const colour of colours) {
|
||||
combinedBinary += Utils.bin(rgba[i + colour])[bit];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let rowWidth;
|
||||
const pixelWidth = width * 4;
|
||||
for (let col = 0; col < width; col++) {
|
||||
for (let row = 0; row < height; row++) {
|
||||
rowWidth = row * pixelWidth;
|
||||
for (const colour of colours) {
|
||||
i = rowWidth + (col + colour * 4);
|
||||
combinedBinary += Utils.bin(rgba[i])[bit];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fromBinary(combinedBinary);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const COLOUR_OPTIONS = ["R", "G", "B", "A"];
|
||||
|
||||
export default ExtractLSB;
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract MAC addresses operation
|
||||
|
|
65
src/core/operations/ExtractRGBA.mjs
Normal file
65
src/core/operations/ExtractRGBA.mjs
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @author Ge0rg3 [georgeomnet+cyberchef@gmail.com]
|
||||
* @copyright Crown Copyright 2019
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { isImage } from "../lib/FileType.mjs";
|
||||
import jimp from "jimp";
|
||||
|
||||
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
|
||||
/**
|
||||
* Extract RGBA operation
|
||||
*/
|
||||
class ExtractRGBA extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractRGBA constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract RGBA";
|
||||
this.module = "Image";
|
||||
this.description = "Extracts each pixel's RGBA value in an image. These are sometimes used in Steganography to hide text or data.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/RGBA_color_space";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "editableOption",
|
||||
value: RGBA_DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
name: "Include Alpha",
|
||||
type: "boolean",
|
||||
value: true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
|
||||
|
||||
const delimiter = args[0],
|
||||
includeAlpha = args[1],
|
||||
parsedImage = await jimp.read(input);
|
||||
|
||||
let bitmap = parsedImage.bitmap.data;
|
||||
bitmap = includeAlpha ? bitmap : bitmap.filter((val, idx) => idx % 4 !== 3);
|
||||
|
||||
return bitmap.join(delimiter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractRGBA;
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search, URL_REGEX } from "../lib/Extract";
|
||||
import Operation from "../Operation.mjs";
|
||||
import { search, URL_REGEX } from "../lib/Extract.mjs";
|
||||
|
||||
/**
|
||||
* Extract URLs operation
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Fletcher-16 Checksum operation
|
||||
|
@ -22,19 +22,20 @@ class Fletcher16Checksum extends Operation {
|
|||
this.module = "Crypto";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-16";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xff;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Fletcher-32 Checksum operation
|
||||
|
@ -22,19 +22,20 @@ class Fletcher32Checksum extends Operation {
|
|||
this.module = "Crypto";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-32";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xffff;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Fletcher-64 Checksum operation
|
||||
|
@ -22,19 +22,20 @@ class Fletcher64Checksum extends Operation {
|
|||
this.module = "Crypto";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-64";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xffffffff;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* Fletcher-8 Checksum operation
|
||||
|
@ -22,19 +22,20 @@ class Fletcher8Checksum extends Operation {
|
|||
this.module = "Crypto";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum";
|
||||
this.inputType = "byteArray";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
input = new Uint8Array(input);
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xf;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue