1use rand::seq::SliceRandom;
41use rand::thread_rng;
42
43enum EncMethod {
44 INC,
45 DEC,
46 TIME,
47}
48
49impl EncMethod {
50 fn choose() -> Self {
52 let mut rng = thread_rng();
53 let choices = [0, 1, 2];
54 match choices.choose(&mut rng) {
55 Some(0) => EncMethod::INC,
56 Some(1) => EncMethod::DEC,
57 Some(2) => EncMethod::TIME,
58 _ => unreachable!(),
59 }
60 }
61 fn key(&self) -> usize {
62 match self {
63 EncMethod::INC => 0,
64 EncMethod::DEC => 1,
65 EncMethod::TIME => time_to_key(),
66 }
67 }
68 fn from_key(key: usize) -> Self {
69 match key {
70 0 => EncMethod::INC,
71 1 => EncMethod::DEC,
72 _ => EncMethod::TIME,
73 }
74 }
75}
76
77pub trait SecretMessage {
78 fn one_way_encrypt(&self) -> String;
80
81 fn encrypt_with_key(&self, key: usize) -> String;
83
84 fn encrypt(&self) -> (String, usize);
86
87 fn decrypt(&self, key: usize) -> String;
89}
90
91impl<T: ToString> SecretMessage for T {
92 fn one_way_encrypt(&self) -> String {
93 let hash: [u8; 16] = md5::compute(self.to_string()).into();
94 hash.iter().fold(0, |acc, x| acc + *x as usize).to_string()
95 }
96
97 fn encrypt_with_key(&self, key: usize) -> String {
98 let method = EncMethod::from_key(key);
99
100 self.to_string()
101 .chars()
102 .map(|c| encrypt_character(c, &method, key))
103 .collect::<String>()
104 }
105
106 fn encrypt(&self) -> (String, usize) {
107 let method = EncMethod::choose();
108
109 let key = method.key();
110 let enc = self.encrypt_with_key(key);
111
112 (enc, key)
113 }
114
115 fn decrypt(&self, key: usize) -> String {
116 let method = EncMethod::from_key(key);
117 self.to_string()
118 .chars()
119 .map(|c| decrypt_character(c, &method, key))
120 .collect::<String>()
121 }
122}
123
124fn encrypt_character(c: char, method: &EncMethod, key: usize) -> char {
125 match method {
126 EncMethod::INC => char_move(c, 1),
127 EncMethod::DEC => char_move(c, -1),
128 EncMethod::TIME => enc_time(c, key),
129 }
130}
131
132fn decrypt_character(c: char, method: &EncMethod, key: usize) -> char {
133 match method {
134 EncMethod::INC => char_move(c, -1),
135 EncMethod::DEC => char_move(c, 1),
136 EncMethod::TIME => decrypt_character_time(c, key),
137 }
138}
139
140fn char_move(c: char, add: i32) -> char {
142 let mut enc_c = (c as i32 + add) % 255;
143 if enc_c <= 0 {
144 enc_c += 255;
145 }
146 enc_c as u8 as char
147}
148
149fn enc_time(c: char, key: usize) -> char {
151 let enc_c = key + c as usize;
153 (enc_c % 255) as u8 as char
154}
155fn decrypt_character_time(c: char, key: usize) -> char {
156 let mut c = c as usize;
158 let key = key % 255;
159 if c <= key {
160 c += 255;
161 }
162 (c - key) as u8 as char
163}
164
165fn time_to_key() -> usize {
167 use std::time::Instant;
168 let mut code = 0;
169 Instant::now().elapsed().as_nanos().to_string().chars().for_each(|c| {
170 if c.is_digit(10) {
171 code += c.to_digit(10).unwrap();
172 }
173 });
174 if code == 0 || code == 1 {
176 code = 2;
177 }
178 code as usize
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 #[test]
185 fn it_works() {
186 let (secret, key) = "my very secret msg ÿ0".encrypt();
187 assert_eq!(secret.decrypt(key), "my very secret msg ÿ0");
188
189 let (secret, key) = 56516510.encrypt();
190 assert_eq!(secret.decrypt(key), "56516510");
191
192 let secret = "cool secret".encrypt_with_key(35413613);
193 assert_eq!(secret.decrypt(35413613), "cool secret");
194 }
195}