Skip to content

Commit 215e7a5

Browse files
committed
Citrix CTX1 encoding/decoding
1 parent 6b68668 commit 215e7a5

4 files changed

Lines changed: 97 additions & 6 deletions

File tree

src/core/config/Categories.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"DES Encrypt",
6868
"DES Decrypt",
6969
"Citrix CTX1 Encode",
70+
"Citrix CTX1 Decode",
7071
"Triple DES Encrypt",
7172
"Triple DES Decrypt",
7273
"RC2 Encrypt",
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @author bwhitn [brian.m.whitney@gmail.com]
3+
* @copyright Crown Copyright 2017
4+
* @license Apache-2.0
5+
*/
6+
7+
import Operation from "../Operation";
8+
import cptable from "../vendor/js-codepage/cptable.js";
9+
10+
/**
11+
* Encode Citrix CTX1 class
12+
*/
13+
class DecodeCitrixCTX1 extends Operation {
14+
15+
/**
16+
* EncodeCitrixCTX1 constructor
17+
*/
18+
constructor() {
19+
super();
20+
21+
this.name = "Citrix CTX1 Decode";
22+
this.module = "Ciphers";
23+
this.description = "Decodes strings in a Citrix CTX1 password format to plaintext.";
24+
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
25+
this.inputType = "byteArray";
26+
this.outputType = "string";
27+
this.args = [];
28+
}
29+
30+
/**
31+
* @param {byteArray} input
32+
* @param {Object[]} args
33+
* @returns {string}
34+
*/
35+
run(input, args) {
36+
if (input.length % 4 != 0) {
37+
return "";
38+
}
39+
let revinput = input.reverse();
40+
let result = [];
41+
let temp = 0;
42+
for (let i = 0; i < revinput.length; i+=2) {
43+
if (i+2 >= revinput.length) {
44+
temp = 0;
45+
} else {
46+
temp = ((revinput[i + 2] - 0x41) & 0xf) ^ (((revinput[i + 3]- 0x41) << 4) & 0xf0);
47+
}
48+
temp = (((revinput[i] - 0x41) & 0xf) ^ (((revinput[i + 1] - 0x41) << 4) & 0xf0)) ^ 0xa5 ^ temp;
49+
result.push(temp);
50+
}
51+
// Decodes a utf-16le string
52+
return cptable.utils.decode(1200, result.reverse());
53+
}
54+
55+
}
56+
57+
export default DecodeCitrixCTX1;

src/core/operations/EncodeCitrixCTX1.mjs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* @author n1474335 [n1474335@gmail.com]
2+
* @author bwhitn [brian.m.whitney@gmail.com]
33
* @copyright Crown Copyright 2017
44
* @license Apache-2.0
55
*/
@@ -23,26 +23,26 @@ class EncodeCitrixCTX1 extends Operation {
2323
this.description = "Encodes strings to Citrix CTX1 password format.";
2424
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
2525
this.inputType = "string";
26-
this.outputType = "string";
26+
this.outputType = "byteArray";
2727
this.args = [];
2828
}
2929

3030
/**
3131
* @param {string} input
3232
* @param {Object[]} args
33-
* @returns {string}
33+
* @returns {byteArray}
3434
*/
3535
run(input, args) {
3636
let utf16pass = Buffer.from(cptable.utils.encode(1200, input));
3737
let result = [];
38-
let temp = 0
38+
let temp = 0;
3939
for (let i = 0; i < utf16pass.length; i++) {
4040
temp = utf16pass[i] ^ 0xa5 ^ temp;
41-
result.push(((temp >> 4) & 0xf) + 0x41);
41+
result.push(((temp >>> 4) & 0xf) + 0x41);
4242
result.push((temp & 0xf) + 0x41);
4343
}
4444

45-
return new TextDecoder("utf-8").decode(Buffer.from(result));
45+
return result;
4646
}
4747

4848
}

test/tests/operations/Ciphers.mjs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,39 @@ TestRegister.addTests([
220220
}
221221
],
222222
},
223+
{
224+
name: "Citrix CTX1 Encode",
225+
input: "Password1",
226+
expectedOutput: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO",
227+
recipeConfig: [
228+
{
229+
"op": "Citrix CTX1 Encode",
230+
"args": []
231+
}
232+
],
233+
},
234+
{
235+
name: "Citrix CTX1 Decode: normal",
236+
input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO",
237+
expectedOutput: "Password1",
238+
recipeConfig: [
239+
{
240+
"op": "Citrix CTX1 Decode",
241+
"args": []
242+
}
243+
],
244+
},
245+
{
246+
name: "Citrix CTX1 Decode: invalid length",
247+
input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLA",
248+
expectedOutput: "",
249+
recipeConfig: [
250+
{
251+
"op": "Citrix CTX1 Decode",
252+
"args": []
253+
}
254+
],
255+
},
223256
{
224257
name: "Vigenère Encode: no input",
225258
input: "",

0 commit comments

Comments
 (0)