rsacracker 0.8.0

Powerful RSA cracker for CTFs. Supports RSA, X509, OPENSSH in PEM and DER formats.
Documentation
use rug::{
    ops::{DivRounding, Pow},
    Integer,
};

pub fn rational_to_contfrac(x: &Integer, y: &Integer) -> Vec<Integer> {
    let a = x.clone().div_floor(y);

    if a.clone() * y == *x {
        vec![a]
    } else {
        let mut pquotients = rational_to_contfrac(y, &(x - a.clone() * y));
        pquotients.insert(0, a);
        pquotients
    }
}

pub fn contfrac_to_rational(frac: &[Integer]) -> (Integer, Integer) {
    if frac.is_empty() {
        (0.into(), 1.into())
    } else if frac.len() == 1 {
        (frac[0].clone(), 1.into())
    } else {
        let remainder = frac[1..frac.len()].to_vec();
        let (num, denom) = contfrac_to_rational(&remainder);
        (frac[0].clone() * num.clone() + denom, num)
    }
}

#[allow(dead_code)]
pub fn convergents_from_contfrac(frac: &[Integer]) -> Vec<(Integer, Integer)> {
    let mut convs = Vec::new();

    for i in 0..frac.len() {
        convs.push(contfrac_to_rational(&frac[0..i]));
    }
    convs
}

pub fn trivial_factorization_with_n_phi(n: &Integer, phi: &Integer) -> Option<(Integer, Integer)> {
    let m = n.clone() - phi.clone() + Integer::from(1);
    let m2n2 = m.clone().pow(2) - Integer::from(n << 2);

    if m2n2 > 0 {
        let (i, _) = m2n2.sqrt_rem(Integer::new());
        let roots: (Integer, Integer) = ((m.clone() - i.clone()) >> 1, (m + i) >> 1);

        if roots.0.clone() * roots.1.clone() == *n {
            return Some(roots);
        }
    }
    None
}

pub fn crt(residues: &[Integer], modulli: &[Integer]) -> Option<Integer> {
    let prod = modulli.iter().product::<Integer>();
    let mut sum = Integer::ZERO;

    for (residue, modulus) in residues.iter().zip(modulli) {
        let p = prod.clone() / modulus;
        sum += residue * Integer::from(p.invert_ref(modulus)?) * p
    }

    Some(sum % prod)
}

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

    #[test]
    fn chinese_remainder_theorem() {
        assert_eq!(
            crt(
                &[3.into(), 5.into(), 7.into()],
                &[2.into(), 3.into(), 1.into()]
            ),
            Some(Integer::from(5))
        );
        assert_eq!(
            crt(
                &[1.into(), 4.into(), 6.into()],
                &[3.into(), 5.into(), 7.into()]
            ),
            Some(Integer::from(34))
        );
        assert_eq!(
            crt(
                &[1.into(), 4.into(), 6.into()],
                &[1.into(), 2.into(), 0.into()]
            ),
            None
        );
        assert_eq!(
            crt(
                &[2.into(), 5.into(), 7.into()],
                &[6.into(), 9.into(), 15.into()]
            ),
            None
        );
    }
}