diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index ee638893..59c9a17c 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -68,6 +68,8 @@ "Blowfish Decrypt", "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..05407347 --- /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 ""; + } + const revinput = input.reverse(); + const 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 new file mode 100644 index 00000000..26021f16 --- /dev/null +++ b/src/core/operations/EncodeCitrixCTX1.mjs @@ -0,0 +1,50 @@ +/** + * @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 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 = "byteArray"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + 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; + result.push(((temp >>> 4) & 0xf) + 0x41); + result.push((temp & 0xf) + 0x41); + } + + return result; + } + +} + +export default EncodeCitrixCTX1; 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: "",