ares/decoders/
base32_decoder.rs

1use crate::checkers::CheckerTypes;
2use crate::decoders::interface::check_string_success;
3
4use super::crack_results::CrackResult;
5///! Decodes a base32 string
6///! Performs error handling and returns a string
7///! Call base32_decoder.crack to use. It returns option<String> and check with
8///! `result.is_some()` to see if it returned okay.
9///
10use super::interface::Crack;
11use super::interface::Decoder;
12
13use data_encoding::BASE32;
14use log::{debug, info, trace};
15
16/// The Base32 decoder, call:
17/// `let base32_decoder = Decoder::<Base32Decoder>::new()` to create a new instance
18/// And then call:
19/// `result = base32_decoder.crack(input)` to decode a base32 string
20/// The struct generated by new() comes from interface.rs
21/// ```
22/// use ares::decoders::base32_decoder::{Base32Decoder};
23/// use ares::decoders::interface::{Crack, Decoder};
24/// use ares::checkers::{athena::Athena, CheckerTypes, checker_type::{Check, Checker}};
25///
26/// let decode_base32 = Decoder::<Base32Decoder>::new();
27/// let athena_checker = Checker::<Athena>::new();
28/// let checker = CheckerTypes::CheckAthena(athena_checker);
29///
30/// let result = decode_base32.crack("NBSWY3DPEB3W64TMMQ======", &checker).unencrypted_text;
31/// assert!(result.is_some());
32/// assert_eq!(result.unwrap()[0], "hello world");
33/// ```
34pub struct Base32Decoder;
35
36impl Crack for Decoder<Base32Decoder> {
37    fn new() -> Decoder<Base32Decoder> {
38        Decoder {
39            name: "Base32",
40            description: "Base32 is a group of binary-to-text encoding schemes that represent binary data (more specifically, a sequence of 8-bit bytes) in an ASCII string format by translating the data into a radix-32 representation.",
41            link: "https://en.wikipedia.org/wiki/Base32",
42            tags: vec!["base32", "decoder", "base"],
43            popularity: 0.8,
44            phantom: std::marker::PhantomData,
45        }
46    }
47
48    /// This function does the actual decoding
49    /// It returns an Option<string> if it was successful
50    /// Else the Option returns nothing and the error is logged in Trace
51    fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
52        trace!("Trying Base32 with text {:?}", text);
53        let decoded_text = decode_base32_no_error_handling(text);
54        let mut results = CrackResult::new(self, text.to_string());
55
56        if decoded_text.is_none() {
57            debug!("Failed to decode base32 because Base32Decoder::decode_base32_no_error_handling returned None");
58            return results;
59        }
60
61        let decoded_text = decoded_text.unwrap();
62        if !check_string_success(&decoded_text, text) {
63            info!(
64                "Failed to decode base32 because check_string_success returned false on string {}",
65                decoded_text
66            );
67            return results;
68        }
69
70        let checker_result = checker.check(&decoded_text);
71        results.unencrypted_text = Some(vec![decoded_text]);
72
73        results.update_checker(&checker_result);
74
75        results
76    }
77    /// Gets all tags for this decoder
78    fn get_tags(&self) -> &Vec<&str> {
79        &self.tags
80    }
81    /// Gets the name for the current decoder
82    fn get_name(&self) -> &str {
83        self.name
84    }
85}
86
87/// helper function
88fn decode_base32_no_error_handling(text: &str) -> Option<String> {
89    // Runs the code to decode base32
90    // Doesn't perform error handling, call from_base32
91    if let Ok(decoded_text) = &BASE32.decode(text.as_bytes()) {
92        return Some(String::from_utf8_lossy(decoded_text).to_string());
93    }
94    None
95}
96
97#[cfg(test)]
98mod tests {
99    use super::Base32Decoder;
100    use crate::{
101        checkers::{
102            athena::Athena,
103            checker_type::{Check, Checker},
104            CheckerTypes,
105        },
106        decoders::interface::{Crack, Decoder},
107    };
108
109    // helper for tests
110    fn get_athena_checker() -> CheckerTypes {
111        let athena_checker = Checker::<Athena>::new();
112        CheckerTypes::CheckAthena(athena_checker)
113    }
114
115    #[test]
116    fn successful_decoding() {
117        let base32_decoder = Decoder::<Base32Decoder>::new();
118
119        let result = base32_decoder.crack("NBSWY3DPEB3W64TMMQ======", &get_athena_checker());
120        let decoded_str = &result
121            .unencrypted_text
122            .expect("No unencrypted text for base32");
123        assert_eq!(decoded_str[0], "hello world");
124    }
125
126    #[test]
127    fn base32_decode_empty_string() {
128        // Bsae32 returns an empty string, this is a valid base32 string
129        // but returns False on check_string_success
130        let base32_decoder = Decoder::<Base32Decoder>::new();
131        let result = base32_decoder
132            .crack("", &get_athena_checker())
133            .unencrypted_text;
134        assert!(result.is_none());
135    }
136
137    #[test]
138    fn base32_decode_handles_panics() {
139        let base32_decoder = Decoder::<Base32Decoder>::new();
140        let result = base32_decoder
141            .crack(
142                "hello my name is panicky mc panic face!",
143                &get_athena_checker(),
144            )
145            .unencrypted_text;
146        if result.is_some() {
147            panic!("Decode_base32 did not return an option with Some<t>.")
148        } else {
149            // If we get here, the test passed
150            // Because the base32_decoder.crack function returned None
151            // as it should do for the input
152            assert_eq!(true, true);
153        }
154    }
155
156    #[test]
157    fn base32_handle_panic_if_empty_string() {
158        let base32_decoder = Decoder::<Base32Decoder>::new();
159        let result = base32_decoder
160            .crack("", &get_athena_checker())
161            .unencrypted_text;
162        if result.is_some() {
163            assert_eq!(true, true);
164        }
165    }
166
167    #[test]
168    fn base32_work_if_string_not_base32() {
169        // You can base32 decode a string that is not base32
170        // This string decodes to:
171        // ```.ée¢
172        // (uÖ²```
173        // https://gchq.github.io/CyberChef/#recipe=From_Base32('A-Za-z0-9%2B/%3D',true)&input=aGVsbG8gZ29vZCBkYXkh
174        let base32_decoder = Decoder::<Base32Decoder>::new();
175        let result = base32_decoder
176            .crack("hello good day!", &get_athena_checker())
177            .unencrypted_text;
178        if result.is_some() {
179            assert_eq!(true, true);
180        }
181    }
182
183    #[test]
184    fn base32_handle_panic_if_emoji() {
185        let base32_decoder = Decoder::<Base32Decoder>::new();
186        let result = base32_decoder
187            .crack("😂", &get_athena_checker())
188            .unencrypted_text;
189        if result.is_some() {
190            assert_eq!(true, true);
191        }
192    }
193}