cyberchef 9.38.2 → 9.38.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberchef",
3
- "version": "9.38.2",
3
+ "version": "9.38.4",
4
4
  "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
5
5
  "author": "n1474335 <n1474335@gmail.com>",
6
6
  "homepage": "https://gchq.github.io/CyberChef",
@@ -5791,6 +5791,11 @@
5791
5791
  "name": "Remove non-alphabet chars",
5792
5792
  "type": "boolean",
5793
5793
  "value": true
5794
+ },
5795
+ {
5796
+ "name": "Strict mode",
5797
+ "type": "boolean",
5798
+ "value": false
5794
5799
  }
5795
5800
  ],
5796
5801
  "checks": [
@@ -5799,7 +5804,8 @@
5799
5804
  "flags": "i",
5800
5805
  "args": [
5801
5806
  "A-Za-z0-9+/=",
5802
- true
5807
+ true,
5808
+ false
5803
5809
  ]
5804
5810
  },
5805
5811
  {
@@ -5807,7 +5813,8 @@
5807
5813
  "flags": "i",
5808
5814
  "args": [
5809
5815
  "A-Za-z0-9-_",
5810
- true
5816
+ true,
5817
+ false
5811
5818
  ]
5812
5819
  },
5813
5820
  {
@@ -5815,7 +5822,8 @@
5815
5822
  "flags": "i",
5816
5823
  "args": [
5817
5824
  "A-Za-z0-9+\\-=",
5818
- true
5825
+ true,
5826
+ false
5819
5827
  ]
5820
5828
  },
5821
5829
  {
@@ -5823,7 +5831,8 @@
5823
5831
  "flags": "i",
5824
5832
  "args": [
5825
5833
  "./0-9A-Za-z=",
5826
- true
5834
+ true,
5835
+ false
5827
5836
  ]
5828
5837
  },
5829
5838
  {
@@ -5831,7 +5840,8 @@
5831
5840
  "flags": "i",
5832
5841
  "args": [
5833
5842
  "A-Za-z0-9_.",
5834
- true
5843
+ true,
5844
+ false
5835
5845
  ]
5836
5846
  },
5837
5847
  {
@@ -5839,7 +5849,8 @@
5839
5849
  "flags": "i",
5840
5850
  "args": [
5841
5851
  "A-Za-z0-9._-",
5842
- true
5852
+ true,
5853
+ false
5843
5854
  ]
5844
5855
  },
5845
5856
  {
@@ -5847,7 +5858,8 @@
5847
5858
  "flags": "i",
5848
5859
  "args": [
5849
5860
  "0-9a-zA-Z+/=",
5850
- true
5861
+ true,
5862
+ false
5851
5863
  ]
5852
5864
  },
5853
5865
  {
@@ -5855,7 +5867,8 @@
5855
5867
  "flags": "i",
5856
5868
  "args": [
5857
5869
  "0-9A-Za-z+/=",
5858
- true
5870
+ true,
5871
+ false
5859
5872
  ]
5860
5873
  },
5861
5874
  {
@@ -5863,6 +5876,7 @@
5863
5876
  "flags": "",
5864
5877
  "args": [
5865
5878
  " -_",
5879
+ false,
5866
5880
  false
5867
5881
  ]
5868
5882
  },
@@ -5871,7 +5885,8 @@
5871
5885
  "flags": "i",
5872
5886
  "args": [
5873
5887
  "+\\-0-9A-Za-z",
5874
- true
5888
+ true,
5889
+ false
5875
5890
  ]
5876
5891
  },
5877
5892
  {
@@ -5879,7 +5894,8 @@
5879
5894
  "flags": "",
5880
5895
  "args": [
5881
5896
  "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r",
5882
- true
5897
+ true,
5898
+ false
5883
5899
  ]
5884
5900
  },
5885
5901
  {
@@ -5887,7 +5903,8 @@
5887
5903
  "flags": "i",
5888
5904
  "args": [
5889
5905
  "N-ZA-Mn-za-m0-9+/=",
5890
- true
5906
+ true,
5907
+ false
5891
5908
  ]
5892
5909
  },
5893
5910
  {
@@ -5895,7 +5912,8 @@
5895
5912
  "flags": "i",
5896
5913
  "args": [
5897
5914
  "./0-9A-Za-z",
5898
- true
5915
+ true,
5916
+ false
5899
5917
  ]
5900
5918
  },
5901
5919
  {
@@ -5903,7 +5921,8 @@
5903
5921
  "flags": "i",
5904
5922
  "args": [
5905
5923
  "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC",
5906
- true
5924
+ true,
5925
+ false
5907
5926
  ]
5908
5927
  },
