idea_algorithm 0.1.2

Pure Rust implementation of the idea algorithm
Documentation
//! Pure Rust implementation of the idea algorithm.

#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(clippy::many_single_char_names)]

#[warn(rustdoc::broken_intra_doc_links)]
#[allow(warnings)]
pub use cipher;
use cipher::{consts::U16, AlgorithmName, Key, KeyInit, KeySizeUser};
use core::fmt;

#[cfg(feature = "zeroize")]
use cipher::zeroize::{Zeroize, ZeroizeOnDrop};

/// The International Data Encryption Algorithm (IDEA) block cipher.
#[derive(Clone, Copy)]
pub struct Idea {
    pub enc_keys: [u16; 52],
    pub dec_keys: [u16; 52],
}

impl Idea {
    pub fn expand_key(&mut self, key: &Key<Self>) {
        let length_key = key.len();
        for i in 0..(length_key / 2) {
            self.enc_keys[i] = (u16::from(key[2 * i]) << 8) + u16::from(key[2 * i + 1]);
        }

        let mut a: u16;
        let mut b: u16;
        for i in (length_key / 2)..52 {
            if (i + 1) % 8 == 0 {
                a = self.enc_keys[i - 15];
            } else {
                a = self.enc_keys[i - 7];
            }

            if (i + 2) % 8 < 2 {
                b = self.enc_keys[i - 14];
            } else {
                b = self.enc_keys[i - 6];
            }

            self.enc_keys[i] = (a << 9) + (b >> 7);
        }
    }

    pub fn invert_sub_keys(&mut self) {
        let mut k = 8 * 6;
        for i in 0..=8 {
            let j = i * 6;
            let l = k - j;

            let (m, n) = if i > 0 && i < 8 { (2, 1) } else { (1, 2) };

            self.dec_keys[j] = self.mul_inv(self.enc_keys[l]);
            self.dec_keys[j + 1] = self.add_inv(self.enc_keys[l + m]);
            self.dec_keys[j + 2] = self.add_inv(self.enc_keys[l + n]);
            self.dec_keys[j + 3] = self.mul_inv(self.enc_keys[l + 3]);
        }

        k = (8 - 1) * 6;
        for i in 0..8 {
            let j = i * 6;
            let l = k - j;
            self.dec_keys[j + 4] = self.enc_keys[l + 4];
            self.dec_keys[j + 5] = self.enc_keys[l + 5];
        }
    }
    #[allow(warnings)]
    pub fn crypt(&self, block: Vec<u8>, sub_keys: &[u16; 52]) -> Vec<u8> {
        let b = block.clone();
        let mut x1 = u16::from_be_bytes(b[0..2].try_into().unwrap());
        let mut x2 = u16::from_be_bytes(b[2..4].try_into().unwrap());
        let mut x3 = u16::from_be_bytes(b[4..6].try_into().unwrap());
        let mut x4 = u16::from_be_bytes(b[6..8].try_into().unwrap());

        for i in 0..8 {
            let j = i * 6;
            let y1 = self.mul(x1, sub_keys[j]);
            let y2 = self.add(x2, sub_keys[j + 1]);
            let y3 = self.add(x3, sub_keys[j + 2]);
            let y4 = self.mul(x4, sub_keys[j + 3]);

            let t0 = self.mul(y1 ^ y3, sub_keys[j + 4]);
            let _t = self.add(y2 ^ y4, t0);
            let t1 = self.mul(_t, sub_keys[j + 5]);
            let t2 = self.add(t0, t1);

            x1 = y1 ^ t1;
            x2 = y3 ^ t1;
            x3 = y2 ^ t2;
            x4 = y4 ^ t2;
        }

        let y1 = self.mul(x1, sub_keys[48]);
        let y2 = self.add(x3, sub_keys[49]);
        let y3 = self.add(x2, sub_keys[50]);
        let y4 = self.mul(x4, sub_keys[51]);

        let mut block = block.clone();
        block[0..2].copy_from_slice(&y1.to_be_bytes());
        block[2..4].copy_from_slice(&y2.to_be_bytes());
        block[4..6].copy_from_slice(&y3.to_be_bytes());
        block[6..8].copy_from_slice(&y4.to_be_bytes());
        block
    }

