Citrix CTX1 encoding/decoding

This commit is contained in:
Brian Whitney 2018-11-20 11:09:52 -05:00
parent 6b686681d5
commit 215e7a5f5d
4 changed files with 97 additions and 6 deletions

View file

@ -67,6 +67,7 @@
"DES Encrypt", "DES Encrypt",
"DES Decrypt", "DES Decrypt",
"Citrix CTX1 Encode", "Citrix CTX1 Encode",
"Citrix CTX1 Decode",
"Triple DES Encrypt", "Triple DES Encrypt",
"Triple DES Decrypt", "Triple DES Decrypt",
"RC2 Encrypt", "RC2 Encrypt",

View file

@ -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;

View file

@ -1,5 +1,5 @@
/** /**
* @author n1474335 [n1474335@gmail.com] * @author bwhitn [brian.m.whitney@gmail.com]
* @copyright Crown Copyright 2017 * @copyright Crown Copyright 2017
* @license Apache-2.0 * @license Apache-2.0
*/ */
@ -23,26 +23,26 @@ class EncodeCitrixCTX1 extends Operation {
this.description = "Encodes strings to Citrix CTX1 password format."; this.description = "Encodes strings to Citrix CTX1 password format.";
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/"; this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
this.inputType = "string"; this.inputType = "string";
this.outputType = "string"; this.outputType = "byteArray";
this.args = []; this.args = [];
} }
/** /**
* @param {string} input * @param {string} input
* @param {Object[]} args * @param {Object[]} args
* @returns {string} * @returns {byteArray}
*/ */
run(input, args) { run(input, args) {
let utf16pass = Buffer.from(cptable.utils.encode(1200, input)); let utf16pass = Buffer.from(cptable.utils.encode(1200, input));
let result = []; let result = [];
let temp = 0 let temp = 0;
for (let i = 0; i < utf16pass.length; i++) { for (let i = 0; i < utf16pass.length; i++) {
temp = utf16pass[i] ^ 0xa5 ^ temp; temp = utf16pass[i] ^ 0xa5 ^ temp;
result.push(((temp >> 4) & 0xf) + 0x41); result.push(((temp >>> 4) & 0xf) + 0x41);
result.push((temp & 0xf) + 0x41); result.push((temp & 0xf) + 0x41);
} }
return new TextDecoder("utf-8").decode(Buffer.from(result)); return result;
} }
} }

View file

@ -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", name: "Vigenère Encode: no input",
input: "", input: "",