5909
5928
  {
@@ -5911,7 +5930,8 @@
5911
5930
  "flags": "i",
5912
5931
  "args": [
5913
5932
  "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5",
5914
- true
5933
+ true,
5934
+ false
5915
5935
  ]
5916
5936
  },
5917
5937
  {
@@ -5919,7 +5939,8 @@
5919
5939
  "flags": "i",
5920
5940
  "args": [
5921
5941
  "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2",
5922
- true
5942
+ true,
5943
+ false
5923
5944
  ]
5924
5945
  },
5925
5946
  {
@@ -5927,7 +5948,8 @@
5927
5948
  "flags": "i",
5928
5949
  "args": [
5929
5950
  "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
5930
- true
5951
+ true,
5952
+ false
5931
5953
  ]
5932
5954
  }
5933
5955
  ]
@@ -82,47 +82,74 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
82
82
  * // returns [72, 101, 108, 108, 111]
83
83
  * fromBase64("SGVsbG8=", null, "byteArray");
84
84
  */
85
- export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true) {
85
+ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true, strictMode=false) {
86
86
  if (!data) {
87
87
  return returnType === "string" ? "" : [];
88
88
  }
89
89
 
90
90
  alphabet = alphabet || "A-Za-z0-9+/=";
91
91
  alphabet = Utils.expandAlphRange(alphabet).join("");
92
+
93
+ // Confirm alphabet is a valid length
92
94
  if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
93
- throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
95
+ throw new OperationError(`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`);
94
96
  }
95
97
 
96
- const output = [];
97
- let chr1, chr2, chr3,
98
- enc1, enc2, enc3, enc4,
99
- i = 0;
100
-
98
+ // Remove non-alphabet characters
101
99
  if (removeNonAlphChars) {
102
100
  const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
103
101
  data = data.replace(re, "");
104
102
  }
105
103
 