    pub fn mul(&self, a: u16, b: u16) -> u16 {
        let x = u32::from(a);
        let y = u32::from(b);
        let mut r: i32;

        if x == 0 {
            r = (0x10001 - y) as i32;
        } else if y == 0 {
            r = (0x10001 - x) as i32;
        } else {
            let c: u32 = x * y;
            r = ((c & 0xffff) as i32) - ((c >> 16) as i32);
            if r < 0 {
                r += 0x10001 as i32;
            }
        }

        (r & (0xffff as i32)) as u16
    }

    pub fn add(&self, a: u16, b: u16) -> u16 {
        ((u32::from(a) + u32::from(b)) & 0xffff) as u16
    }

    pub fn mul_inv(&self, a: u16) -> u16 {
        if a <= 1 {
            a
        } else {
            let mut x = u32::from(a);
            let mut y = 0x10001;
            let mut t0 = 1u32;
            let mut t1 = 0u32;
            loop {
                t1 += y / x * t0;
                y %= x;
                if y == 1 {
                    return (0x10001 - t1) as u16;
                }
                t0 += x / y * t1;
                x %= y;
                if x == 1 {
                    return t0 as u16;
                }
            }
        }
    }

    pub fn add_inv(&self, a: u16) -> u16 {
        ((0x10000 - (u32::from(a))) & 0xffff) as u16
    }
}

// impl BlockCipher for Idea {}

impl KeySizeUser for Idea {
    type KeySize = U16;
}

impl KeyInit for Idea {
    fn new(key: &Key<Self>) -> Self {
        let mut cipher = Self {
            enc_keys: [0u16; 52],
            dec_keys: [0u16; 52],
        };
        cipher.expand_key(key);
        cipher.invert_sub_keys();
        cipher
    }
}

impl fmt::Debug for Idea {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Idea { ... }")
    }
}

