ares/decoders/
hexadecimal_decoder.rs1use crate::checkers::CheckerTypes;
2use crate::decoders::interface::check_string_success;
3
4use super::crack_results::CrackResult;
5use super::interface::Crack;
6use super::interface::Decoder;
7
8use log::{debug, info, trace};
9
10pub struct HexadecimalDecoder;
12
13#[derive(Debug)]
15enum Error {
16 InvalidLength,
18 InvalidUtf8,
20}
21
22impl Crack for Decoder<HexadecimalDecoder> {
23 fn new() -> Decoder<HexadecimalDecoder> {
24 Decoder {
25 name: "Hexadecimal",
26 description: "Data is broken into 4-bit sequences, and each value (between 0 and 15 inclusively) is encoded using one of 16 symbols from the ASCII character set. Although any 16 symbols from the ASCII character set can be used, in practice the ASCII digits '0'–'9' and the letters 'A'–'F' (or the lowercase 'a'–'f') are always chosen in order to align with standard written notation for hexadecimal numbers.",
27 link: "https://en.wikipedia.org/wiki/Hexadecimal#Base16_(transfer_encoding)",
28 tags: vec!["hexadecimal", "hex", "base", "decoder"],
29 popularity: 1.0,
30 phantom: std::marker::PhantomData,
31 }
32 }
33
34 fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
38 trace!("Trying hexadecimal with text {:?}", text);
39 let decoded_text: Result<String, Error> = hexadecimal_to_string(text);
40 let mut results = CrackResult::new(self, text.to_string());
41
42 if decoded_text.is_err() {
43 debug!("Failed to decode hexadecimal: {:?}", decoded_text);
44 return results;
45 }
46
47 trace!("Decoded text for hexadecimal: {:?}", decoded_text);
48
49 let decoded_text = decoded_text.unwrap();
50
51 if !check_string_success(&decoded_text, text) {
52 info!(
53 "Failed to decode hexadecimal because check_string_success returned false on string {}",
54 decoded_text
55 );
56 return results;
57 }
58
59 let checker_result = checker.check(&decoded_text);
60 results.unencrypted_text = Some(vec![decoded_text]);
61
62 results.update_checker(&checker_result);
63
64 results
65 }
66 fn get_tags(&self) -> &Vec<&str> {
68 &self.tags
69 }
70 fn get_name(&self) -> &str {
72 self.name
73 }
74}
75
76fn hexadecimal_to_string(hex: &str) -> Result<String, Error> {
78 let hex = hex.replace("0x", "");
80 let hex = hex.replace(|c: char| !c.is_ascii_hexdigit(), "");
82
83 let bytes = hex.as_bytes();
85
86 if bytes.len() % 2 == 1 {
88 return Err(Error::InvalidLength);
89 }
90
91 let mut result = String::new();
93 for pair in bytes.chunks(2) {
94 result.push(u8::from_str_radix(std::str::from_utf8(pair).unwrap(), 16).unwrap() as char);
97 }
98
99 String::from_utf8(result.into()).map_err(|_| Error::InvalidUtf8)
100}
101
102#[cfg(test)]
103mod tests {
104 use super::HexadecimalDecoder;
105 use crate::{
106 checkers::{
107 athena::Athena,
108 checker_type::{Check, Checker},
109 CheckerTypes,
110 },
111 decoders::interface::{Crack, Decoder},
112 };
113
114 fn get_athena_checker() -> CheckerTypes {
116 let athena_checker = Checker::<Athena>::new();
117 CheckerTypes::CheckAthena(athena_checker)
118 }
119
120 #[test]
121 fn hexadecimal_with_no_spaces_decodes_successfully() {
122 let decoder = Decoder::<HexadecimalDecoder>::new();
124 let result = decoder.crack(
125 "537068696e78206f6620626c61636b2071756172747a2c206a75646765206d7920766f772e",
126 &get_athena_checker(),
127 );
128 assert_eq!(
129 result.unencrypted_text.unwrap()[0],
130 "Sphinx of black quartz, judge my vow."
131 );
132 }
133
134 #[test]
135 fn hexadecimal_with_spaces_decodes_successfully() {
136 let decoder = Decoder::<HexadecimalDecoder>::new();
139 let result = decoder.crack(
140 "68 65 78 61 64 65 63 69 6d 61 6c 20 6f 72 20 62 61 73 65 31 36 3f",
141 &get_athena_checker(),
142 );
143 assert_eq!(
144 result.unencrypted_text.unwrap()[0],
145 "hexadecimal or base16?"
146 );
147 }
148
149 #[test]
150 fn hexadecimal_with_delimiters_decodes_successfully() {
151 let decoder = Decoder::<HexadecimalDecoder>::new();
153 let result = decoder.crack(
154 "68;74;74;70;73;3a;2f;2f;77;77;77;2e;67;6f;6f;67;6c;65;2e;63;6f;6d",
155 &get_athena_checker(),
156 );
157 assert_eq!(
158 result.unencrypted_text.unwrap()[0],
159 "https://www.google.com"
160 );
161 }
162
163 #[test]
164 fn uppercase_hexadecimal_decodes_successfully() {
165 let decoder = Decoder::<HexadecimalDecoder>::new();
167 let result = decoder.crack(
168 "5570706572636173652068657861646563696D616C",
169 &get_athena_checker(),
170 );
171 assert_eq!(result.unencrypted_text.unwrap()[0], "Uppercase hexadecimal");
172 }
173
174 #[test]
175 fn hexadecimal_with_0x_delimiters_decodes_successfully() {
176 let decoder = Decoder::<HexadecimalDecoder>::new();
178 let result = decoder.crack(
179 "0x540x680x690x730x200x750x730x650x730x200x300x780x200x610x730x200x740x680x650x200x700x720x650x660x690x780x200x620x650x740x770x650x650x6e0x200x650x760x650x720x790x200x630x680x750x6e0x6b",
180 &get_athena_checker(),
181 );
182 assert_eq!(
183 result.unencrypted_text.unwrap()[0],
184 "This uses 0x as the prefix between every chunk"
185 );
186 }
187
188 #[test]
189 fn hexadecimal_with_0x_and_comma_delimiters_decodes_successfully() {
190 let decoder = Decoder::<HexadecimalDecoder>::new();
192 let result = decoder.crack(
193 "0x48,0x65,0x78,0x61,0x64,0x65,0x63,0x69,0x6d,0x61,0x6c,0x20,0x77,0x69,0x74,0x68,0x20,0x30,0x78,0x20,0x2b,0x20,0x63,0x6f,0x6d,0x6d,0x61,0x73",
194 &get_athena_checker(),
195 );
196 assert_eq!(
197 result.unencrypted_text.unwrap()[0],
198 "Hexadecimal with 0x + commas"
199 );
200 }
201
202 #[test]
203 fn hexadecimal_handles_panics() {
204 let hexadecimal_decoder = Decoder::<HexadecimalDecoder>::new();
208 let result = hexadecimal_decoder
209 .crack(
210 "hello my name is panicky mc panic face!",
211 &get_athena_checker(),
212 )
213 .unencrypted_text;
214 assert!(result.is_some());
215 }
216
217 #[test]
218 fn hexadecimal_handles_panic_if_empty_string() {
219 let citrix_ctx1_decoder = Decoder::<HexadecimalDecoder>::new();
222 let result = citrix_ctx1_decoder
223 .crack("", &get_athena_checker())
224 .unencrypted_text;
225 assert!(result.is_none());
226 }
227
228 #[test]
229 fn hexadecimal_handles_panic_if_emoji() {
230 let base64_url_decoder = Decoder::<HexadecimalDecoder>::new();
233 let result = base64_url_decoder
234 .crack("😂", &get_athena_checker())
235 .unencrypted_text;
236 assert!(result.is_none());
237 }
238}