104
+ if (strictMode) {
105
+ // Check for incorrect lengths (even without padding)
106
+ if (data.length % 4 === 1) {
107
+ throw new OperationError(`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`);
108
+ }
109
+
110
+ if (alphabet.length === 65) { // Padding character included
111
+ const pad = alphabet.charAt(64);
112
+ const padPos = data.indexOf(pad);
113
+ if (padPos >= 0) {
114
+ // Check that the padding character is only used at the end and maximum of twice
115
+ if (padPos < data.length - 2 || data.charAt(data.length - 1) !== pad) {
116
+ throw new OperationError(`Error: Base64 padding character (${pad}) not used in the correct place.`);
117
+ }
118
+
119
+ // Check that input is padded to the correct length
120
+ if (data.length % 4 !== 0) {
121
+ throw new OperationError("Error: Base64 not padded to a multiple of 4.");
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ const output = [];
128
+ let chr1, chr2, chr3,
129
+ enc1, enc2, enc3, enc4,
130
+ i = 0;
131
+
106
132
  while (i < data.length) {
107
133
  enc1 = alphabet.indexOf(data.charAt(i++));
108
- enc2 = alphabet.indexOf(data.charAt(i++) || "=");
109
- enc3 = alphabet.indexOf(data.charAt(i++) || "=");
110
- enc4 = alphabet.indexOf(data.charAt(i++) || "=");
134
+ enc2 = alphabet.indexOf(data.charAt(i++));
135
+ enc3 = alphabet.indexOf(data.charAt(i++));
136
+ enc4 = alphabet.indexOf(data.charAt(i++));
111
137
 
112
- enc2 = enc2 === -1 ? 64 : enc2;
113
- enc3 = enc3 === -1 ? 64 : enc3;
114
- enc4 = enc4 === -1 ? 64 : enc4;
138
+ if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
139
+ throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
140
+ }
115
141
 
116
142
  chr1 = (enc1 << 2) | (enc2 >> 4);
117
143
  chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
118
144
  chr3 = ((enc3 & 3) << 6) | enc4;
119
145
 
120
- output.push(chr1);
121
-
122
- if (enc3 !== 64) {
146
+ if (chr1 < 256) {
147
+ output.push(chr1);
148
+ }
149
+ if (chr2 < 256 && enc3 !== 64) {
123
150
  output.push(chr2);
124
151
  }
125
- if (enc4 !== 64) {
152
+ if (chr3 < 256 && enc4 !== 64) {
126
153
  output.push(chr3);
127
154
  }
128
155
  }
@@ -19,31 +19,33 @@ import OperationError from "../errors/OperationError.mjs";
19
19
  * @returns {string}
20
20
  *
21
21
  * @example
22
- * // returns "00010000 00100000 00110000"
22
+ * // returns "00001010 00010100 00011110"
23
23
  * toBinary([10,20,30]);
24
24
  *
25
- * // returns "00010000 00100000 00110000"
26
- * toBinary([10,20,30], ":");
25
+ * // returns "00001010:00010100:00011110"
26
+ * toBinary([10,20,30], "Colon");
27
+ *
28
+ * // returns "1010:10100:11110"
29
+ * toBinary([10,20,30], "Colon", 0);
27
30
  */
28
31
  export function toBinary(data, delim="Space", padding=8) {
32
+ if (data === undefined || data === null)
33
+ throw new OperationError("Unable to convert to binary: Empty input data enocuntered");
34
+
29
35
  delim = Utils.charRep(delim);
30
36
  let output = "";
31
37
 
32
38
  if (data.length) { // array
33
39
  for (let i = 0; i < data.length; i++) {
34
- output += data[i].toString(2).padStart(padding, "0") + delim;
40
+ output += data[i].toString(2).padStart(padding, "0");
41
+ if (i !== data.length - 1) output += delim;
35
42
  }
36
43
  } else if (typeof data === "number") { // Single value
37
44
  return data.toString(2).padStart(padding, "0");
38
45
  } else {
39
46
  return "";
40
47
  }
41
-
42
- if (delim.length) {
43
- return output.slice(0, -delim.length);
44
- } else {
45
- return output;
46
- }
48
+ return output;
47
49
  }
48
50
 
49
51
 
@@ -57,10 +59,10 @@ export function toBinary(data, delim="Space", padding=8) {
57
59
  *
58
60
  * @example
59
61
  * // returns [10,20,30]
60
- * fromBinary("00010000 00100000 00110000");
62
+ * fromBinary("00001010 00010100 00011110");
61
63
  *
62
64
  * // returns [10,20,30]
63
- * fromBinary("00010000:00100000:00110000", "Colon");
65
+ * fromBinary("00001010:00010100:00011110", "Colon");
64
66
  */
65
67
  export function fromBinary(data, delim="Space", byteLen=8) {
66
68
  if (byteLen < 1 || Math.round(byteLen) !== byteLen)
@@ -34,93 +34,98 @@ class FromBase64 extends Operation {
34
34
  name: "Remove non-alphabet chars",
35
35
  type: "boolean",
36
36
  value: true
37
+ },
38
+ {
39
+ name: "Strict mode",
40
+ type: "boolean",
41
+ value: false
37
42
  }
38
43
  ];
39
44
  this.checks = [
40
45
  {
41
46
  pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
42
47
  flags: "i",
43
- args: ["A-Za-z0-9+/=", true]
48
+ args: ["A-Za-z0-9+/=", true, false]
44
49
  },
45
50
  {
46
51
  pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
47
52
  flags: "i",
48
- args: ["A-Za-z0-9-_", true]
53
+ args: ["A-Za-z0-9-_", true, false]
49
54
  },
50
55
  {
51
56
  pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
52
57
  flags: "i",
53
- args: ["A-Za-z0-9+\\-=", true]
58
+ args: ["A-Za-z0-9+\\-=", true, false]
54
59
  },
55
60
  {
56
61
  pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
57
62
  flags: "i",
58
- args: ["./0-9A-Za-z=", true]
63
+ args: ["./0-9A-Za-z=", true, false]
59
64
  },
60
65
  {
61
66
  pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
62
67
  flags: "i",
63
- args: ["A-Za-z0-9_.", true]
68
+ args: ["A-Za-z0-9_.", true, false]
64
69
  },
65
70
  {
66
71
  pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
67
72
  flags: "i",
68
- args: ["A-Za-z0-9._-", true]
73
+ args: ["A-Za-z0-9._-", true, false]
69
74
  },
70
75
  {
71
76
  pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
72
77
  flags: "i",
73
- args: ["0-9a-zA-Z+/=", true]
78
+ args: ["0-9a-zA-Z+/=", true, false]
74
79
  },
75
80
  {
76
81
  pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
77
82
  flags: "i",
78
- args: ["0-9A-Za-z+/=", true]
83
+ args: ["0-9A-Za-z+/=", true, false]
79
84
  },
80
85
  {
81
86
  pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
82
87
  flags: "",
83
- args: [" -_", false]
88
+ args: [" -_", false, false]
84
89
  },
85
90
  {
86
91
  pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
87
92
  flags: "i",
88
- args: ["+\\-0-9A-Za-z", true]
93
+ args: ["+\\-0-9A-Za-z", true, false]
89
94
  },
90
95
  {
91
96
  pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
92
97
  flags: "",
93
- args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
98
+ args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true, false]
94
99
  },
95
100
  {
96
101
  pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
97
102
  flags: "i",
98
- args: ["N-ZA-Mn-za-m0-9+/=", true]
103
+ args: ["N-ZA-Mn-za-m0-9+/=", true, false]
99
104
  },
100
105
  {
101
106
  pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
102
107
  flags: "i",
103
- args: ["./0-9A-Za-z", true]
108
+ args: ["./0-9A-Za-z", true, false]
104
109
  },
105
110
  {
106
111
  pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}CC|[A-Z=\\d\\+/]{3}C)?\\s*$",
107
112
  flags: "i",
108
- args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true]
113
+ args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true, false]
109
114
  },
110
115
  {
111
116
  pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
112
117
  flags: "i",
113
- args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true]
118
+ args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true, false]
114
119
  },
