cifra/cipher/
affine.rs

1/// Library to cipher and decipher texts using Affine method.
2use std::convert::TryInto;
3// use std::fmt;
4use std::fmt::{Display, Formatter};
5
6use rand;
7
8use crate::{Result, ErrorKind, ResultExt};
9use crate::attack::simple_attacks::Parameters;
10use crate::cipher::common::{offset_text, Ciphers, DEFAULT_CHARSET, get_key_parts};
11use crate::cipher::cryptomath::gcd;
12use rand::Rng;
13
14
15#[derive(Debug, Copy, Clone)]
16enum WrongAffineKeyCauses {
17    MultiplyingKeyBelowZero,
18    MultiplyingKeyZero,
19    AddingKeyBelowZero,
20    AddingKeyTooLong,
21    KeysNotRelativelyPrime
22}
23
24impl Display for WrongAffineKeyCauses {
25    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
26        let message = match self {
27            WrongAffineKeyCauses::MultiplyingKeyBelowZero=> "Multiplying key must be greater than 0.",
28            WrongAffineKeyCauses::MultiplyingKeyZero=> "Multiplying key must not be 0.",
29            WrongAffineKeyCauses::AddingKeyBelowZero=> "Adding key must be greater than 0.",
30            WrongAffineKeyCauses::AddingKeyTooLong=> "Adding key must be smaller than charset length.",
31            WrongAffineKeyCauses::KeysNotRelativelyPrime=> "Keys are not relatively prime."
32        };
33        write!(f, "{}", message)
34    }
35}
36
37#[derive(Debug)]
38pub struct WrongAffineKey {
39    key: usize,
40    multiplying_key: usize,
41    adding_key: usize,
42    cause: WrongAffineKeyCauses
43}
44
45impl WrongAffineKey {
46
47    fn new(key: usize, cause: WrongAffineKeyCauses, charset_length: usize) -> Self {
48        let (multiplying_key, adding_key) = get_key_parts(key, charset_length);
49        WrongAffineKey {
50            key,
51            multiplying_key,
52            adding_key,
53            cause
54        }
55    }
56}
57
58impl Display for WrongAffineKey {
59    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60        write!(f, "Wrong key: {} key decomposes to {} as multiplicative key and {} as adding key, \
61        but problem is {}", self.key, self.multiplying_key, self.adding_key, self.cause)
62    }
63}
64
65/// Cipher given text using Affine method.
66///
67///  Be aware that different languages use different charsets. Default charset
68/// is for english language, if you are using any other you should use a proper
69/// dataset. For instance, if you are ciphering an spanish text, you should use
70/// a charset with "ñ" character.
71///
72/// Not every key is good to cipher using Affine with a given charset. It must
73/// meet a set of rules. So we must check given key meets them.
74///
75/// If given key does not meet any of the rules them a WrongKey exception is raised.
76///
77/// # Parameters:
78/// * text: Text to be ciphered.
79/// * key: Secret key. Both ends should know this and use the same one.
80/// * charset: Charset used for Affine method substitution. Both ends, ciphering
81///     and deciphering, should use the same charset or original text won't be properly
82///     recovered.
83///
84/// # Returns:
85/// * Ciphered text.
86// pub fn cipher<T, U>(text: T, key: usize, charset: U)-> Result<String>
87//     where T: AsRef<str>,
88//           U: AsRef<str> {
89pub fn cipher(text: &str, key: usize, charset: &str)-> Result<String> {
90    validate_key(key, charset.len())?;
91    let ciphered_text = offset_text(text, key, true, &Ciphers::AFFINE, DEFAULT_CHARSET);
92    ciphered_text
93}
94
95/// Decipher given text using Affine method.
96///
97/// Note you should use the same charset that ciphering end did.
98///
99/// # Parameters:
100/// * ciphered_text: Text to be deciphered.
101/// * key: Secret key. Both ends should know this and use the same one.
102/// * charset: Charset used for Affine method substitutions. Both end should
103///     use the same charset or original text won't be properly recovered.
104///
105/// # Returns:
106/// * Deciphered text.
107// pub fn decipher<T, U>(ciphered_text: T, key: usize, charset: U)-> Result<String>
108//     where T: AsRef<str>,
109//           U: AsRef<str> {
110pub fn decipher(ciphered_text: &str, key: usize, charset: &str)-> Result<String> {
111    validate_key(key, charset.len())?;
112    let deciphered_text = offset_text(ciphered_text, key, false, &Ciphers::AFFINE, charset);
113    deciphered_text
114}
115
116
117/// Call decipher function using a Parameters type.
118///
119/// You probably wont use this function. It's used by brute force attacks instead.
120///
121/// # Parameters:
122/// * parameters: Parameters stored in a Parameters type. It should include next keys-values:
123///     * ciphered_text (str): Text to be deciphered.
124///     * key (usize): Secret key. In Affine method, and for deciphering end, it correspond
125///         with how many position get bat in the charset. Both ends should know this and
126///         use the same one.
127///     * charset (str): Charset used for Affine method substitutions. Both end should
128///         use the same charset or original text won't be properly recovered.
129///
130/// # Returns:
131/// * Deciphered text.
132pub fn decipher_par(parameters: &Parameters)-> Result<String> {
133    let ciphered_text = parameters.get_str("ciphered_text")?;
134    let charset = parameters.get_str("charset")?;
135    let key = parameters.get_int("key")?;
136    decipher(ciphered_text.as_str(), key, charset.as_str())
137}
138
139/// Get a valid random Affine key for given charset.
140///
141/// Get manually a valid Affine key can be hardsome because all rules it must meet.
142/// This function automates that task, so you can use it and run.
143///
144/// # Parameters:
145/// * charset: Charset you are going to use to cipher.
146///
147/// # Returns:
148/// * An random Affine key valid for given charset.
149pub fn get_random_key<T>(charset: T)-> Result<usize>
150    where T: AsRef<str>{
151    let charset_length = charset.as_ref().len();
152    let charset_length_isize: isize = charset_length.try_into()
153        .chain_err(|| ErrorKind::ConversionError("charset_length", "usize", "isize"))?;
154    let mut rng = rand::thread_rng();
155    loop {
156        let key_a = rng.gen_range(2, charset_length_isize);
157        let key_b = rng.gen_range(2, charset_length_isize);
158        if gcd(key_a, charset_length_isize) == 1 {
159            return Ok((key_a as usize) * charset_length + (key_b as usize))
160        }
161    }
162}
163
164/// Check if given key is good for Affine cipher using this charset.
165///
166/// Not every key is good to cipher using Affine with a given charset. It must
167/// meet a set of rules. So we must check given key meets them.
168///
169/// If given key does not meet any of the rules them a WrongKey exception is raised.
170///
171/// # Parameters:
172/// * key: Secret key. Both ends should know this and use the same one.
173/// * charset_length: Charset used for Affine method substitutions. Both end should
174///     use the same charset or original text won't be properly recovered.
175///
176/// # Returns:
177/// * True if validation was right. You won't receive a False, an exception will be raised before.
178pub fn validate_key(key: usize, charset_length: usize)-> Result<bool> {
179    let multiplying_key = key / charset_length;
180    let adding_key = key % charset_length;
181    if multiplying_key == 0 {
182        bail!(ErrorKind::WrongAffineKeyError(
183            WrongAffineKey::new(key, WrongAffineKeyCauses::MultiplyingKeyZero, charset_length)
184            ));
185    } else if adding_key > charset_length -1 {
186        bail!(ErrorKind::WrongAffineKeyError(
187            WrongAffineKey::new(key, WrongAffineKeyCauses::AddingKeyTooLong, charset_length)
188            ));
189    } else if gcd(multiplying_key.try_into().chain_err(|| ErrorKind::ConversionError("multiplying_key", "usize", "isize"))?,
190                  charset_length.try_into().chain_err(|| ErrorKind::ConversionError("charset_length", "usize", "isize"))?) != 1 {
191        bail!(ErrorKind::WrongAffineKeyError(
192            WrongAffineKey::new(key, WrongAffineKeyCauses::KeysNotRelativelyPrime, charset_length)
193            ));
194    }
195    Ok(true)
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201
202    use test_common::random::strings::random_string;
203
204    use crate::cipher::common::DEFAULT_CHARSET;
205
206    const ORIGINAL_MESSAGE: &'static str = "A computer would deserve to be called intelligent if it could deceive a human into believing that it was human.\" Alan Turing";
207    const CIPHERED_MESSAGE_KEY_2894: &'static str = "5QG9ol3La6QI93!xQxaia6faQL9QdaQG1!!axQARLa!!AuaRLQADQALQG93!xQxaGaAfaQ1QX3o1RQARL9Qda!AafARuQLX1LQALQI1iQX3o1RN\"Q5!1RQP36ARu";
208    const TEST_KEY: usize = 2894;
209
210    #[test]
211    fn test_cipher() {
212        let ciphered_text = cipher(ORIGINAL_MESSAGE, TEST_KEY, DEFAULT_CHARSET).expect("Error getting ciphered text.");
213        assert_eq!(CIPHERED_MESSAGE_KEY_2894, ciphered_text);
214    }
215
216    #[test]
217    fn test_decipher() {
218        let deciphered_text = decipher(CIPHERED_MESSAGE_KEY_2894, TEST_KEY, DEFAULT_CHARSET).unwrap();
219        assert_eq!(ORIGINAL_MESSAGE, deciphered_text);
220    }
221
222    #[test]
223    fn test_get_random_key() {
224        let test_string = random_string(10);
225        let key = get_random_key(DEFAULT_CHARSET).unwrap();
226        assert!(validate_key(key, DEFAULT_CHARSET.len()).unwrap());
227        let ciphered_test_string = cipher(&test_string, key, DEFAULT_CHARSET).expect("Error getting ciphered text.");
228        let recovered_string = decipher(ciphered_test_string.as_str(), key, DEFAULT_CHARSET).unwrap();
229        assert_eq!(test_string, recovered_string);
230    }
231}