diff --git a/src/main.rs b/src/main.rs index 1bb6886..5f58c13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ mod lfsr; +mod period; mod tea3; use lfsr::Lfsr; -use tea3::{Tea3, period_floyd}; +use period::{period_bruteforce, period_floyd, period_paper}; +use tea3::Tea3; fn main() { let mut lfsr = Lfsr::new(4, vec![0, 3], vec![0x12, 0x34, 0x56, 0x78]); @@ -47,5 +49,8 @@ fn main() { println!("Decrypted : {:?}", decrypted); - // println!("\nperiod: {}", period_floyd(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0], vec![0; 8])); + println!( + "\nPaper period: {}", + period_paper(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + ); } diff --git a/src/period.rs b/src/period.rs new file mode 100644 index 0000000..675095f --- /dev/null +++ b/src/period.rs @@ -0,0 +1,163 @@ +use std::collections::HashMap; + +use crate::tea3::Tea3; + +/// period brute force with hashmap +pub fn period_bruteforce(key: Vec, iv: Vec) -> u64 { + let mut cipher = Tea3::new(key, iv); + cipher.init(); + + let mut seen = HashMap::new(); + let mut step: u64 = 0; + + loop { + let state = ( + cipher.key_register().to_vec(), + cipher.state_register().to_vec(), + ); + + if let Some(prev) = seen.get(&state) { + return step - prev; + } + + seen.insert(state, step); + + cipher.step(); + step += 1; + } +} + +/// period brute force with Floyd tortoise and hare algorithm +pub fn period_floyd(key: Vec, iv: Vec) -> u64 { + let mut tortoise = Tea3::new(key.clone(), iv.clone()); + let mut hare = Tea3::new(key, iv); + + tortoise.init(); + hare.init(); + + tortoise.step(); + hare.step(); + hare.step(); + + while (tortoise.key_register(), tortoise.state_register()) + != (hare.key_register(), hare.state_register()) + { + tortoise.step(); + hare.step(); + hare.step(); + } + + let mut lambda = 1; + hare.step(); + + while (tortoise.key_register(), tortoise.state_register()) + != (hare.key_register(), hare.state_register()) + { + hare.step(); + lambda += 1; + } + + lambda +} + +// paper method, decomposition key register +// (Observations on TETRA Encryption Algorithm TEA-3) +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Reg5([u8; 5]); + +impl Reg5 { + fn step_h(&mut self) -> u8 { + let out = self.0[0]; + let feedback = out ^ Tea3::p(self.0[2]); + + self.0.copy_within(1..5, 0); + self.0[4] = feedback; + + out + } + + fn step_g(&mut self, h_out: u8) -> u8 { + let out = self.0[0]; + let feedback = out ^ h_out; + + self.0.copy_within(1..5, 0); + self.0[4] = feedback; + + out + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct Decomposed { + g: Reg5, + h: Reg5, +} + +impl Decomposed { + fn from_key(key: &[u8]) -> Self { + Self { + g: Reg5([key[0], key[1], key[2], key[3], key[4]]), + h: Reg5([ + key[0] ^ key[5], + key[1] ^ key[6], + key[2] ^ key[7], + key[3] ^ key[8], + key[4] ^ key[9], + ]), + } + } + + fn step(&mut self) -> u8 { + let h_out = self.h.step_h(); + self.g.step_g(h_out) + } +} + +fn period_h(start: Reg5) -> u64 { + let mut tortoise = start; + let mut hare = start; + + tortoise.step_h(); + hare.step_h(); + hare.step_h(); + + while tortoise != hare { + tortoise.step_h(); + hare.step_h(); + hare.step_h(); + } + + let mut lambda = 1; + hare.step_h(); + + while tortoise != hare { + hare.step_h(); + lambda += 1; + } + + lambda +} + +/// paper method, decomposition key register +/// (Observations on TETRA Encryption Algorithm TEA-3) +pub fn period_paper(key: Vec) -> u64 { + let start = Decomposed::from_key(&key); + + let p = period_h(start.h); + + for mult in [1u64, 2, 5, 10] { + let target = p * mult; + + let mut cur = start; + + for _ in 0..target { + cur.step(); + } + + if cur == start { + return target; + } + } + + panic!("No valid period found"); +} diff --git a/src/tea3.rs b/src/tea3.rs index 307e129..a2e4558 100644 --- a/src/tea3.rs +++ b/src/tea3.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - #[derive(Debug, Clone)] pub struct Tea3 { /// Cipher key register k0..k9 @@ -207,65 +205,6 @@ fn bp(x: u8) -> u8 { | bit(5) } -pub fn period(key: Vec, iv: Vec) -> u64 { - let mut cipher = Tea3::new(key, iv); - cipher.init(); - - let mut seen = HashMap::new(); - - let mut step: u64 = 0; - - loop { - let state = ( - cipher.key_register().to_vec(), - cipher.state_register().to_vec(), - ); - - if let Some(prev) = seen.get(&state) { - return step - prev; - } - - seen.insert(state, step); - - cipher.step(); - step += 1; - } -} - -pub fn period_floyd(key: Vec, iv: Vec) -> u64 { - let mut tortoise = Tea3::new(key.clone(), iv.clone()); - let mut hare = Tea3::new(key, iv); - - tortoise.init(); - hare.init(); - - // Move tortoise by 1, hare by 2 - tortoise.step(); - hare.step(); - hare.step(); - - while tortoise.key_register() != hare.key_register() - || tortoise.state_register() != hare.state_register() - { - tortoise.step(); - - hare.step(); - hare.step(); - } - - let mut lambda = 1; - hare.step(); - - while tortoise.key_register() != hare.key_register() - || tortoise.state_register() != hare.state_register() - { - hare.step(); - lambda += 1; - } - - lambda -} - #[cfg(test)] mod tests { use super::*; @@ -470,7 +409,6 @@ mod tests { let poly = Lfsr::berlekamp_massey(&keystream); - let history = &keystream[keystream.len() - (poly.len() - 1)..]; let predicted = Lfsr::predict_next_from_poly(history, &poly);