diff --git a/src/ecb.rs b/src/ecb.rs index 8f0cd16..ff80d6f 100644 --- a/src/ecb.rs +++ b/src/ecb.rs @@ -1,50 +1,18 @@ +use crate::ecb_impl; use byteorder::{ByteOrder, BE}; -// Tencent chooses 16 rounds instead of traditional 32 rounds. -const ROUNDS: u32 = 16; -const DELTA: u32 = 0x9e3779b9; - -/// Perform a single round of encrypting/decrypting wrapping arithmetics -fn ecb_single_round(value: u32, sum: u32, key1: u32, key2: u32) -> u32 { - let left = value.wrapping_shl(4).wrapping_add(key1); - let right = value.wrapping_shr(5).wrapping_add(key2); - let mid = sum.wrapping_add(value); - - left ^ mid ^ right -} - /// Perform a 16 round TEA ECB encryption. -pub fn encrypt(block: &mut [u8; 8], k: &[u32; 4]) { - let mut y = BE::read_u32(&block[..4]); - let mut z = BE::read_u32(&block[4..]); - let mut sum = 0_u32; - - for _ in 0..ROUNDS { - sum = sum.wrapping_add(DELTA); - - y = y.wrapping_add(ecb_single_round(z, sum, k[0], k[1])); - z = z.wrapping_add(ecb_single_round(y, sum, k[2], k[3])); - } - - BE::write_u32(&mut block[..4], y); - BE::write_u32(&mut block[4..], z); +pub fn encrypt(block: &mut [u8; 8], key: &[u32; 4]) { + let state = BE::read_u64(block); + let state = ecb_impl::encrypt(state, key); + BE::write_u64(block, state); } /// Perform a 16 round TEA ECB decryption. pub fn decrypt(block: &mut [u8; 8], key: &[u32; 4]) { - let mut y = BE::read_u32(&block[..4]); - let mut z = BE::read_u32(&block[4..]); - let mut sum = DELTA.wrapping_mul(ROUNDS); - - for _ in 0..ROUNDS { - z = z.wrapping_sub(ecb_single_round(y, sum, key[2], key[3])); - y = y.wrapping_sub(ecb_single_round(z, sum, key[0], key[1])); - - sum = sum.wrapping_sub(DELTA); - } - - BE::write_u32(&mut block[..4], y); - BE::write_u32(&mut block[4..], z); + let state = BE::read_u64(block); + let state = ecb_impl::decrypt(state, key); + BE::write_u64(block, state); } #[cfg(test)] diff --git a/src/ecb_impl.rs b/src/ecb_impl.rs new file mode 100644 index 0000000..d8b5fc7 --- /dev/null +++ b/src/ecb_impl.rs @@ -0,0 +1,52 @@ +// Tencent chooses 16 rounds instead of traditional 32 rounds. +const ROUNDS: u32 = 16; +const DELTA: u32 = 0x9e3779b9; + +/// Perform a single round of encrypting/decrypting wrapping arithmetics +fn ecb_single_round(value: u32, sum: u32, key1: u32, key2: u32) -> u32 { + let left = value.wrapping_shl(4).wrapping_add(key1); + let right = value.wrapping_shr(5).wrapping_add(key2); + let mid = sum.wrapping_add(value); + + left ^ mid ^ right +} + +fn parse_tea_u64(state: u64) -> (u32, u32) { + let y = (state >> 32) as u32; + let z = state as u32; + (y, z) +} + +fn make_tea_u64(y: u32, z: u32) -> u64 { + (y as u64) << 32 | (z as u64) +} + +/// Perform a 16 round TEA ECB encryption. +pub fn encrypt(block: u64, key: &[u32; 4]) -> u64 { + let (mut y, mut z) = parse_tea_u64(block); + let mut sum = 0_u32; + + for _ in 0..ROUNDS { + sum = sum.wrapping_add(DELTA); + + y = y.wrapping_add(ecb_single_round(z, sum, key[0], key[1])); + z = z.wrapping_add(ecb_single_round(y, sum, key[2], key[3])); + } + + make_tea_u64(y, z) +} + +/// Perform a 16 round TEA ECB decryption. +pub fn decrypt(block: u64, key: &[u32; 4]) -> u64 { + let (mut y, mut z) = parse_tea_u64(block); + let mut sum = DELTA.wrapping_mul(ROUNDS); + + for _ in 0..ROUNDS { + z = z.wrapping_sub(ecb_single_round(y, sum, key[2], key[3])); + y = y.wrapping_sub(ecb_single_round(z, sum, key[0], key[1])); + + sum = sum.wrapping_sub(DELTA); + } + + make_tea_u64(y, z) +} diff --git a/src/lib.rs b/src/lib.rs index a186d40..74eb0b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ use thiserror::Error; pub mod cbc; pub mod ecb; +mod ecb_impl; #[derive(Error, Debug, PartialEq)] pub enum TcTeaError {