From 1509b2b96cecbe5202e8d43471d29330b9e7cb90 Mon Sep 17 00:00:00 2001 From: Flavio Diez Date: Wed, 29 Jan 2020 12:46:38 +0100 Subject: [PATCH 1/4] Implemented the Rail Fence Cipher with both encoding and decoding --- src/core/config/Categories.json | 2 + src/core/operations/RailFenceCipherDecode.mjs | 87 ++++++++++++++ src/core/operations/RailFenceCipherEncode.mjs | 73 ++++++++++++ tests/operations/tests/Ciphers.mjs | 110 ++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 src/core/operations/RailFenceCipherDecode.mjs create mode 100644 src/core/operations/RailFenceCipherEncode.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 53ca796d..0d68efe8 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -95,6 +95,8 @@ "Affine Cipher Decode", "A1Z26 Cipher Encode", "A1Z26 Cipher Decode", + "Rail Fence Cipher Encode", + "Rail Fence Cipher Decode", "Atbash Cipher", "Substitute", "Derive PBKDF2 key", diff --git a/src/core/operations/RailFenceCipherDecode.mjs b/src/core/operations/RailFenceCipherDecode.mjs new file mode 100644 index 00000000..5280bb1a --- /dev/null +++ b/src/core/operations/RailFenceCipherDecode.mjs @@ -0,0 +1,87 @@ +/** + * @author Flavio Diez [flaviofdiez+cyberchef@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Rail Fence Cipher Decode operation + */ +class RailFenceCipherDecode extends Operation { + + /** + * RailFenceCipherDecode constructor + */ + constructor() { + super(); + + this.name = "Rail Fence Cipher Decode"; + this.module = "Ciphers"; + this.description = "Decodes Strings that were created using the Rail fence Cipher provided a key and an offset"; + this.infoURL = "https://en.wikipedia.org/wiki/Rail_fence_cipher"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Key", + type: "number", + value: 2 + }, + { + name: "Offset", + type: "number", + value: 0 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [key, offset] = args; + + let cipher = input; + + if (key < 2) { + return "Key has to be bigger than 2"; + } else if (key > cipher.length) { + return "Key should be smaller than the cipher's length"; + } + + if (offset < 0) { + return "Offset has to be a positive integer"; + } + + const cycle = (key - 1) * 2; + + const rest = cipher.length % key; + + if (rest !== 0) { + cipher = cipher + (" ".repeat(key - rest)); + } + + const plaintext = new Array(cipher.length); + + let j = 0; + let x, y; + + for (y = 0; y < key; y++) { + for (x = 0; x < cipher.length; x++) { + if ((y + x + offset) % cycle === 0 || (y - x - offset) % cycle === 0) { + plaintext[x] = cipher[j++]; + } + } + } + + return plaintext.join("").trim(); + } + +} + + +export default RailFenceCipherDecode; diff --git a/src/core/operations/RailFenceCipherEncode.mjs b/src/core/operations/RailFenceCipherEncode.mjs new file mode 100644 index 00000000..5d9d5eb1 --- /dev/null +++ b/src/core/operations/RailFenceCipherEncode.mjs @@ -0,0 +1,73 @@ +/** + * @author Flavio Diez [flaviofdiez+cyberchef@gmail.com] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Rail Fence Cipher Encode operation + */ +class RailFenceCipherEncode extends Operation { + + /** + * RailFenceCipherEncode constructor + */ + constructor() { + super(); + + this.name = "Rail Fence Cipher Encode"; + this.module = "Ciphers"; + this.description = "Encodes Strings using the Rail fence Cipher provided a key and an offset"; + this.infoURL = "https://en.wikipedia.org/wiki/Rail_fence_cipher"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Key", + type: "number", + value: 2 + }, + { + name: "Offset", + type: "number", + value: 0 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [key, offset] = args; + + const plaintext = input; + if (key < 2) { + return "Key has to be bigger than 2"; + } else if (key > plaintext.length) { + return "Key should be smaller than the plain text's length"; + } + + if (offset < 0) { + return "Offset has to be a positive integer"; + } + + const cycle = (key - 1) * 2; + const rows = new Array(key).fill(""); + + for (let pos = 0; pos < plaintext.length; pos++) { + const rowIdx = key - 1 - Math.abs(cycle / 2 - (pos + offset) % cycle); + + rows[rowIdx] += plaintext[pos]; + } + + return rows.join("").trim(); + } + +} + +export default RailFenceCipherEncode; diff --git a/tests/operations/tests/Ciphers.mjs b/tests/operations/tests/Ciphers.mjs index 62cbaa54..47453cf7 100644 --- a/tests/operations/tests/Ciphers.mjs +++ b/tests/operations/tests/Ciphers.mjs @@ -418,4 +418,114 @@ TestRegister.addTests([ } ], }, + { + name: "Rail Fence Cipher Decode: normal", + input: "Cytgah sTEAto rtn rsligcdsrporpyi H r fWiigo ovn oe", + expectedOutput: "Cryptography is THE Art of Writing or solving codes", + recipeConfig: [ + { + "op": "Rail Fence Cipher Decode", + "args": [2, 0] + } + ], + }, + { + name: "Rail Fence Cipher Decode: key has to be bigger than 2", + input: "Cytgah sTEAto rtn rsligcdsrporpyi H r fWiigo ovn oe", + expectedOutput: "Key has to be bigger than 2", + recipeConfig: [ + { + "op": "Rail Fence Cipher Decode", + "args": [1, 0] + } + ], + }, + { + name: "Rail Fence Cipher Decode: key has to be smaller than input's length", + input: "shortinput", + expectedOutput: "Key should be smaller than the cipher's length", + recipeConfig: [ + { + "op": "Rail Fence Cipher Decode", + "args": [22, 0] + } + ], + }, + { + name: "Rail Fence Cipher Decode: offset should be positive", + input: "shortinput", + expectedOutput: "Offset has to be a positive integer", + recipeConfig: [ + { + "op": "Rail Fence Cipher Decode", + "args": [2, -1] + } + ], + }, + { + name: "Rail Fence Cipher Decode: Normal with Offset non-null", + input: "51746026813793592840", + expectedOutput: "12345678901234567890", + recipeConfig: [ + { + "op": "Rail Fence Cipher Decode", + "args": [4, 2] + } + ], + }, + { + name: "Rail Fence Cipher Encode: normal", + input: "Cryptography is THE Art of Writing or solving codes", + expectedOutput: "Cytgah sTEAto rtn rsligcdsrporpyi H r fWiigo ovn oe", + recipeConfig: [ + { + "op": "Rail Fence Cipher Encode", + "args": [2, 0] + } + ], + }, + { + name: "Rail Fence Cipher Encode: key has to be bigger than 2", + input: "Cryptography is THE Art of Writing or solving codes", + expectedOutput: "Key has to be bigger than 2", + recipeConfig: [ + { + "op": "Rail Fence Cipher Encode", + "args": [1, 0] + } + ], + }, + { + name: "Rail Fence Cipher Encode: key has to be smaller than input's length", + input: "shortinput", + expectedOutput: "Key should be smaller than the plain text's length", + recipeConfig: [ + { + "op": "Rail Fence Cipher Encode", + "args": [22, 0] + } + ], + }, + { + name: "Rail Fence Cipher Encode: offset should be positive", + input: "shortinput", + expectedOutput: "Offset has to be a positive integer", + recipeConfig: [ + { + "op": "Rail Fence Cipher Encode", + "args": [2, -1] + } + ], + }, + { + name: "Rail Fence Cipher Encode: Normal with Offset non-null", + input: "12345678901234567890", + expectedOutput: "51746026813793592840", + recipeConfig: [ + { + "op": "Rail Fence Cipher Encode", + "args": [4, 2] + } + ], + }, ]); From 0ab96dd4ca19c61f5d20c56d858908c8f5ecf883 Mon Sep 17 00:00:00 2001 From: Flavio Diez Date: Wed, 29 Jan 2020 14:16:04 +0100 Subject: [PATCH 2/4] Throw OperationError instead of returning a String --- src/core/operations/RailFenceCipherDecode.mjs | 7 ++++--- src/core/operations/RailFenceCipherEncode.mjs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/operations/RailFenceCipherDecode.mjs b/src/core/operations/RailFenceCipherDecode.mjs index 5280bb1a..7317b438 100644 --- a/src/core/operations/RailFenceCipherDecode.mjs +++ b/src/core/operations/RailFenceCipherDecode.mjs @@ -5,6 +5,7 @@ */ import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; /** * Rail Fence Cipher Decode operation @@ -48,13 +49,13 @@ class RailFenceCipherDecode extends Operation { let cipher = input; if (key < 2) { - return "Key has to be bigger than 2"; + throw new OperationError("Key has to be bigger than 2"); } else if (key > cipher.length) { - return "Key should be smaller than the cipher's length"; + throw new OperationError("Key should be smaller than the cipher's length"); } if (offset < 0) { - return "Offset has to be a positive integer"; + throw new OperationError("Offset has to be a positive integer"); } const cycle = (key - 1) * 2; diff --git a/src/core/operations/RailFenceCipherEncode.mjs b/src/core/operations/RailFenceCipherEncode.mjs index 5d9d5eb1..af3a0016 100644 --- a/src/core/operations/RailFenceCipherEncode.mjs +++ b/src/core/operations/RailFenceCipherEncode.mjs @@ -5,6 +5,7 @@ */ import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; /** * Rail Fence Cipher Encode operation @@ -47,13 +48,13 @@ class RailFenceCipherEncode extends Operation { const plaintext = input; if (key < 2) { - return "Key has to be bigger than 2"; + throw new OperationError("Key has to be bigger than 2"); } else if (key > plaintext.length) { - return "Key should be smaller than the plain text's length"; + throw new OperationError("Key should be smaller than the plain text's length"); } if (offset < 0) { - return "Offset has to be a positive integer"; + throw new OperationError("Offset has to be a positive integer"); } const cycle = (key - 1) * 2; From b045dc37f53e9643749bb8234a317bffba6f0fbf Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 13 Feb 2020 15:05:33 +0000 Subject: [PATCH 3/4] Tidied up infoURL in Rail Fence Cipher ops --- src/core/operations/RailFenceCipherDecode.mjs | 2 +- src/core/operations/RailFenceCipherEncode.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/operations/RailFenceCipherDecode.mjs b/src/core/operations/RailFenceCipherDecode.mjs index 7317b438..d98742b8 100644 --- a/src/core/operations/RailFenceCipherDecode.mjs +++ b/src/core/operations/RailFenceCipherDecode.mjs @@ -21,7 +21,7 @@ class RailFenceCipherDecode extends Operation { this.name = "Rail Fence Cipher Decode"; this.module = "Ciphers"; this.description = "Decodes Strings that were created using the Rail fence Cipher provided a key and an offset"; - this.infoURL = "https://en.wikipedia.org/wiki/Rail_fence_cipher"; + this.infoURL = "https://wikipedia.org/wiki/Rail_fence_cipher"; this.inputType = "string"; this.outputType = "string"; this.args = [ diff --git a/src/core/operations/RailFenceCipherEncode.mjs b/src/core/operations/RailFenceCipherEncode.mjs index af3a0016..03651f85 100644 --- a/src/core/operations/RailFenceCipherEncode.mjs +++ b/src/core/operations/RailFenceCipherEncode.mjs @@ -21,7 +21,7 @@ class RailFenceCipherEncode extends Operation { this.name = "Rail Fence Cipher Encode"; this.module = "Ciphers"; this.description = "Encodes Strings using the Rail fence Cipher provided a key and an offset"; - this.infoURL = "https://en.wikipedia.org/wiki/Rail_fence_cipher"; + this.infoURL = "https://wikipedia.org/wiki/Rail_fence_cipher"; this.inputType = "string"; this.outputType = "string"; this.args = [ From 3ecbe22d99ef619a8fd091f3bfc1c7c14591bd14 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 13 Feb 2020 15:08:54 +0000 Subject: [PATCH 4/4] Updated CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c96618..86ba6848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master). +### [9.13.0] - 2020-02-13 +- 'Rail Fence Cipher Encode' and 'Rail Fence Cipher Decode' operations added [@Flavsditz] | [#948] + ### [9.12.0] - 2019-12-20 - 'Normalise Unicode' operation added [@matthieuxyz] | [#912] @@ -200,6 +203,7 @@ All major and minor version changes will be documented in this file. Details of +[9.13.0]: https://github.com/gchq/CyberChef/releases/tag/v9.13.0 [9.12.0]: https://github.com/gchq/CyberChef/releases/tag/v9.12.0 [9.11.0]: https://github.com/gchq/CyberChef/releases/tag/v9.11.0 [9.10.0]: https://github.com/gchq/CyberChef/releases/tag/v9.10.0 @@ -286,6 +290,7 @@ All major and minor version changes will be documented in this file. Details of [@VirtualColossus]: https://github.com/VirtualColossus [@cbeuw]: https://github.com/cbeuw [@matthieuxyz]: https://github.com/matthieuxyz +[@Flavsditz]: https://github.com/Flavsditz [#95]: https://github.com/gchq/CyberChef/pull/299 [#173]: https://github.com/gchq/CyberChef/pull/173 @@ -350,3 +355,4 @@ All major and minor version changes will be documented in this file. Details of [#653]: https://github.com/gchq/CyberChef/pull/653 [#865]: https://github.com/gchq/CyberChef/pull/865 [#912]: https://github.com/gchq/CyberChef/pull/912 +[#948]: https://github.com/gchq/CyberChef/pull/948