#![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};
#[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 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
}
#[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
}
#[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
}
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
}
#[allow(warnings)]
fn encrypt_file(file_path: &str, key: Vec<u8>) {
use std::fs;
let data = fs::read(file_path).unwrap();
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);
}
}
}
#[allow(warnings)]
fn decrypt_file(file_path: &str, key: Vec<u8>) {
use std::fs;
let data = fs::read(file_path).unwrap();
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<_>>());
}
#[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>>>()
}