impl AlgorithmName for Idea {
    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("Idea")
    }
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl Drop for Idea {
    fn drop(&mut self) {
        self.enc_keys.zeroize();
        self.dec_keys.zeroize();
    }
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl ZeroizeOnDrop for Idea {}

fn en(data: &[u8], key: &[u8]) -> Vec<u8> {
    let idea = Idea::new_from_slice(&key).unwrap();
    let en = idea.crypt(data.to_vec(), &idea.enc_keys);
    en
}
fn de(cipher: &[u8], key: &[u8]) -> Vec<u8> {
    let idea = Idea::new_from_slice(&key).unwrap();
    let de = idea.crypt(cipher.to_vec(), &idea.dec_keys);
    de
}
/// use encrypt() to encrypt data,the password key length must be equal to 16
/// ```rust
///use idea_algorithm::decrypt;
///use idea_algorithm::display_decrypt;
///use idea_algorithm::encrypt;
///let data = "I like rust,do't ask me why?".as_bytes();
///let key = "alen_andryalen_a".as_bytes();//key length must be equal to 16
///let enc = encrypt(data.to_vec(), key.to_vec());
///let dec = decrypt(enc.to_vec(), key.to_vec());
///assert_eq!(enc,vec![vec![227, 50, 135, 181, 96, 140, 192, 61],vec![14, 26, 91, 233, 40, 203, 211, 156],vec![25, 159, 71, 85, 37, 42, 209, 92],vec![202, 44, 159, 167, 57, 84, 106, 170, 150, 160, 226, 150, 160, 226, 150, 160]]);
///assert_eq!(display_decrypt(dec),format!("I like rust,do't ask me why?"));
/// ```
#[allow(warnings)]
pub fn encrypt(data: Vec<u8>, key: Vec<u8>) -> Vec<Vec<u8>> {
    let mut re = vec![];
    if data.len() == 8 {
        re.push(en(&data, &key));
    } else if data.len() < 8 {
        let mut new_data = data.clone().to_vec();
        for i in data.len()..=8 {
            new_data.extend_from_slice("â– ".as_bytes());
        }
        re.push(en(&new_data, &key));
    } else if data.len() > 8 {
        let mut new_data = data.clone().to_vec();
        let new_vec_list = new_data
            .chunks(8)
            .into_iter()
            .map(|s| {
                let mut re = s.clone().to_vec();
                let ss = s.clone();
                if ss.len() < 8 {
                    for i in re.len()..8 {
                        re.extend_from_slice("â– ".as_bytes());
                    }
                } else {
                    re = ss.to_vec();
                }
                re
            })
            .collect::<Vec<Vec<u8>>>();
        for item in new_vec_list {
            re.push(en(&item, &key));
        }
    }
    re
}
/// use decrypt() to decrypt encrypted data
/// ```rust
///use idea_algorithm::decrypt;
///use idea_algorithm::display_decrypt;
///use idea_algorithm::encrypt;
///let data = "I like rust,do't ask me why?".as_bytes();
///let key = "alen_andryalen_a".as_bytes();//key length must be equal to 16
///let enc = encrypt(data.to_vec(), key.to_vec());
///let dec = decrypt(enc.to_vec(), key.to_vec());
///assert_eq!(enc,vec![vec![227, 50, 135, 181, 96, 140, 192, 61],vec![14, 26, 91, 233, 40, 203, 211, 156],vec![25, 159, 71, 85, 37, 42, 209, 92],vec![202, 44, 159, 167, 57, 84, 106, 170, 150, 160, 226, 150, 160, 226, 150, 160]]);
///assert_eq!(display_decrypt(dec),format!("I like rust,do't ask me why?"));
/// ```
#[allow(warnings)]
pub fn decrypt(cipher_vec: Vec<Vec<u8>>, key: Vec<u8>) -> Vec<Vec<u8>> {
    let mut re = vec![];
    for cipher in cipher_vec {
        let ss = de(&cipher, &key).into_iter().collect::<Vec<u8>>();
        let sss = String::from_utf8_lossy(&ss).to_string();
        let ssss = sss
            .split("â– ")
            .filter(|s| !s.is_empty())
            .into_iter()
            .collect::<Vec<_>>();
        re.push(
            ssss.join("")
                .chars()
                .into_iter()
                .map(|s| s as u8)
                .collect::<Vec<u8>>(),
        );
    }
    re
}
/// use display_decrypt() to print decrypted code
/// ```rust
///use idea_algorithm::decrypt;
///use idea_algorithm::display_decrypt;
///use idea_algorithm::encrypt;
///let data = "I like rust,do't ask me why?".as_bytes();
///let key = "alen_andryalen_a".as_bytes();//key length must be equal to 16
///let enc = encrypt(data.to_vec(), key.to_vec());
///let dec = decrypt(enc.to_vec(), key.to_vec());
///assert_eq!(enc,vec![vec![227, 50, 135, 181, 96, 140, 192, 61],vec![14, 26, 91, 233, 40, 203, 211, 156],vec![25, 159, 71, 85, 37, 42, 209, 92],vec![202, 44, 159, 167, 57, 84, 106, 170, 150, 160, 226, 150, 160, 226, 150, 160]]);
///assert_eq!(display_decrypt(dec),format!("I like rust,do't ask me why?"));
/// ```
pub fn display_decrypt(dec_data: Vec<Vec<u8>>) -> String {
    let mut re = String::new();
    for item in &dec_data {
        re.push_str(&String::from_utf8_lossy(item));
    }
    re
}

/// use encrypt_file() to encrypt file
/// ```rust
///use idea_algorithm::decrypt;
///use idea_algorithm::display_decrypt;
///use idea_algorithm::encrypt;
///let data = "I like rust,do't ask me why?".as_bytes();
///let key = "alen_andryalen_a".as_bytes();//key length must be equal to 16
///let enc = encrypt(data.to_vec(), key.to_vec());
///let dec = decrypt(enc.to_vec(), key.to_vec());
///assert_eq!(enc,vec![vec![227, 50, 135, 181, 96, 140, 192, 61],vec![14, 26, 91, 233, 40, 203, 211, 156],vec![25, 159, 71, 85, 37, 42, 209, 92],vec![202, 44, 159, 167, 57, 84, 106, 170, 150, 160, 226, 150, 160, 226, 150, 160]]);
///assert_eq!(display_decrypt(dec),format!("I like rust,do't ask me why?"));
/// ```
#[allow(warnings)]
fn encrypt_file(file_path: &str, key: Vec<u8>) {
    use std::fs;
    let data = fs::read(file_path).unwrap();
    // println!("{:?}", data);
    let enc = encrypt(data.to_vec(), key.to_vec());
    println!(
        "{:?}",
        enc.clone().into_iter().map(|s| s.len()).collect::<Vec<_>>()
    );
    let mut new_enc = vec![];
    for i in enc {
        for j in i {
            new_enc.push(j);
        }
    }
    // println!("{:?}", new_enc);
    // fs::write(file_path, &new_enc).unwrap();
}

/// use decrypt_file() to decrypt file
/// ```rust
///use idea_algorithm::decrypt;
///use idea_algorithm::display_decrypt;
///use idea_algorithm::encrypt;
///let data = "I like rust,do't ask me why?".as_bytes();
///let key = "alen_andryalen_a".as_bytes();//key length must be equal to 16
///let enc = encrypt(data.to_vec(), key.to_vec());
///let dec = decrypt(enc.to_vec(), key.to_vec());
///assert_eq!(enc,vec![vec![227, 50, 135, 181, 96, 140, 192, 61],vec![14, 26, 91, 233, 40, 203, 211, 156],vec![25, 159, 71, 85, 37, 42, 209, 92],vec![202, 44, 159, 167, 57, 84, 106, 170, 150, 160, 226, 150, 160, 226, 150, 160]]);
///assert_eq!(display_decrypt(dec),format!("I like rust,do't ask me why?"));
/// ```
#[allow(warnings)]
fn decrypt_file(file_path: &str, key: Vec<u8>) {
    use std::fs;
    let data = fs::read(file_path).unwrap();

    // let data_string = format!("{:?}", data);
    // println!("{:?}", data_string);
    // let s_enc = String::from_utf8_lossy(&data).to_string();
    // println!("{:?}", s_enc);

    // let enc = parse_u8(data_string);
    // println!("{:?}", enc);
    let enc = data
        .chunks(8)
        .into_iter()
        .map(|s| s.to_vec())
        .collect::<Vec<Vec<u8>>>();
    println!("{:?}", enc.into_iter().map(|s| s.len()).collect::<Vec<_>>());
    // let dec = decrypt(enc.to_vec(), key.to_vec());
    // let dec_string = format!("{:?}", dec);
    // println!(
    //     "{:?}",
    //     dec_string
    //         .split("226, 150, 160")
    //         .into_iter()
    //         .map(|s| s)
    //         .collect::<Vec<_>>()
    // )
    // fs::write(file_path, &new_dec).unwrap();
    // let dec_string = display_decrypt(dec.to_owned());
    // println!("{:?}", dec_string);
}
#[allow(warnings)]
fn parse_u8(v: String) -> Vec<Vec<u8>> {
    v.split("226, 150, 160")
        .filter(|s| !s.is_empty())
        .map(|s| {
            s.split(",")
                .into_iter()
                .filter(|s| !s.is_empty())
                .map(|s| s.to_string().parse::<u8>().unwrap())
                .collect::<Vec<u8>>()
        })
        .collect::<Vec<Vec<u8>>>()
}