basecracker 0.1.0

Encode, Decode and Crack encoded data, useful to crack some random encoded strings in CTFs.
Documentation
pub use rug::Integer;
use std::cmp;

pub trait PackedBy<T> {
    fn packed_by(&self, len: usize) -> Vec<T>;
}

impl PackedBy<String> for &str {
    fn packed_by(&self, len: usize) -> Vec<String> {
        let mut result = Vec::new();
        for i in (0..self.len()).step_by(len) {
            result.push(self[i..cmp::min(i + len, self.len())].to_string());
        }
        result
    }
}

pub fn str_to_int(s: &str, mult: u32) -> Integer {
    let mut result = Integer::from(0);
    for c in s.chars() {
        result = result * mult + Integer::from(c as u32);
    }
    result
}

pub fn int_to_str(n: &Integer, mult: u32) -> String {
    let mut result = String::new();
    let mut tmp_n = n.clone();
    while tmp_n > Integer::from(0) {
        let (q, r) = tmp_n.div_rem(Integer::from(mult));
        result.push(r.to_i32().unwrap() as u8 as char);
        tmp_n = q;
    }
    result.chars().rev().collect()
}

pub fn to_base(n: &Integer, base: &str, block_size: impl Into<Option<usize>>) -> String {
    let block_size = block_size.into().unwrap_or(1);

    let mut result = String::new();
    let mut n = n.clone();
    while n > Integer::from(0) {
        let (q, r) = n.div_rem(Integer::from(base.len()));
        result.push(base.chars().nth(r.to_usize().unwrap()).unwrap());
        n = q;
    }
    if result.len() % block_size != 0 {
        result.push_str(&base[0..1].repeat(block_size - result.len() % block_size));
    }
    result.chars().rev().collect()
}

pub fn from_base(s: &str, base: &str) -> Result<Integer, &'static str> {
    let mut result = Integer::from(0);
    let mut power = Integer::from(1);
    for c in s.chars().rev() {
        let index = base.find(c).ok_or("Invalid base")?;
        result += &power * &Integer::from(index);
        power *= Integer::from(base.len());
    }
    Ok(result)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_str_packed_by_3_1() {
        let s = "abcdef";
        let result = s.packed_by(3);
        assert_eq!(result.len(), 2);
        assert_eq!(result[0], "abc");
        assert_eq!(result[1], "def");
    }

    #[test]
    fn test_str_packed_by_3_2() {
        let s = "abcdefg";
        let result = s.packed_by(3);
        assert_eq!(result.len(), 3);
        assert_eq!(result[0], "abc");
        assert_eq!(result[1], "def");
        assert_eq!(result[2], "g");
    }

    #[test]
    fn test_str_packed_by_3_3() {
        let s = "abcdefgh";
        let result = s.packed_by(3);
        assert_eq!(result.len(), 3);
        assert_eq!(result[0], "abc");
        assert_eq!(result[1], "def");
        assert_eq!(result[2], "gh");
    }

    #[test]
    fn test_to_integer_1() {
        let result = str_to_int("Hello World!", 256);
        assert_eq!(result, Integer::from(22405534230753928650781647905 as u128));
    }

    #[test]
    fn test_to_integer_2() {
        let result = str_to_int("BaseCracker", 256);
        assert_eq!(result, Integer::from(80249302315773941590484338 as u128));
    }

    #[test]
    fn test_to_string_1() {
        let result = int_to_str(&Integer::from(22405534230753928650781647905 as u128), 256);
        assert_eq!(result, "Hello World!");
    }

    #[test]
    fn test_to_string_2() {
        let result = int_to_str(&Integer::from(80249302315773941590484338 as u128), 256);
        assert_eq!(result, "BaseCracker");
    }

    #[test]
    fn test_to_base_2_1() {
        let n = Integer::from(
            0b0110000101100010011000110110010001100101011001100110111001101110 as u64,
        );
        let base = "01".to_string();
        let result = to_base(&n, &base, None);
        assert_eq!(
            result,
            "110000101100010011000110110010001100101011001100110111001101110"
        );
    }
    #[test]
    fn test_to_base_2_2() {
        let n = Integer::from(
            0b0110000101100010011000110110010001100101011001100110111001101110 as u64,
        );
        let base = "01".to_string();
        let result = to_base(&n, &base, 8);
        assert_eq!(
            result,
            "0110000101100010011000110110010001100101011001100110111001101110"
        );
    }

    #[test]
    fn test_to_base_16() {
        let n = Integer::from(0x48656c6c6f20576f726c6421 as u128);
        let base = "0123456789abcdef".to_string();
        let result = to_base(&n, &base, 8);
        assert_eq!(result, "48656c6c6f20576f726c6421");
    }

    #[test]
    fn test_from_base_2_1() {
        let s = "110000101100010011000110110010001100101011001100110111001101110".to_string();
        let base = "01".to_string();
        let result = from_base(&s, &base);
        assert_eq!(
            result,
            Ok(Integer::from(
                0b0110000101100010011000110110010001100101011001100110111001101110 as u64
            ))
        );
    }

    #[test]
    fn test_from_base_2_2() {
        let s = "0110000101100010011000110110010001100101011001100110111001101110".to_string();
        let base = "01".to_string();
        let result = from_base(&s, &base);
        assert_eq!(
            result,
            Ok(Integer::from(
                0b0110000101100010011000110110010001100101011001100110111001101110 as u64
            ))
        );
    }

    #[test]
    fn test_from_base_16() {
        let s = "48656c6c6f20576f726c6421".to_string();
        let base = "0123456789abcdef".to_string();
        let result = from_base(&s, &base);
        assert_eq!(
            result,
            Ok(Integer::from(0x48656c6c6f20576f726c6421 as u128))
        );
    }
}