ares/decoders/
base64_decoder.rs

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