ares/decoders/
atbash_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::{info, trace};
9
10pub struct AtbashDecoder;
12
13impl Crack for Decoder<AtbashDecoder> {
14 fn new() -> Decoder<AtbashDecoder> {
15 Decoder {
16 name: "Atbash",
17 description: "Atbash is a monoalphabetic substitution cipher originally used to encrypt the Hebrew alphabet. It can be modified for use with any known writing system with a standard collating order.",
18 link: "https://en.wikipedia.org/wiki/Atbash",
19 tags: vec!["atbash", "substitution", "decoder", "reciprocal"],
20 popularity: 1.0,
21 phantom: std::marker::PhantomData,
22 }
23 }
24
25 fn crack(&self, text: &str, checker: &CheckerTypes) -> CrackResult {
29 trace!("Trying atbash with text {:?}", text);
30 let decoded_text = atbash_to_alphabet(text);
31
32 trace!("Decoded text for atbash: {:?}", decoded_text);
33 let mut results = CrackResult::new(self, text.to_string());
34
35 if !check_string_success(&decoded_text, text) {
36 info!(
37 "Failed to decode atbash because check_string_success returned false on string {}",
38 decoded_text
39 );
40 return results;
41 }
42
43 let checker_result = checker.check(&decoded_text);
44 results.unencrypted_text = Some(vec![decoded_text]);
45
46 results.update_checker(&checker_result);
47
48 results
49 }
50 fn get_tags(&self) -> &Vec<&str> {
52 &self.tags
53 }
54 fn get_name(&self) -> &str {
56 self.name
57 }
58}
59
60fn atbash_to_alphabet(text: &str) -> String {
62 text.chars()
63 .map(|char| match char {
64 letter @ 'a'..='z' => (b'a' + b'z' - letter as u8) as char,
65 letter @ 'A'..='Z' => (b'A' + b'Z' - letter as u8) as char,
66 other => other,
67 })
68 .collect()
69}
70
71#[cfg(test)]
72mod tests {
73 use super::AtbashDecoder;
74 use crate::{
75 checkers::{
76 athena::Athena,
77 checker_type::{Check, Checker},
78 CheckerTypes,
79 },
80 decoders::interface::{Crack, Decoder},
81 };
82
83 fn get_athena_checker() -> CheckerTypes {
85 let athena_checker = Checker::<Athena>::new();
86 CheckerTypes::CheckAthena(athena_checker)
87 }
88
89 #[test]
90 fn test_atbash() {
91 let decoder = Decoder::<AtbashDecoder>::new();
92 let result = decoder.crack("svool dliow", &get_athena_checker());
93 assert_eq!(result.unencrypted_text.unwrap()[0], "hello world");
94 }
95
96 #[test]
97 fn test_atbash_capitalization() {
98 let decoder = Decoder::<AtbashDecoder>::new();
99 let result = decoder.crack(
100 "Zgyzhs Hslfow Pvvk Xzkrgzorazgrlm orpv GSRH",
101 &get_athena_checker(),
102 );
103 assert_eq!(
104 result.unencrypted_text.unwrap()[0],
105 "Atbash Should Keep Capitalization like THIS"
106 );
107 }
108
109 #[test]
110 fn test_atbash_non_alphabetic_characters() {
111 let decoder = Decoder::<AtbashDecoder>::new();
112 let result = decoder.crack(
113 "Zgyzhs hslfow ovzev xszizxgvih orpv gsvhv: ',.39=_#%^ rmgzxg zugvi wvxlwrmt!",
114 &get_athena_checker(),
115 );
116 assert_eq!(
117 result.unencrypted_text.unwrap()[0],
118 "Atbash should leave characters like these: ',.39=_#%^ intact after decoding!"
119 );
120 }
121
122 #[test]
123 fn atbash_decode_empty_string() {
124 let atbash_decoder = Decoder::<AtbashDecoder>::new();
127 let result = atbash_decoder
128 .crack("", &get_athena_checker())
129 .unencrypted_text;
130 assert!(result.is_none());
131 }
132
133 #[test]
134 fn atbash_decode_handles_panics() {
135 let atbash_decoder = Decoder::<AtbashDecoder>::new();
136 let result = atbash_decoder
137 .crack("583920482058430191", &get_athena_checker())
138 .unencrypted_text;
139 if result.is_some() {
140 panic!("Decode_atbash did not return an option with Some<t>.")
141 } else {
142 assert_eq!(true, true);
146 }
147 }
148
149 #[test]
150 fn atbash_handle_panic_if_empty_string() {
151 let atbash_decoder = Decoder::<AtbashDecoder>::new();
152 let result = atbash_decoder
153 .crack("", &get_athena_checker())
154 .unencrypted_text;
155 if result.is_some() {
156 assert_eq!(true, true);
157 }
158 }
159
160 #[test]
161 fn atbash_work_if_string_not_atbash() {
162 let atbash_decoder = Decoder::<AtbashDecoder>::new();
163 let result = atbash_decoder
164 .crack("hello good day!", &get_athena_checker())
165 .unencrypted_text;
166 if result.is_some() {
167 assert_eq!(true, true);
168 }
169 }
170
171 #[test]
172 fn atbash_handle_panic_if_emoji() {
173 let atbash_decoder = Decoder::<AtbashDecoder>::new();
174 let result = atbash_decoder
175 .crack("😂", &get_athena_checker())
176 .unencrypted_text;
177 if result.is_some() {
178 assert_eq!(true, true);
179 }
180 }
181}