Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ROT8000 #1250

Merged
merged 1 commit into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/core/config/Categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"SM4 Decrypt",
"ROT13",
"ROT47",
"ROT8000",
"XOR",
"XOR Brute Force",
"Vigenère Encode",
Expand Down Expand Up @@ -176,7 +177,8 @@
"Bit shift right",
"Rotate left",
"Rotate right",
"ROT13"
"ROT13",
"ROT8000"
]
},
{
Expand Down
105 changes: 105 additions & 0 deletions src/core/operations/ROT8000.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* @author Daniel Temkin [http://danieltemkin.com]
* @author Thomas Leplus [https://www.leplus.org]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";

/**
* ROT8000 operation.
*/
class ROT8000 extends Operation {

/**
* ROT8000 constructor
*/
constructor() {
super();
this.name = "ROT8000";
this.module = "Default";
this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet.";
this.infoURL = "https://github.com/rottytooth/rot8000";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}

/**
* @param {byteArray} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
// Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js
// these come from the valid-code-point-transitions.json file generated from the c# proj
// this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000
const validCodePoints = JSON.parse('{"33":true,"127":false,"161":true,"5760":false,"5761":true,"8192":false,"8203":true,"8232":false,"8234":true,"8239":false,"8240":true,"8287":false,"8288":true,"12288":false,"12289":true,"55296":false,"57344":true}');
const bmpSize = 0x10000;
const rotList = {}; // the mapping of char to rotated char
const hiddenBlocks = [];
let startBlock = 0;
for (const key in validCodePoints) {
if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) {
if (validCodePoints[key] === true)
hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 });
else
startBlock = parseInt(key, 10);
}
}
const validIntList = []; // list of all valid chars
let currValid = false;
for (let i = 0; i < bmpSize; i++) {
if (validCodePoints[i] !== undefined) {
currValid = validCodePoints[i];
}
if (currValid) validIntList.push(i);
}
const rotateNum = Object.keys(validIntList).length / 2;
// go through every valid char and find its match
for (let i = 0; i < validIntList.length; i++) {
rotList[String.fromCharCode(validIntList[i])] =
String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]);
}
let output = "";
for (let count = 0; count < input.length; count++) {
// if it is not in the mappings list, just add it directly (no rotation)
if (rotList[input[count]] === undefined) {
output += input[count];
continue;
}
// otherwise, rotate it and add it to the string
output += rotList[input[count]];
}
return output;
}

/**
* Highlight ROT8000
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlight(pos, args) {
return pos;
}

/**
* Highlight ROT8000 in reverse
*
* @param {Object[]} pos
* @param {number} pos[].start
* @param {number} pos[].end
* @param {Object[]} args
* @returns {Object[]} pos
*/
highlightReverse(pos, args) {
return pos;
}
}

export default ROT8000;
1 change: 1 addition & 0 deletions tests/browser/ops.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ module.exports = {
// testOp(browser, "RIPEMD", "test input", "test_output");
// testOp(browser, "ROT13", "test input", "test_output");
// testOp(browser, "ROT47", "test input", "test_output");
// testOp(browser, "ROT8000", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output");
// testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output");
// testOp(browser, "Randomize Colour Palette", "test input", "test_output");
Expand Down
33 changes: 33 additions & 0 deletions tests/operations/tests/Rotate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,37 @@ TestRegister.addTests([
},
],
},
{
name: "ROT8000: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
{
name: "ROT8000: normal",
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
expectedOutput: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
{
name: "ROT8000: backward",
input: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
recipeConfig: [
{
op: "ROT8000",
args: []
},
],
},
]);