Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve base32 decoder #200

Merged
merged 2 commits into from
Feb 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 44 additions & 48 deletions src/decoders/base32_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::crack_results::CrackResult;
use super::interface::Crack;
use super::interface::Decoder;

use data_encoding::BASE32;
use data_encoding::BASE32_NOPAD;
use log::{debug, info, trace};

/// The Base32 decoder, call:
Expand Down Expand Up @@ -86,9 +86,11 @@ impl Crack for Decoder<Base32Decoder> {

/// helper function
fn decode_base32_no_error_handling(text: &str) -> Option<String> {
// Strip all padding
let text = text.replace('=', "");
// Runs the code to decode base32
// Doesn't perform error handling, call from_base32
if let Ok(decoded_text) = &BASE32.decode(text.as_bytes()) {
if let Ok(decoded_text) = &BASE32_NOPAD.decode(text.as_bytes()) {
return Some(String::from_utf8_lossy(decoded_text).to_string());
}
None
Expand All @@ -113,81 +115,75 @@ mod tests {
}

#[test]
fn successful_decoding() {
fn base32_decodes_successfully() {
// This tests if Base32 can decode Base32 successfully
let base32_decoder = Decoder::<Base32Decoder>::new();

let result = base32_decoder.crack("NBSWY3DPEB3W64TMMQ======", &get_athena_checker());
let decoded_str = &result
.unencrypted_text
.expect("No unencrypted text for base32");
assert_eq!(decoded_str[0], "hello world");
assert_eq!(result.unencrypted_text.unwrap()[0], "hello world");
}

#[test]
fn base32_decode_empty_string() {
// Bsae32 returns an empty string, this is a valid base32 string
// but returns False on check_string_success
fn base32_decodes_no_padding_base32_successfully() {
// This tests if Base32 can decode Base32 with no padding successfully
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder
.crack("", &get_athena_checker())
.unencrypted_text;
assert!(result.is_none());
let result =
base32_decoder.crack("KRUGS4ZANBQXGID2MVZG6IDQMFSGI2LOM4", &get_athena_checker());
assert_eq!(result.unencrypted_text.unwrap()[0], "This has zero padding");
}

#[test]
fn base32_decodes_broken_padding_base32_successfully() {
// This tests if Base32 can decode Base32 with broken padding successfully
// Normally this string should have 4 equal signs instead of 2
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder.crack("JFXGG33SOJSWG5BAOBQWIZDJNZTQ==", &get_athena_checker());
assert_eq!(result.unencrypted_text.unwrap()[0], "Incorrect padding");
}

#[ignore]
#[test]
fn base32_decodes_tryhackme_base32_successfully() {
// This tests if Base32 can decode Base32 with no padding successfully
// The string is from the "breakit" THM room
// TODO: Ignoring this until we have quadgrams
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder.crack("GM4HOU3VHBAW6OKNJJFW6SS2IZ3VAMTYORFDMUC2G44EQULIJI3WIVRUMNCWI6KGK5XEKZDTN5YU2RT2MR3E45KKI5TXSOJTKZJTC4KRKFDWKZTZOF3TORJTGZTXGNKCOE", &get_athena_checker());
assert_eq!(result.unencrypted_text.unwrap()[0], "base16_is_hex");
}

#[test]
fn base32_decode_handles_panics() {
fn base32_handles_panics() {
// This tests if Base32 can handle panics
// It should return None
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder
.crack(
"hello my name is panicky mc panic face!",
&get_athena_checker(),
)
.unencrypted_text;
if result.is_some() {
panic!("Decode_base32 did not return an option with Some<t>.")
} else {
// If we get here, the test passed
// Because the base32_decoder.crack function returned None
// as it should do for the input
assert_eq!(true, true);
}
assert!(result.is_none());
}

#[test]
fn base32_handle_panic_if_empty_string() {
fn base32_handles_panic_if_empty_string() {
// This tests if Base32 can handle an empty string
// It should return None
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder
.crack("", &get_athena_checker())
.unencrypted_text;
if result.is_some() {
assert_eq!(true, true);
}
}

#[test]
fn base32_work_if_string_not_base32() {
// You can base32 decode a string that is not base32
// This string decodes to:
// ```.ée¢
// (uÖ²```
// https://gchq.github.io/CyberChef/#recipe=From_Base32('A-Za-z0-9%2B/%3D',true)&input=aGVsbG8gZ29vZCBkYXkh
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder
.crack("hello good day!", &get_athena_checker())
.unencrypted_text;
if result.is_some() {
assert_eq!(true, true);
}
assert!(result.is_none());
}

#[test]
fn base32_handle_panic_if_emoji() {
fn base32_handles_panic_if_emoji() {
// This tests if Base32 can handle an emoji
// It should return None
let base32_decoder = Decoder::<Base32Decoder>::new();
let result = base32_decoder
.crack("😂", &get_athena_checker())
.unencrypted_text;
if result.is_some() {
assert_eq!(true, true);
}
assert!(result.is_none());
}
}