From f4c49a913779ff17265e180e52018be78a8b3bfd Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Tue, 29 Oct 2024 13:53:10 +0100 Subject: [PATCH 1/4] refactor: externalise gfmul to make it more accessible and semantic support --- src/tasks/mod.rs | 10 ++----- src/tasks/tasks01/gfmul.rs | 51 +++++++++-------------------------- src/utils/ciphers.rs | 4 +-- src/utils/math.rs | 55 +++++++++++++++++++++++++++----------- src/utils/poly.rs | 40 ++++++++++++++++++++++++++- 5 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index 13f27d8..0e0f3c3 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use crate::utils::parse::{Responses, Testcase, Testcases}; use tasks01::{ block2poly::block2poly, - gfmul::gfmul, + gfmul::gfmul_task, poly2block::poly2block, sea128::sea128, xex::{self, fde_xex}, @@ -43,13 +43,7 @@ pub fn task_deploy(testcase: &Testcase) -> Result { Ok(json) } "gfmul" => { - 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 result = BASE64_STANDARD.encode(gfmul_task(args)?); let json = json!({"product" : result}); Ok(json) } diff --git a/src/tasks/tasks01/gfmul.rs b/src/tasks/tasks01/gfmul.rs index 44a032e..58e5afb 100644 --- a/src/tasks/tasks01/gfmul.rs +++ b/src/tasks/tasks01/gfmul.rs @@ -1,49 +1,24 @@ -use anyhow::Result; -use base64::prelude::*; -//use num_bigint::{BigUint, ToBigUint}; -use serde_json::Value; - use crate::utils::{ math::ByteArray, - poly::{b64_2_num, coefficient_to_binary}, + poly::{b64_2_num, coefficient_to_binary, gfmul}, }; -pub const RED_POLY: u128 = 0x87000000_00000000_00000000_00000000; +use anyhow::Result; +use base64::prelude::*; +use serde_json::Value; -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); +pub fn gfmul_task(args: &Value) -> Result> { + let poly1_text: String = serde_json::from_value(args["a"].clone())?; + let poly_a = BASE64_STANDARD.decode(poly1_text)?; - let mut poly1: ByteArray = ByteArray(poly_a); - poly1.0.push(0x00); + let poly2_text: String = serde_json::from_value(args["b"].clone())?; + let poly_b = BASE64_STANDARD.decode(poly2_text)?; - let mut poly2: ByteArray = ByteArray(poly_b); - poly2.0.push(0x00); + let semantic: String = serde_json::from_value(args["semantic"].clone())?; - let mut result: ByteArray = ByteArray(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + let result = gfmul(poly_a, poly_b, &semantic)?; - if poly2.LSB_is_one() { - result.xor_byte_arrays(&poly1); - poly2.right_shift(); - } else { - poly2.right_shift(); - } - - while !poly2.is_empty() { - if poly2.LSB_is_one() { - poly1.left_shift(); - poly1.xor_byte_arrays(&red_poly_bytes); - result.xor_byte_arrays(&poly1); - } else { - poly1.left_shift(); - poly1.xor_byte_arrays(&red_poly_bytes); - } - poly2.right_shift(); - } - - result.0.remove(16); - - Ok(result.0) + Ok(result) } #[cfg(test)] @@ -64,7 +39,7 @@ mod tests { 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 result = BASE64_STANDARD.encode(gfmul(poly_a, poly_b, "xex")?); assert_eq!( result, "hSQAAAAAAAAAAAAAAAAAAA==", diff --git a/src/utils/ciphers.rs b/src/utils/ciphers.rs index ec1b467..6ffa52a 100644 --- a/src/utils/ciphers.rs +++ b/src/utils/ciphers.rs @@ -83,7 +83,7 @@ pub fn xex_encrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result 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(); + tweak_block.left_shift_reduce("xex"); } Ok(output) @@ -116,7 +116,7 @@ pub fn xex_decrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result 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(); + tweak_block.left_shift_reduce("xex"); } Ok(output) diff --git a/src/utils/math.rs b/src/utils/math.rs index 82b2c61..5fb6a35 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -1,7 +1,7 @@ -use anyhow::{Ok, Result}; +use anyhow::{anyhow, Ok, Result}; use base64::Engine; -use crate::tasks::tasks01::gfmul::gfmul; +use super::poly::gfmul; pub fn xor_bytes(vec1: &Vec, mut vec2: Vec) -> Result> { for (byte1, byte2) in vec1.iter().zip(vec2.iter_mut()) { @@ -25,21 +25,46 @@ 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 left_shift_reduce(&mut self, semantic: &str) { + match semantic { + "xex" => { + let alpha_poly: Vec = base64::prelude::BASE64_STANDARD + .decode("AgAAAAAAAAAAAAAAAAAAAA==") + .expect("Decode failed"); + self.0 = gfmul(self.0.clone(), alpha_poly, "xex").unwrap(); + } + "gcm" => { + let alpha_poly: Vec = base64::prelude::BASE64_STANDARD + .decode("AgAAAAAAAAAAAAAAAAAAAA==") + .expect("Decode failed"); + self.0 = gfmul(self.0.clone(), alpha_poly, "gcm").unwrap(); + } + _ => {} + } } - pub fn right_shift(&mut self) -> u8 { - let mut carry = 0u8; - for byte in self.0.iter_mut().rev() { - let new_carry = *byte & 1; - *byte = (*byte >> 1) | (carry << 7); - carry = new_carry; + pub fn right_shift(&mut self, semantic: &str) -> Result { + match semantic { + "xex" => { + let mut carry = 0u8; + for byte in self.0.iter_mut().rev() { + let new_carry = *byte & 1; + *byte = (*byte >> 1) | (carry << 7); + carry = new_carry; + } + Ok(carry) + } + "gcm" => { + let mut carry = 0u8; + for byte in self.0.iter_mut().rev() { + let new_carry = *byte & 1; + *byte = (*byte << 1) | carry; + carry = new_carry; + } + Ok(carry) + } + _ => Err(anyhow!("Failure in rsh. No valid semantic found")), } - carry } pub fn xor_byte_arrays(&mut self, vec2: &ByteArray) { @@ -94,7 +119,7 @@ mod tests { fn test_byte_array_shift_right() { let mut byte_array: ByteArray = ByteArray(vec![0x02]); let shifted_array: ByteArray = ByteArray(vec![0x01]); - byte_array.right_shift(); + byte_array.right_shift("xex"); assert_eq!( byte_array.0, shifted_array.0, diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 3c14e76..74233ed 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -1,7 +1,45 @@ +use crate::utils::math::ByteArray; use anyhow::Result; use base64::prelude::*; - +use serde_json::Value; use std::{str::FromStr, u128, u8, usize}; +pub const RED_POLY: u128 = 0x87000000_00000000_00000000_00000000; + +pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result> { + let mut red_poly_bytes: ByteArray = ByteArray(RED_POLY.to_be_bytes().to_vec()); + red_poly_bytes.0.push(0x01); + + let mut poly1: ByteArray = ByteArray(poly_a); + poly1.0.push(0x00); + + let mut poly2: ByteArray = ByteArray(poly_b); + poly2.0.push(0x00); + + let mut result: ByteArray = ByteArray(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + if poly2.LSB_is_one() { + result.xor_byte_arrays(&poly1); + poly2.right_shift(semantic); + } else { + poly2.right_shift(semantic); + } + + while !poly2.is_empty() { + if poly2.LSB_is_one() { + poly1.left_shift(); + poly1.xor_byte_arrays(&red_poly_bytes); + result.xor_byte_arrays(&poly1); + } else { + poly1.left_shift(); + poly1.xor_byte_arrays(&red_poly_bytes); + } + poly2.right_shift(semantic); + } + + result.0.remove(16); + + Ok(result.0) +} pub fn get_alpha_rep(num: u128) -> String { let powers: Vec = get_coefficients(num); From ccf0b03ec0a7a040f18a6aacc6f6b59a33485e5c Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Tue, 29 Oct 2024 14:50:55 +0100 Subject: [PATCH 2/4] feat: add more shifting capabilities for gfmul --- src/utils/math.rs | 64 ++++++++++++++++++++++++++++++++++++++--------- src/utils/poly.rs | 10 ++++---- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/utils/math.rs b/src/utils/math.rs index 5fb6a35..f0308ba 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -15,14 +15,28 @@ pub fn xor_bytes(vec1: &Vec, mut vec2: Vec) -> Result> { pub struct ByteArray(pub Vec); impl ByteArray { - pub fn left_shift(&mut self) -> u8 { - let mut carry = 0u8; - for byte in self.0.iter_mut() { - let new_carry = *byte >> 7; - *byte = (*byte << 1) | carry; - carry = new_carry; + pub fn left_shift(&mut self, semantic: &str) -> Result { + match semantic { + "xex" => { + let mut carry = 0u8; + for byte in self.0.iter_mut() { + let new_carry = *byte >> 7; + *byte = (*byte << 1) | carry; + carry = new_carry; + } + Ok(carry) + } + "gcm" => { + let mut carry = 0u8; + for byte in self.0.iter_mut() { + let new_carry = *byte & 1; + *byte = (*byte >> 1) | (carry << 7); + carry = new_carry; + } + Ok(carry) + } + _ => Err(anyhow!("Failure in lsh. No compatible action found")), } - carry } pub fn left_shift_reduce(&mut self, semantic: &str) { @@ -97,7 +111,7 @@ mod tests { fn test_byte_array_shift1() { let mut byte_array: ByteArray = ByteArray(vec![0x00, 0x01]); let shifted_array: ByteArray = ByteArray(vec![0x00, 0x02]); - byte_array.left_shift(); + byte_array.left_shift("xex"); assert_eq!(byte_array.0, shifted_array.0); } @@ -106,7 +120,7 @@ mod tests { fn test_byte_array_shift2() { let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); let shifted_array: ByteArray = ByteArray(vec![0xFE, 0x01]); - byte_array.left_shift(); + byte_array.left_shift("xex"); assert_eq!( byte_array.0, shifted_array.0, @@ -115,6 +129,32 @@ mod tests { ); } + #[test] + fn test_byte_array_shift1_gcm() { + let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); + let shifted_array: ByteArray = ByteArray(vec![0x7F, 0x80]); + byte_array.left_shift("gcm"); + + assert_eq!( + byte_array.0, shifted_array.0, + "Failure: Shifted array was: {:02X?}", + byte_array.0 + ); + } + + #[test] + fn test_byte_array_shift1_right_gcm() { + let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); + let shifted_array: ByteArray = ByteArray(vec![0xFE, 0x00]); + byte_array.right_shift("gcm"); + + assert_eq!( + byte_array.0, shifted_array.0, + "Failure: Shifted array was: {:02X?}", + byte_array.0 + ); + } + #[test] fn test_byte_array_shift_right() { let mut byte_array: ByteArray = ByteArray(vec![0x02]); @@ -130,13 +170,13 @@ mod tests { #[test] fn test_lsb_one() { - let mut byte_array: ByteArray = ByteArray(vec![0x00, 0xFF]); + let byte_array: ByteArray = ByteArray(vec![0x00, 0xFF]); assert!(!byte_array.LSB_is_one()); - let mut byte_array2: ByteArray = ByteArray(vec![0x02, 0xFF]); + let byte_array2: ByteArray = ByteArray(vec![0x02, 0xFF]); assert!(!byte_array2.LSB_is_one()); - let mut byte_array3: ByteArray = ByteArray(vec![0xFF, 0x00]); + let byte_array3: ByteArray = ByteArray(vec![0xFF, 0x00]); assert!(byte_array3.LSB_is_one()); } diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 74233ed..5b6fb9a 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -19,21 +19,21 @@ pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result if poly2.LSB_is_one() { result.xor_byte_arrays(&poly1); - poly2.right_shift(semantic); + poly2.right_shift(semantic)?; } else { - poly2.right_shift(semantic); + poly2.right_shift(semantic)?; } while !poly2.is_empty() { if poly2.LSB_is_one() { - poly1.left_shift(); + poly1.left_shift(semantic)?; poly1.xor_byte_arrays(&red_poly_bytes); result.xor_byte_arrays(&poly1); } else { - poly1.left_shift(); + poly1.left_shift(semantic)?; poly1.xor_byte_arrays(&red_poly_bytes); } - poly2.right_shift(semantic); + poly2.right_shift(semantic)?; } result.0.remove(16); From 2e22bd5789de7d27cf38c04793ac270bd037f5a7 Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Wed, 30 Oct 2024 17:57:24 +0100 Subject: [PATCH 3/4] refactor: fix broken gfmil algo --- src/tasks/tasks01/gfmul.rs | 60 ++++++++++++++++++++++++++++++++++++++ src/utils/math.rs | 4 +++ src/utils/poly.rs | 18 ++++++------ 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/tasks/tasks01/gfmul.rs b/src/tasks/tasks01/gfmul.rs index 58e5afb..0ca5480 100644 --- a/src/tasks/tasks01/gfmul.rs +++ b/src/tasks/tasks01/gfmul.rs @@ -48,4 +48,64 @@ mod tests { ); Ok(()) } + + #[test] + fn gfmul_task02() -> Result<()> { + let args: Value = json!({"a": "AwEAAAAAAAAAAAAAAAAAgA==", "b": "gBAAAAAAAAAAAAAAAAAAAA=="}); + + 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, "xex")?); + + assert_eq!( + result, "QKgUAAAAAAAAAAAAAAAAAA==", + "Failure. Calulated result was: {}", + result + ); + Ok(()) + } + + #[test] + fn gfmul_task03() -> Result<()> { + let args: Value = json!({"a": "AwEAAAAAAAAAAAAAAAAAgA==", "b": "oBAAAAAAAAAAAAAAAAAAAA=="}); + + 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, "xex")?); + + assert_eq!( + result, "UIAUAAAAAAAAAAAAAAAAAA==", + "Failure. Calulated result was: {}", + result + ); + Ok(()) + } + + #[test] + fn gfmul_task04() -> Result<()> { + let args: Value = json!({"a": "ARIAAAAAAAAAAAAAAAAAgA==", "b": "AgAAAAAAAAAAAAAAAAAAAA=="}); + + 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, "xex")?); + + assert_eq!( + result, "hSQAAAAAAAAAAAAAAAAAAA==", + "Failure. Calulated result was: {}", + result + ); + Ok(()) + } } diff --git a/src/utils/math.rs b/src/utils/math.rs index f0308ba..98836a9 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -92,6 +92,10 @@ impl ByteArray { (self.0.first().unwrap() & 1) == 1 } + pub fn msb_is_one(&self) -> bool { + (self.0.last().unwrap() & 1) == 1 + } + pub fn is_empty(&self) -> bool { for i in self.0.iter() { if *i != 0 { diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 5b6fb9a..82336d7 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -19,20 +19,20 @@ pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result if poly2.LSB_is_one() { result.xor_byte_arrays(&poly1); - poly2.right_shift(semantic)?; - } else { - poly2.right_shift(semantic)?; } + poly2.right_shift(semantic)?; while !poly2.is_empty() { - if poly2.LSB_is_one() { - poly1.left_shift(semantic)?; - poly1.xor_byte_arrays(&red_poly_bytes); - result.xor_byte_arrays(&poly1); - } else { - poly1.left_shift(semantic)?; + poly1.left_shift(semantic)?; + + if poly1.msb_is_one() { poly1.xor_byte_arrays(&red_poly_bytes); } + + if poly2.LSB_is_one() { + result.xor_byte_arrays(&poly1); + } + poly2.right_shift(semantic)?; } From 28a8753d55705cad15a4e809590e629529f73214 Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Wed, 30 Oct 2024 18:00:09 +0100 Subject: [PATCH 4/4] feat: add test case for XEX empty --- src/utils/ciphers.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/utils/ciphers.rs b/src/utils/ciphers.rs index 6ffa52a..a9548e8 100644 --- a/src/utils/ciphers.rs +++ b/src/utils/ciphers.rs @@ -167,4 +167,17 @@ mod tests { Ok(()) } + + #[test] + fn test_xex_encrypt_empty_case() -> Result<()> { + let key = BASE64_STANDARD.decode("B1ygNO/CyRYIUYhTSgoUysX5Y/wWLi4UiWaVeloUWs0=")?; + let tweak = BASE64_STANDARD.decode("6VXORr+YYHrd2nVe0OlA+Q==")?; + let input = BASE64_STANDARD.decode("")?; + + let output = BASE64_STANDARD.encode(xex_encrypt(key, &tweak, &input)?); + + assert_eq!(output, ""); + + Ok(()) + } }