secret_msg/
lib.rs

1//! # Secret Message
2//!
3//! Simple way to encrypt a message (No security whatsoever!!!)
4//!
5//! This crate exposes **SecretMessage** trait:
6//!
7//! encrypt and decrypt a messge:
8//!
9//! **encrypt** and **decrypt**:
10//!
11//! ```rust
12//! use secret_msg::SecretMessage;
13//!
14//! let (secret, key) = "my_secret!".encrypt();
15//! assert_eq!(secret.decrypt(key), "my_secret!");
16//! let (secret, key) = 1234.encrypt();
17//! assert_eq!(secret.decrypt(key), "1234");
18//! ```
19//!
20//! or use a custom key:
21//!
22//! ```rust
23//! use secret_msg::SecretMessage;
24//! let secret = "cool secret".encrypt_with_key(58794);
25//! assert_eq!(secret.decrypt(58794), "cool secret");
26//! ```
27//! encrypt a message with no easy way to retrieve it back:
28//!
29//! **one_way_encrypt**:
30//!
31//! ```rust
32//! use secret_msg::SecretMessage;
33//!
34//! let cipher = "my_secret!".one_way_encrypt();
35//! assert_eq!(cipher, "1537");
36//! let cipher = 158721.one_way_encrypt();
37//! assert_eq!(cipher, "2361");
38//! ```
39
40use rand::seq::SliceRandom;
41use rand::thread_rng;
42
43enum EncMethod {
44    INC,
45    DEC,
46    TIME,
47}
48
49impl EncMethod {
50    //XXX Check fns when adding methods
51    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    /// encrypt a msg with no easy way to get the original back
79    fn one_way_encrypt(&self) -> String;
80
81    /// encrypt a msg with a given key
82    fn encrypt_with_key(&self, key: usize) -> String;
83
84    /// encrypt a msg -> returns an encrytped msg and a decrypt key
85    fn encrypt(&self) -> (String, usize);
86
87    /// decrypt a msg using decrypt key
88    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
140// Char Move Crypto
141fn 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
149// Time Crypto
150fn enc_time(c: char, key: usize) -> char {
151    // handle add with overflow
152    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    // handle subtract with overflow
157    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
165// helper fns
166fn 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    // hmm
175    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}