115
120
  {
116
121
  pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}22|[A-Z=\\d\\+/]{3}2)?\\s*$",
117
122
  flags: "i",
118
- args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true]
123
+ args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true, false]
119
124
  },
120
125
  {
121
126
  pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
122
127
  flags: "i",
123
- args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true]
128
+ args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true, false]
124
129
  }
125
130
  ];
126
131
  }
@@ -131,9 +136,9 @@ class FromBase64 extends Operation {
131
136
  * @returns {byteArray}
132
137
  */
133
138
  run(input, args) {
134
- const [alphabet, removeNonAlphChars] = args;
139
+ const [alphabet, removeNonAlphChars, strictMode] = args;
135
140
 
136
- return fromBase64(input, alphabet, "byteArray", removeNonAlphChars);
141
+ return fromBase64(input, alphabet, "byteArray", removeNonAlphChars, strictMode);
137
142
  }
138
143
 
139
144
  /**
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
8
9
 
9
10
  /**
10
11
  * To Upper case operation
@@ -37,25 +38,30 @@ class ToUpperCase extends Operation {
37
38
  * @returns {string}
38
39
  */
39
40
  run(input, args) {
41
+ if (!args || args.length === 0) {
42
+ throw new OperationError("No capitalization scope was provided.");
43
+ }
44
+
40
45
  const scope = args[0];
41
46
 
42
- switch (scope) {
43
- case "Word":
44
- return input.replace(/(\b\w)/gi, function(m) {
45
- return m.toUpperCase();
46
- });
47
- case "Sentence":
48
- return input.replace(/(?:\.|^)\s*(\b\w)/gi, function(m) {
49
- return m.toUpperCase();
50
- });
51
- case "Paragraph":
52
- return input.replace(/(?:\n|^)\s*(\b\w)/gi, function(m) {
53
- return m.toUpperCase();
54
- });
55
- case "All": /* falls through */
56
- default:
57
- return input.toUpperCase();
47
+ if (scope === "All") {
48
+ return input.toUpperCase();
49
+ }
50
+
51
+ const scopeRegex = {
52
+ "Word": /(\b\w)/gi,
53
+ "Sentence": /(?:\.|^)\s*(\b\w)/gi,
54
+ "Paragraph": /(?:\n|^)\s*(\b\w)/gi
55
+ }[scope];
56
+
57
+ if (scopeRegex === undefined) {
58
+ throw new OperationError("Unrecognized capitalization scope");
58
59
  }
60
+
61
+ // Use the regex to capitalize the input
62
+ return input.replace(scopeRegex, function(m) {
63
+ return m.toUpperCase();
64
+ });
59
65
  }
60
66
 
61
67
  /**
@@ -68,7 +68,7 @@ TestRegister.addTests([
68
68
  {
69
69
  name: "Magic Chain: Base64",
70
70
  input: "WkVkV2VtUkRRbnBrU0Vwd1ltMWpQUT09",
71
- expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)/,
71
+ expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)/,
72
72
  recipeConfig: [
73
73
  {
74
74
  op: "Magic",
@@ -79,7 +79,7 @@ TestRegister.addTests([
79
79
  {
80
80
  name: "Magic Chain: Hex -> Hexdump -> Base64",
81
81
  input: "MDAwMDAwMDAgIDM3IDM0IDIwIDM2IDM1IDIwIDM3IDMzIDIwIDM3IDM0IDIwIDMyIDMwIDIwIDM3ICB8NzQgNjUgNzMgNzQgMjAgN3wKMDAwMDAwMTAgIDMzIDIwIDM3IDM0IDIwIDM3IDMyIDIwIDM2IDM5IDIwIDM2IDY1IDIwIDM2IDM3ICB8MyA3NCA3MiA2OSA2ZSA2N3w=",
82
- expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
82
+ expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
83
83
  recipeConfig: [
84
84
  {
85
85
  op: "Magic",