Skip to content

Commit d99ee32

Browse files
committed
2 parents f1d318f + e712af3 commit d99ee32

File tree

4 files changed

+142
-1
lines changed

4 files changed

+142
-1
lines changed

src/core/config/Categories.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
"ROT13 Brute Force",
9292
"ROT47",
9393
"ROT47 Brute Force",
94+
"ROT8000",
9495
"XOR",
9596
"XOR Brute Force",
9697
"Vigenère Encode",
@@ -181,7 +182,8 @@
181182
"Bit shift right",
182183
"Rotate left",
183184
"Rotate right",
184-
"ROT13"
185+
"ROT13",
186+
"ROT8000"
185187
]
186188
},
187189
{

src/core/operations/ROT8000.mjs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* @author Daniel Temkin [http://danieltemkin.com]
3+
* @author Thomas Leplus [https://www.leplus.org]
4+
* @copyright Crown Copyright 2021
5+
* @license Apache-2.0
6+
*/
7+
8+
import Operation from "../Operation.mjs";
9+
10+
/**
11+
* ROT8000 operation.
12+
*/
13+
class ROT8000 extends Operation {
14+
15+
/**
16+
* ROT8000 constructor
17+
*/
18+
constructor() {
19+
super();
20+
this.name = "ROT8000";
21+
this.module = "Default";
22+
this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet.";
23+
this.infoURL = "https://github.com/rottytooth/rot8000";
24+
this.inputType = "string";
25+
this.outputType = "string";
26+
this.args = [];
27+
}
28+
29+
/**
30+
* @param {byteArray} input
31+
* @param {Object[]} args
32+
* @returns {byteArray}
33+
*/
34+
run(input, args) {
35+
// Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js
36+
// these come from the valid-code-point-transitions.json file generated from the c# proj
37+
// this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000
38+
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}');
39+
const bmpSize = 0x10000;
40+
const rotList = {}; // the mapping of char to rotated char
41+
const hiddenBlocks = [];
42+
let startBlock = 0;
43+
for (const key in validCodePoints) {
44+
if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) {
45+
if (validCodePoints[key] === true)
46+
hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 });
47+
else
48+
startBlock = parseInt(key, 10);
49+
}
50+
}
51+
const validIntList = []; // list of all valid chars
52+
let currValid = false;
53+
for (let i = 0; i < bmpSize; i++) {
54+
if (validCodePoints[i] !== undefined) {
55+
currValid = validCodePoints[i];
56+
}
57+
if (currValid) validIntList.push(i);
58+
}
59+
const rotateNum = Object.keys(validIntList).length / 2;
60+
// go through every valid char and find its match
61+
for (let i = 0; i < validIntList.length; i++) {
62+
rotList[String.fromCharCode(validIntList[i])] =
63+
String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]);
64+
}
65+
let output = "";
66+
for (let count = 0; count < input.length; count++) {
67+
// if it is not in the mappings list, just add it directly (no rotation)
68+
if (rotList[input[count]] === undefined) {
69+
output += input[count];
70+
continue;
71+
}
72+
// otherwise, rotate it and add it to the string
73+
output += rotList[input[count]];
74+
}
75+
return output;
76+
}
77+
78+
/**
79+
* Highlight ROT8000
80+
*
81+
* @param {Object[]} pos
82+
* @param {number} pos[].start
83+
* @param {number} pos[].end
84+
* @param {Object[]} args
85+
* @returns {Object[]} pos
86+
*/
87+
highlight(pos, args) {
88+
return pos;
89+
}
90+
91+
/**
92+
* Highlight ROT8000 in reverse
93+
*
94+
* @param {Object[]} pos
95+
* @param {number} pos[].start
96+
* @param {number} pos[].end
97+
* @param {Object[]} args
98+
* @returns {Object[]} pos
99+
*/
100+
highlightReverse(pos, args) {
101+
return pos;
102+
}
103+
}
104+
105+
export default ROT8000;

tests/browser/ops.js

+1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ module.exports = {
249249
// testOp(browser, "RIPEMD", "test input", "test_output");
250250
// testOp(browser, "ROT13", "test input", "test_output");
251251
// testOp(browser, "ROT47", "test input", "test_output");
252+
// testOp(browser, "ROT8000", "test input", "test_output");
252253
// testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output");
253254
// testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output");
254255
// testOp(browser, "Randomize Colour Palette", "test input", "test_output");

tests/operations/tests/Rotate.mjs

+33
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,37 @@ TestRegister.addTests([
212212
},
213213
],
214214
},
215+
{
216+
name: "ROT8000: nothing",
217+
input: "",
218+
expectedOutput: "",
219+
recipeConfig: [
220+
{
221+
op: "ROT8000",
222+
args: []
223+
},
224+
],
225+
},
226+
{
227+
name: "ROT8000: normal",
228+
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
229+
expectedOutput: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
230+
recipeConfig: [
231+
{
232+
op: "ROT8000",
233+
args: []
234+
},
235+
],
236+
},
237+
{
238+
name: "ROT8000: backward",
239+
input: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
240+
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
241+
recipeConfig: [
242+
{
243+
op: "ROT8000",
244+
args: []
245+
},
246+
],
247+
},
215248
]);

0 commit comments

Comments
 (0)