From c34557ea29a39f64d47e123c1a90f058e21ecd6c Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Mon, 28 Oct 2024 00:35:39 +0100 Subject: [PATCH] feat: both XEX enc/dec are working in atomic tests --- src/tasks/mod.rs | 20 +++++-- src/tasks/tasks01/gfmul.rs | 8 +-- src/tasks/tasks01/sea128.rs | 2 +- src/tasks/tasks01/xex.rs | 0 src/utils/ciphers.rs | 116 ++++++++++++++++++++++++++++++++++-- src/utils/math.rs | 10 ++++ 6 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 src/tasks/tasks01/xex.rs diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index 05d8e85..ad5c83c 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -1,3 +1,5 @@ +use base64::prelude::*; + use std::collections::HashMap; use crate::utils::parse::{Responses, Testcase, Testcases}; @@ -6,7 +8,7 @@ use tasks01::{block2poly::block2poly, gfmul::gfmul, poly2block::poly2block, sea1 use anyhow::{anyhow, Result}; use serde_json::{json, Value}; -mod tasks01; +pub mod tasks01; pub fn task_deploy(testcase: &Testcase) -> Result { /* @@ -35,7 +37,13 @@ pub fn task_deploy(testcase: &Testcase) -> Result { Ok(json) } "gfmul" => { - let result = gfmul(args)?; + let poly1_text: String = serde_json::from_value(args["a"].clone())?; + let poly_a = BASE64_STANDARD.decode(poly1_text)?; + + let poly2_text: String = serde_json::from_value(args["b"].clone())?; + let poly_b = BASE64_STANDARD.decode(poly2_text)?; + + let result = BASE64_STANDARD.encode(gfmul(poly_a, poly_b)?); let json = json!({"product" : result}); Ok(json) } @@ -67,7 +75,7 @@ mod tests { #[test] fn test_task_deploy() { - let json = fs::read_to_string("src/test_json/poly2block_example.json").unwrap(); + let json = fs::read_to_string("test_json/poly2block_example.json").unwrap(); let parsed = parse_json(json).unwrap(); let testcase = parsed .testcases @@ -83,7 +91,7 @@ mod tests { #[test] fn test_task_distribution() -> Result<()> { - let json = fs::read_to_string("src/test_json/poly2block_example.json").unwrap(); + let json = fs::read_to_string("test_json/poly2block_example.json").unwrap(); let parsed = parse_json(json).unwrap(); let expected = json!({ "responses": { "b856d760-023d-4b00-bad2-15d2b6da22fe": {"block": "ARIAAAAAAAAAAAAAAAAAgA=="}}}); @@ -98,7 +106,7 @@ mod tests { #[test] fn test_task_sea128_task_full() -> Result<()> { - let json = fs::read_to_string("src/test_json/sea128.json").unwrap(); + let json = fs::read_to_string("test_json/sea128.json").unwrap(); let parsed = parse_json(json).unwrap(); let expected = json!({ @@ -122,7 +130,7 @@ mod tests { #[test] fn test_task_gfmul_full() -> Result<()> { - let json = fs::read_to_string("src/test_json/gfmul_test.json").unwrap(); + let json = fs::read_to_string("test_json/gfmul_test.json").unwrap(); let parsed = parse_json(json).unwrap(); let expected = json!({ "responses": { "b856d760-023d-4b00-bad2-15d2b6da22fe": {"product": "hSQAAAAAAAAAAAAAAAAAAA=="}}}); diff --git a/src/tasks/tasks01/gfmul.rs b/src/tasks/tasks01/gfmul.rs index 91ce8a2..44a032e 100644 --- a/src/tasks/tasks01/gfmul.rs +++ b/src/tasks/tasks01/gfmul.rs @@ -10,7 +10,7 @@ use crate::utils::{ pub const RED_POLY: u128 = 0x87000000_00000000_00000000_00000000; -pub fn gfmul(poly_a: Vec, poly_b: Vec) -> Result { +pub fn gfmul(poly_a: Vec, poly_b: Vec) -> Result> { let mut red_poly_bytes: ByteArray = ByteArray(RED_POLY.to_be_bytes().to_vec()); red_poly_bytes.0.push(0x01); @@ -42,10 +42,8 @@ pub fn gfmul(poly_a: Vec, poly_b: Vec) -> Result { } result.0.remove(16); - let mut bytes: [u8; 16] = [0u8; 16]; - bytes.copy_from_slice(&result.0); - Ok(BASE64_STANDARD.encode(bytes)) + Ok(result.0) } #[cfg(test)] @@ -66,7 +64,7 @@ mod tests { let poly2_text: String = serde_json::from_value(args["b"].clone())?; let poly_b = BASE64_STANDARD.decode(poly2_text)?; - let result = gfmul(poly_a, poly_b)?; + let result = BASE64_STANDARD.encode(gfmul(poly_a, poly_b)?); assert_eq!( result, "hSQAAAAAAAAAAAAAAAAAAA==", diff --git a/src/tasks/tasks01/sea128.rs b/src/tasks/tasks01/sea128.rs index 3f5c40d..cd5a87d 100644 --- a/src/tasks/tasks01/sea128.rs +++ b/src/tasks/tasks01/sea128.rs @@ -24,7 +24,7 @@ pub fn sea128(args: &Value) -> Result { Ok(output) } "decrypt" => { - let output = BASE64_STANDARD.encode(sea_128_decrypt(&key, &input)?); + let output = BASE64_STANDARD.encode(sea_128_decrypt(&key.into(), &input)?); Ok(output) } diff --git a/src/tasks/tasks01/xex.rs b/src/tasks/tasks01/xex.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/ciphers.rs b/src/utils/ciphers.rs index bfa999e..6b38c1a 100644 --- a/src/utils/ciphers.rs +++ b/src/utils/ciphers.rs @@ -3,6 +3,8 @@ use std::io::BufRead; use anyhow::Result; use openssl::symm::{Cipher, Crypter, Mode}; +use crate::utils::math::ByteArray; + use super::math::xor_bytes; pub fn aes_128_encrypt(key: &Vec, input: &Vec) -> Result> { @@ -54,11 +56,77 @@ pub fn sea_128_decrypt(key: &Vec, input: &Vec) -> Result> { } pub fn xex_encrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result> { - let key_parts: Vec = key.split_off(128); - let key1 = key_parts[0]; - let key2 = key_parts[1]; + let key2: Vec = key.split_off(16); + //let key1: ByteArray = ByteArray(vec![key_parts[0]]); + //let key2: ByteArray = ByteArray(vec![key_parts[1]]); - todo!(); + let input_chunks: Vec> = input.chunks(16).map(|x| x.to_vec()).collect(); + + let mut output: Vec = vec![]; + assert!(key.len() % 16 == 0, "Failure: Key len {}", key.len()); + assert!(key2.len() % 16 == 0, "Failure: Key2 len {}", key2.len()); + let mut tweak_block: ByteArray = ByteArray(sea_128_encrypt(&key2, tweak)?); + + dbg!("input_chunks: {:001X?}", &input_chunks); + + for chunk in input_chunks { + eprintln!("chunk: {:001X?}", &chunk); + let plaintext_intermediate = xor_bytes(&tweak_block.0, chunk)?; + eprintln!("key: {:001X?}", &key); + eprintln!("key2: {:001X?}", &key2); + eprintln!("plain: {:001X?}", &plaintext_intermediate); + eprintln!("tweak_block: {:001X?}", &tweak_block.0); + + assert!( + plaintext_intermediate.len() % 16 == 0, + "Failure: plaintext_intermediate len was {}", + plaintext_intermediate.len() + ); + assert!(key.len() % 16 == 0, "Failure: Key len {}", key.len()); + assert!(key2.len() % 16 == 0, "Failure: Key2 len {}", key2.len()); + let cypher_block_intermediate = sea_128_encrypt(&key, &plaintext_intermediate)?; + let mut cypher_block = xor_bytes(&tweak_block.0, cypher_block_intermediate)?; + output.append(cypher_block.as_mut()); + tweak_block.left_shift_reduce(); + } + + Ok(output) +} + +pub fn xex_decrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result> { + let key2: Vec = key.split_off(16); + //let key1: ByteArray = ByteArray(vec![key_parts[0]]); + //let key2: ByteArray = ByteArray(vec![key_parts[1]]); + + let input_chunks: Vec> = input.chunks(16).map(|x| x.to_vec()).collect(); + + let mut output: Vec = vec![]; + assert!(key.len() % 16 == 0, "Failure: Key len {}", key.len()); + assert!(key2.len() % 16 == 0, "Failure: Key2 len {}", key2.len()); + let mut tweak_block: ByteArray = ByteArray(sea_128_encrypt(&key2, tweak)?); + + for chunk in input_chunks { + eprintln!("chunk: {:001X?}", &chunk); + let cyphertext_intermediate = xor_bytes(&tweak_block.0, chunk)?; + eprintln!("key: {:001X?}", &key); + eprintln!("key2: {:001X?}", &key2); + eprintln!("plain: {:001X?}", &cyphertext_intermediate); + eprintln!("tweak_block: {:001X?}", &tweak_block.0); + + assert!( + cyphertext_intermediate.len() % 16 == 0, + "Failure: plaintext_intermediate len was {}", + cyphertext_intermediate.len() + ); + assert!(key.len() % 16 == 0, "Failure: Key len {}", key.len()); + assert!(key2.len() % 16 == 0, "Failure: Key2 len {}", key2.len()); + let plaintext_block_intermediate = sea_128_decrypt(&key, &cyphertext_intermediate)?; + let mut cypher_block = xor_bytes(&tweak_block.0, plaintext_block_intermediate)?; + output.append(cypher_block.as_mut()); + tweak_block.left_shift_reduce(); + } + + Ok(output) } /* @@ -67,3 +135,43 @@ pub fn xex_encrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result let number: u128 = ::from_be_bytes(bytes); * */ + +#[cfg(test)] +mod tests { + use super::*; + use base64::prelude::*; + + #[test] + fn test_xex_encrypt() -> Result<()> { + let key = BASE64_STANDARD.decode("B1ygNO/CyRYIUYhTSgoUysX5Y/wWLi4UiWaVeloUWs0=")?; + let tweak = BASE64_STANDARD.decode("6VXORr+YYHrd2nVe0OlA+Q==")?; + let input = BASE64_STANDARD + .decode("/aOg4jMocLkBLkDLgkHYtFKc2L9jjyd2WXSSyxXQikpMY9ZRnsJE76e9dW9olZIW")?; + + let output = BASE64_STANDARD.encode(xex_encrypt(key, &tweak, &input)?); + + assert_eq!( + output, + "mHAVhRCKPAPx0BcufG5BZ4+/CbneMV/gRvqK5rtLe0OJgpDU5iT7z2P0R7gEeRDO" + ); + + Ok(()) + } + + #[test] + fn test_xex_decrypt() -> Result<()> { + let key = BASE64_STANDARD.decode("B1ygNO/CyRYIUYhTSgoUysX5Y/wWLi4UiWaVeloUWs0=")?; + let tweak = BASE64_STANDARD.decode("6VXORr+YYHrd2nVe0OlA+Q==")?; + let input = BASE64_STANDARD + .decode("lr/ItaYGFXCtHhdPndE65yg7u/GIdM9wscABiiFOUH2Sbyc2UFMlIRSMnZrYCW1a")?; + + let output = BASE64_STANDARD.encode(xex_decrypt(key, &tweak, &input)?); + + assert_eq!( + output, + "SGV5IHdpZSBrcmFzcyBkYXMgZnVua3Rpb25pZXJ0IGphIG9mZmVuYmFyIGVjaHQu" + ); + + Ok(()) + } +} diff --git a/src/utils/math.rs b/src/utils/math.rs index 5fff14a..82b2c61 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -1,4 +1,7 @@ use anyhow::{Ok, Result}; +use base64::Engine; + +use crate::tasks::tasks01::gfmul::gfmul; pub fn xor_bytes(vec1: &Vec, mut vec2: Vec) -> Result> { for (byte1, byte2) in vec1.iter().zip(vec2.iter_mut()) { @@ -22,6 +25,13 @@ impl ByteArray { carry } + pub fn left_shift_reduce(&mut self) { + let alpha_poly: Vec = base64::prelude::BASE64_STANDARD + .decode("AgAAAAAAAAAAAAAAAAAAAA==") + .expect("Decode failed"); + self.0 = gfmul(self.0.clone(), alpha_poly).unwrap(); + } + pub fn right_shift(&mut self) -> u8 { let mut carry = 0u8; for byte in self.0.iter_mut().rev() {