From 6b686681d5e7fba0863151ddcd9dcd2302ca64c2 Mon Sep 17 00:00:00 2001 From: bwhitn Date: Mon, 19 Nov 2018 23:48:33 -0500 Subject: [PATCH 1/4] Encoding ctx1 --- src/core/config/Categories.json | 1 + src/core/operations/EncodeCitrixCTX1.mjs | 50 ++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/core/operations/EncodeCitrixCTX1.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 1891c460..f317e9a1 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -66,6 +66,7 @@ "Blowfish Decrypt", "DES Encrypt", "DES Decrypt", + "Citrix CTX1 Encode", "Triple DES Encrypt", "Triple DES Decrypt", "RC2 Encrypt", diff --git a/src/core/operations/EncodeCitrixCTX1.mjs b/src/core/operations/EncodeCitrixCTX1.mjs new file mode 100644 index 00000000..c0a42b18 --- /dev/null +++ b/src/core/operations/EncodeCitrixCTX1.mjs @@ -0,0 +1,50 @@ +/** + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2017 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import cptable from "../vendor/js-codepage/cptable.js"; + +/** + * Encode Citrix CTX1 class + */ +class EncodeCitrixCTX1 extends Operation { + + /** + * EncodeCitrixCTX1 constructor + */ + constructor() { + super(); + + this.name = "Citrix CTX1 Encode"; + this.module = "Ciphers"; + this.description = "Encodes strings to Citrix CTX1 password format."; + this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/"; + this.inputType = "string"; + this.outputType = "string"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + let utf16pass = Buffer.from(cptable.utils.encode(1200, input)); + let result = []; + let temp = 0 + for (let i = 0; i < utf16pass.length; i++) { + temp = utf16pass[i] ^ 0xa5 ^ temp; + result.push(((temp >> 4) & 0xf) + 0x41); + result.push((temp & 0xf) + 0x41); + } + + return new TextDecoder("utf-8").decode(Buffer.from(result)); + } + +} + +export default EncodeCitrixCTX1; From 215e7a5f5db32f416b3c606adfc788315851742c Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Tue, 20 Nov 2018 11:09:52 -0500 Subject: [PATCH 2/4] Citrix CTX1 encoding/decoding --- src/core/config/Categories.json | 1 + src/core/operations/DecodeCitrixCTX1.mjs | 57 ++++++++++++++++++++++++ src/core/operations/EncodeCitrixCTX1.mjs | 12 ++--- test/tests/operations/Ciphers.mjs | 33 ++++++++++++++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/core/operations/DecodeCitrixCTX1.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index f317e9a1..158f3f76 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -67,6 +67,7 @@ "DES Encrypt", "DES Decrypt", "Citrix CTX1 Encode", + "Citrix CTX1 Decode", "Triple DES Encrypt", "Triple DES Decrypt", "RC2 Encrypt", diff --git a/src/core/operations/DecodeCitrixCTX1.mjs b/src/core/operations/DecodeCitrixCTX1.mjs new file mode 100644 index 00000000..af7fa035 --- /dev/null +++ b/src/core/operations/DecodeCitrixCTX1.mjs @@ -0,0 +1,57 @@ +/** + * @author bwhitn [brian.m.whitney@gmail.com] + * @copyright Crown Copyright 2017 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import cptable from "../vendor/js-codepage/cptable.js"; + +/** + * Encode Citrix CTX1 class + */ +class DecodeCitrixCTX1 extends Operation { + + /** + * EncodeCitrixCTX1 constructor + */ + constructor() { + super(); + + this.name = "Citrix CTX1 Decode"; + this.module = "Ciphers"; + 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.outputType = "string"; + this.args = []; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (input.length % 4 != 0) { + return ""; + } + let revinput = input.reverse(); + let result = []; + let temp = 0; + for (let i = 0; i < revinput.length; i+=2) { + if (i+2 >= revinput.length) { + temp = 0; + } else { + temp = ((revinput[i + 2] - 0x41) & 0xf) ^ (((revinput[i + 3]- 0x41) << 4) & 0xf0); + } + temp = (((revinput[i] - 0x41) & 0xf) ^ (((revinput[i + 1] - 0x41) << 4) & 0xf0)) ^ 0xa5 ^ temp; + result.push(temp); + } + // Decodes a utf-16le string + return cptable.utils.decode(1200, result.reverse()); + } + +} + +export default DecodeCitrixCTX1; diff --git a/src/core/operations/EncodeCitrixCTX1.mjs b/src/core/operations/EncodeCitrixCTX1.mjs index c0a42b18..ad90b559 100644 --- a/src/core/operations/EncodeCitrixCTX1.mjs +++ b/src/core/operations/EncodeCitrixCTX1.mjs @@ -1,5 +1,5 @@ /** - * @author n1474335 [n1474335@gmail.com] + * @author bwhitn [brian.m.whitney@gmail.com] * @copyright Crown Copyright 2017 * @license Apache-2.0 */ @@ -23,26 +23,26 @@ class EncodeCitrixCTX1 extends Operation { this.description = "Encodes strings to Citrix CTX1 password format."; this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/"; this.inputType = "string"; - this.outputType = "string"; + this.outputType = "byteArray"; this.args = []; } /** * @param {string} input * @param {Object[]} args - * @returns {string} + * @returns {byteArray} */ run(input, args) { let utf16pass = Buffer.from(cptable.utils.encode(1200, input)); let result = []; - let temp = 0 + let temp = 0; for (let i = 0; i < utf16pass.length; i++) { temp = utf16pass[i] ^ 0xa5 ^ temp; - result.push(((temp >> 4) & 0xf) + 0x41); + result.push(((temp >>> 4) & 0xf) + 0x41); result.push((temp & 0xf) + 0x41); } - return new TextDecoder("utf-8").decode(Buffer.from(result)); + return result; } } diff --git a/test/tests/operations/Ciphers.mjs b/test/tests/operations/Ciphers.mjs index 553216ef..ad69b6a5 100644 --- a/test/tests/operations/Ciphers.mjs +++ b/test/tests/operations/Ciphers.mjs @@ -220,6 +220,39 @@ TestRegister.addTests([ } ], }, + { + name: "Citrix CTX1 Encode", + input: "Password1", + expectedOutput: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO", + recipeConfig: [ + { + "op": "Citrix CTX1 Encode", + "args": [] + } + ], + }, + { + name: "Citrix CTX1 Decode: normal", + input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO", + expectedOutput: "Password1", + recipeConfig: [ + { + "op": "Citrix CTX1 Decode", + "args": [] + } + ], + }, + { + name: "Citrix CTX1 Decode: invalid length", + input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLA", + expectedOutput: "", + recipeConfig: [ + { + "op": "Citrix CTX1 Decode", + "args": [] + } + ], + }, { name: "Vigenère Encode: no input", input: "", From c378bcb00b0c5e79ecd00bd8619532bd680206db Mon Sep 17 00:00:00 2001 From: Brian Whitney Date: Tue, 20 Nov 2018 11:24:50 -0500 Subject: [PATCH 3/4] Fixed lint issues --- src/core/operations/DecodeCitrixCTX1.mjs | 6 +++--- src/core/operations/EncodeCitrixCTX1.mjs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/operations/DecodeCitrixCTX1.mjs b/src/core/operations/DecodeCitrixCTX1.mjs index af7fa035..05407347 100644 --- a/src/core/operations/DecodeCitrixCTX1.mjs +++ b/src/core/operations/DecodeCitrixCTX1.mjs @@ -33,11 +33,11 @@ class DecodeCitrixCTX1 extends Operation { * @returns {string} */ run(input, args) { - if (input.length % 4 != 0) { + if (input.length % 4 !== 0) { return ""; } - let revinput = input.reverse(); - let result = []; + const revinput = input.reverse(); + const result = []; let temp = 0; for (let i = 0; i < revinput.length; i+=2) { if (i+2 >= revinput.length) { diff --git a/src/core/operations/EncodeCitrixCTX1.mjs b/src/core/operations/EncodeCitrixCTX1.mjs index ad90b559..26021f16 100644 --- a/src/core/operations/EncodeCitrixCTX1.mjs +++ b/src/core/operations/EncodeCitrixCTX1.mjs @@ -33,8 +33,8 @@ class EncodeCitrixCTX1 extends Operation { * @returns {byteArray} */ run(input, args) { - let utf16pass = Buffer.from(cptable.utils.encode(1200, input)); - let result = []; + const utf16pass = Buffer.from(cptable.utils.encode(1200, input)); + const result = []; let temp = 0; for (let i = 0; i < utf16pass.length; i++) { temp = utf16pass[i] ^ 0xa5 ^ temp; From 79d7a5dd8706b65f1a3367b6d7ed3c3921b67a74 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 21 Nov 2018 12:28:19 +0000 Subject: [PATCH 4/4] Tidied up Citrix CTX1 operations and updated CHANGELOG --- CHANGELOG.md | 5 +++++ src/core/config/Categories.json | 4 ++-- ...odeCitrixCTX1.mjs => CitrixCTX1Decode.mjs} | 19 ++++++++++--------- ...odeCitrixCTX1.mjs => CitrixCTX1Encode.mjs} | 14 +++++++------- test/tests/operations/Ciphers.mjs | 2 +- 5 files changed, 25 insertions(+), 19 deletions(-) rename src/core/operations/{DecodeCitrixCTX1.mjs => CitrixCTX1Decode.mjs} (74%) rename src/core/operations/{EncodeCitrixCTX1.mjs => CitrixCTX1Encode.mjs} (77%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 875244b9..14cbdcfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All notable changes to CyberChef will be documented in this file. +### [8.12.0] - 2018-11-21 +- 'Citrix CTX1 Encode' and 'Citrix CTX1 Decode' operations added [@bwhitn] | [#428] + ### [8.11.0] - 2018-11-13 - 'CSV to JSON' and 'JSON to CSV' operations added [@n1474335] | [#277] @@ -87,6 +90,7 @@ All notable changes to CyberChef will be documented in this file. [@PenguinGeorge]: https://github.com/PenguinGeorge [@arnydo]: https://github.com/arnydo [@klaxon1]: https://github.com/klaxon1 +[@bwhitn]: https://github.com/bwhitn [#95]: https://github.com/gchq/CyberChef/pull/299 [#173]: https://github.com/gchq/CyberChef/pull/173 @@ -109,3 +113,4 @@ All notable changes to CyberChef will be documented in this file. [#351]: https://github.com/gchq/CyberChef/pull/351 [#387]: https://github.com/gchq/CyberChef/pull/387 [#394]: https://github.com/gchq/CyberChef/pull/394 +[#428]: https://github.com/gchq/CyberChef/pull/428 diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 59c9a17c..4fac84c9 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -68,8 +68,6 @@ "Blowfish Decrypt", "DES Encrypt", "DES Decrypt", - "Citrix CTX1 Encode", - "Citrix CTX1 Decode", "Triple DES Encrypt", "Triple DES Decrypt", "RC2 Encrypt", @@ -97,6 +95,8 @@ "JWT Sign", "JWT Verify", "JWT Decode", + "Citrix CTX1 Encode", + "Citrix CTX1 Decode", "Pseudo-Random Number Generator" ] }, diff --git a/src/core/operations/DecodeCitrixCTX1.mjs b/src/core/operations/CitrixCTX1Decode.mjs similarity index 74% rename from src/core/operations/DecodeCitrixCTX1.mjs rename to src/core/operations/CitrixCTX1Decode.mjs index 05407347..31c20ee9 100644 --- a/src/core/operations/DecodeCitrixCTX1.mjs +++ b/src/core/operations/CitrixCTX1Decode.mjs @@ -1,25 +1,26 @@ /** * @author bwhitn [brian.m.whitney@gmail.com] - * @copyright Crown Copyright 2017 + * @copyright Crown Copyright 2018 * @license Apache-2.0 */ import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; import cptable from "../vendor/js-codepage/cptable.js"; /** - * Encode Citrix CTX1 class + * Citrix CTX1 Decode operation */ -class DecodeCitrixCTX1 extends Operation { +class CitrixCTX1Decode extends Operation { /** - * EncodeCitrixCTX1 constructor + * CitrixCTX1Decode constructor */ constructor() { super(); this.name = "Citrix CTX1 Decode"; - this.module = "Ciphers"; + 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"; @@ -34,13 +35,13 @@ class DecodeCitrixCTX1 extends Operation { */ run(input, args) { if (input.length % 4 !== 0) { - return ""; + throw new OperationError("Incorrect hash length"); } const revinput = input.reverse(); const result = []; let temp = 0; - for (let i = 0; i < revinput.length; i+=2) { - if (i+2 >= revinput.length) { + for (let i = 0; i < revinput.length; i += 2) { + if (i + 2 >= revinput.length) { temp = 0; } else { temp = ((revinput[i + 2] - 0x41) & 0xf) ^ (((revinput[i + 3]- 0x41) << 4) & 0xf0); @@ -54,4 +55,4 @@ class DecodeCitrixCTX1 extends Operation { } -export default DecodeCitrixCTX1; +export default CitrixCTX1Decode; diff --git a/src/core/operations/EncodeCitrixCTX1.mjs b/src/core/operations/CitrixCTX1Encode.mjs similarity index 77% rename from src/core/operations/EncodeCitrixCTX1.mjs rename to src/core/operations/CitrixCTX1Encode.mjs index 26021f16..add563d8 100644 --- a/src/core/operations/EncodeCitrixCTX1.mjs +++ b/src/core/operations/CitrixCTX1Encode.mjs @@ -1,6 +1,6 @@ /** * @author bwhitn [brian.m.whitney@gmail.com] - * @copyright Crown Copyright 2017 + * @copyright Crown Copyright 2018 * @license Apache-2.0 */ @@ -8,18 +8,18 @@ import Operation from "../Operation"; import cptable from "../vendor/js-codepage/cptable.js"; /** - * Encode Citrix CTX1 class + * Citrix CTX1 Encode operation */ -class EncodeCitrixCTX1 extends Operation { +class CitrixCTX1Encode extends Operation { /** - * EncodeCitrixCTX1 constructor + * CitrixCTX1Encode constructor */ constructor() { super(); this.name = "Citrix CTX1 Encode"; - this.module = "Ciphers"; + this.module = "Encodings"; this.description = "Encodes strings to Citrix CTX1 password format."; this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/"; this.inputType = "string"; @@ -33,7 +33,7 @@ class EncodeCitrixCTX1 extends Operation { * @returns {byteArray} */ run(input, args) { - const utf16pass = Buffer.from(cptable.utils.encode(1200, input)); + const utf16pass = Array.from(cptable.utils.encode(1200, input)); const result = []; let temp = 0; for (let i = 0; i < utf16pass.length; i++) { @@ -47,4 +47,4 @@ class EncodeCitrixCTX1 extends Operation { } -export default EncodeCitrixCTX1; +export default CitrixCTX1Encode; diff --git a/test/tests/operations/Ciphers.mjs b/test/tests/operations/Ciphers.mjs index ad69b6a5..fdc98a3a 100644 --- a/test/tests/operations/Ciphers.mjs +++ b/test/tests/operations/Ciphers.mjs @@ -245,7 +245,7 @@ TestRegister.addTests([ { name: "Citrix CTX1 Decode: invalid length", input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLA", - expectedOutput: "", + expectedOutput: "Incorrect hash length", recipeConfig: [ { "op": "Citrix CTX1 Decode",