diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index a019cfe..aeca1c7 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -6,6 +6,7 @@ use crate::utils::parse::{Responses, Testcase, Testcases}; use tasks01::{ block2poly::block2poly, gcm::{gcm_decrypt, gcm_encrypt}, + gcm_crack::gcm_crack, gfmul::gfmul_task, pad_oracle::padding_oracle, pfmath::{ @@ -176,6 +177,12 @@ pub fn task_deploy(testcase: &Testcase) -> Result { Ok(json) } + "gcm_crack" => { + let result = gcm_crack(args)?; + let json = json!({"factors" : result}); + + Ok(json) + } _ => Err(anyhow!( "Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}", @@ -234,7 +241,7 @@ pub fn task_distribute_st(testcases: &Testcases) -> Result { pub fn task_distribute(testcases: &Testcases) -> Result { let cpus = num_cpus::get(); - if cpus > 1 { + if cpus > 1000000 { task_distribute_mt(testcases) } else { task_distribute_st(testcases) diff --git a/src/tasks/tasks01/gcm_crack.rs b/src/tasks/tasks01/gcm_crack.rs new file mode 100644 index 0000000..d8aab77 --- /dev/null +++ b/src/tasks/tasks01/gcm_crack.rs @@ -0,0 +1,188 @@ +use std::{env::args, fs::canonicalize, slice::Chunks}; + +use anyhow::{Ok, Result}; +use base64::{prelude::BASE64_STANDARD, Engine}; +use openssl::derive; +use serde::{Deserialize, Serialize}; +use serde_json::{map, Value}; + +use crate::utils::{ + self, + ciphers::ghash, + dff::ddf, + edf::edf, + field::FieldElement, + math::{reverse_bits_in_bytevec, xor_bytes}, + poly::Polynomial, + sff::sff, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CrackAnswer { + tag: String, + H: String, + mask: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct Message { + ciphertext: Vec, + ad: Vec, + tag: Vec, + l_field: Vec, +} + +fn parse_message(val: &Value) -> Result<(Message, Polynomial)> { + let ciphertext_text: String = serde_json::from_value(val["ciphertext"].clone())?; + let ciphertext_bytes: Vec = BASE64_STANDARD.decode(ciphertext_text)?; + let ciphertext_chunks: Vec = ciphertext_bytes + .chunks(16) + .into_iter() + .map(|chunk| FieldElement::new(chunk.to_vec())) + .collect(); + + let ad_text: String = serde_json::from_value(val["associated_data"].clone())?; + let mut ad_bytes: Vec = BASE64_STANDARD.decode(ad_text)?; + let mut l_field: Vec = ((ad_bytes.len() * 8) as u64).to_be_bytes().to_vec(); + + if ad_bytes.len() % 16 != 0 || ad_bytes.is_empty() { + ad_bytes.append(vec![0u8; 16 - (ad_bytes.len() % 16)].as_mut()); + } + let ad_chunks: Vec = ad_bytes + .chunks(16) + .into_iter() + .map(|chunk| FieldElement::new(chunk.to_vec())) + .collect(); + + let tag_text: String = serde_json::from_value(val["tag"].clone()).unwrap_or("".to_string()); + let tag_bytes: Vec = BASE64_STANDARD.decode(tag_text)?; + let tag_field: FieldElement = FieldElement::new(tag_bytes.clone()); + + let mut c_len: Vec = ((ciphertext_bytes.len() * 8) as u64).to_be_bytes().to_vec(); + l_field.append(c_len.as_mut()); + + // Combine all data + let mut combined: Vec = + Vec::with_capacity(ad_chunks.len() + ciphertext_chunks.len() + 1); + combined.extend(ad_chunks); + combined.extend(ciphertext_chunks.clone()); + combined.push(FieldElement::new(l_field.clone())); + combined.push(tag_field); + + combined.reverse(); + + let h_poly: Polynomial = Polynomial::new(combined); + + Ok(( + Message { + ciphertext: ciphertext_bytes, + ad: ad_bytes, + tag: tag_bytes, + l_field, + }, + h_poly, + )) +} + +pub fn gcm_crack(args: &Value) -> Result { + // Prepare first equation + let (m1_data, m1_h_poly) = parse_message(&args["m1"])?; + + let (_, m2_h_poly) = parse_message(&args["m2"])?; + + let (m3_data, _) = parse_message(&args["m3"])?; + + eprintln!("m1 poly: {:?}", m1_h_poly.clone().to_c_array()); + eprintln!("m2 poly: {:?}", m2_h_poly.clone().to_c_array()); + + let combine_poly = m1_h_poly + m2_h_poly; + + eprintln!("combine poly: {:?}", combine_poly.clone().to_c_array()); + + let combine_sff = sff(combine_poly.monic()); + + let mut combine_ddf: Vec<(Polynomial, u128)> = vec![]; + for (factor, _) in combine_sff { + combine_ddf.extend(ddf(factor)); + } + + eprintln!("combine_ddf: {:?}", combine_ddf); + + let mut combine_edf: Vec = vec![]; + for (factor, degree) in combine_ddf { + if degree == 1 { + combine_edf.extend(edf(factor, degree as u32)); + } + } + + eprintln!("combine_edf: {:?}", combine_edf); + + let mut m3_auth_tag: Vec = vec![]; + let mut h_candidate: FieldElement = FieldElement::zero(); + let mut eky0: Vec = vec![]; + for candidate in combine_edf { + if candidate.degree() == 1 { + h_candidate = candidate.extract_component(0); + eprintln!("H candidate: {:02X?}", h_candidate.to_b64()); + let m1_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + m1_data.ad.clone(), + m1_data.ciphertext.clone(), + m1_data.l_field.clone(), + ) + .unwrap(); + + eky0 = xor_bytes(&m1_data.tag, m1_ghash).unwrap(); + eprintln!("eky0: {:?}", BASE64_STANDARD.encode(eky0.clone())); + + let m3_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + m3_data.ad.clone(), + m3_data.ciphertext.clone(), + m3_data.l_field.clone(), + ) + .unwrap(); + + m3_auth_tag = xor_bytes(&eky0, m3_ghash).unwrap(); + eprintln!( + "M3 auth tag: {:02X?}", + BASE64_STANDARD.encode(m3_auth_tag.clone()) + ); + + if m3_auth_tag == m3_data.tag { + eprintln!("Candidate valid"); + eprintln!("{:02X?}", m3_auth_tag); + break; + } else { + eprintln!("H candidate not valid"); + } + } + } + + eprintln!( + "M3 Authentication TAG {:02X?}", + BASE64_STANDARD.encode(&m3_auth_tag) + ); + + if m3_auth_tag.is_empty() { + eprintln!("No valid candidate found"); + } + + let (forgery_data, _) = parse_message(&args["forgery"])?; + + let forgery_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + forgery_data.ad.clone(), + forgery_data.ciphertext.clone(), + forgery_data.l_field.clone(), + ) + .unwrap(); + + let forgery_auth_tag = xor_bytes(&eky0, forgery_ghash).unwrap(); + + Ok(CrackAnswer { + tag: BASE64_STANDARD.encode(forgery_auth_tag), + H: h_candidate.to_b64(), + mask: BASE64_STANDARD.encode(eky0), + }) +} diff --git a/src/tasks/tasks01/mod.rs b/src/tasks/tasks01/mod.rs index 8200de5..64d24da 100644 --- a/src/tasks/tasks01/mod.rs +++ b/src/tasks/tasks01/mod.rs @@ -1,5 +1,6 @@ pub mod block2poly; pub mod gcm; +pub mod gcm_crack; pub mod gfmul; pub mod pad_oracle; pub mod pfmath; diff --git a/src/utils/dff.rs b/src/utils/dff.rs index bcd1ca0..4cd4b39 100644 --- a/src/utils/dff.rs +++ b/src/utils/dff.rs @@ -25,20 +25,14 @@ pub fn ddf(f: Polynomial) -> Vec<(Polynomial, u128)> { let g = gcd(&h, &f_star); if g != one_cmp { - eprintln!("d is: {}", d); - eprintln!("g is: {:?}", &g.clone().to_c_array()); - z.push((g.clone(), d)); f_star = f_star.div(&g).0; } - eprintln!("d outer is: {}", d); - eprintln!("F star degree is {:?}", &f_star.degree()); d += 1; } if f_star != one_cmp { - eprintln!("fstar not one"); z.push((f_star.clone(), f_star.degree() as u128)); } else if z.len() == 0 { z.push((f.clone(), 1)); diff --git a/src/utils/edf.rs b/src/utils/edf.rs index da05db5..dfb59cf 100644 --- a/src/utils/edf.rs +++ b/src/utils/edf.rs @@ -4,34 +4,21 @@ use rand::Rng; use super::poly::{gcd, Polynomial}; pub fn edf(f: Polynomial, d: u32) -> Vec { - eprintln!("edf started: {:?}", f.clone().to_c_array()); let q = BigUint::pow(&BigUint::from_u8(2).unwrap(), 128); let n: u32 = (f.degree() as u32) / (d); let mut z: Vec = vec![f.clone()]; let one_cmp = Polynomial::one(); while (z.len() as u32) < n { - eprintln!("z len {}", z.len()); - eprintln!("n len {}", n); - let h = Polynomial::rand(&rand::thread_rng().gen_range(1..=f.degree())); - eprintln!("h: {:02X?}", h); let exponent = (q.pow(d) - BigUint::one()) / BigUint::from_u8(3).unwrap(); let g = h.bpow_mod(exponent, &f) + Polynomial::one(); - eprintln!("g before for {:0X?}", g); - - eprintln!("z before for {:0X?}", z); for i in (0..z.len()).rev() { if z[i].degree() as u32 > d { - eprintln!("Inside if"); let j = gcd(&z[i], &g); - eprintln!("j != one_cmp {:?}", j != one_cmp); - eprintln!("j != z[i] {:?}", j != z[i]); - - eprintln!("Inside if"); if j != one_cmp && j != z[i] { let intemediate = z[i].div(&j).0; z.remove(i); @@ -40,11 +27,8 @@ pub fn edf(f: Polynomial, d: u32) -> Vec { } } } - - eprintln!("z after for {:0X?}", z); } - eprintln!("edf finished"); z } diff --git a/src/utils/field.rs b/src/utils/field.rs index 7d359c8..13029cd 100644 --- a/src/utils/field.rs +++ b/src/utils/field.rs @@ -39,6 +39,18 @@ impl FieldElement { FieldElement::new_no_convert(vec![0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } + pub fn to_vec(&self) -> Vec { + self.field_element.clone() + } + + /* + pub fn padd(&mut self) { + if self.field_element.len() % 16 != 0 || ad.is_empty() { + ad.append(vec![0u8; 16 - (ad.len() % 16)].as_mut()); + } + } + */ + pub fn new(field_element: Vec) -> Self { Self { field_element: reverse_bits_in_bytevec(field_element), diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 7f9cbe6..61109f8 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -1,7 +1,7 @@ use crate::utils::field::ByteArray; use base64::prelude::*; -use num::traits::FromBytes; +use num::traits::{FromBytes, ToBytes}; use num::{BigInt, BigUint, One, Zero}; use std::{str::FromStr, u128, u8, usize}; @@ -31,6 +31,10 @@ impl Polynomial { self.polynomial.len() - 1 } + pub fn empty() -> Polynomial { + Polynomial::new(vec![]) + } + pub fn one() -> Self { Polynomial::new(vec![FieldElement::one()]) } @@ -373,6 +377,10 @@ impl Polynomial { self } + + pub fn extract_component(&self, i: u32) -> FieldElement { + self.polynomial[i as usize].clone() + } } impl Clone for Polynomial { diff --git a/test_json/sandbox.json b/test_json/sandbox.json index 836b3c8..e3f5e1f 100644 --- a/test_json/sandbox.json +++ b/test_json/sandbox.json @@ -1,19 +1,29 @@ { - "testcases": { - "sandbox": { - "action": "gfpoly_factor_edf", - "arguments": { - "F": [ - "mmAAAAAAAAAAAAAAAAAAAA==", - "AbAAAAAAAAAAAAAAAAAAAA==", - "zgAAAAAAAAAAAAAAAAAAAA==", - "FwAAAAAAAAAAAAAAAAAAAA==", - "AAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "gAAAAAAAAAAAAAAAAAAAAA==" - ], - "d": 3 - } + "testcases": { + "gcm_crack1": { + "action": "gcm_crack", + "arguments": { + "nonce": "4gF+BtR3ku/PUQci", + "m1": { + "ciphertext": "CGOkZDnJEt24aVV8mqQq+P4pouVDWhAYj0SN5MDAgg==", + "associated_data": "TmFjaHJpY2h0IDE=", + "tag": "GC9neV3aZLnmznTIWqCC4A==" + }, + "m2": { + "ciphertext": "FnWyLSTfRrO8Y1MuhLIs6A==", + "associated_data": "", + "tag": "gb2ph1vzwU85/FsUg51t3Q==" + }, + "m3": { + "ciphertext": "CGOkZDnJEt25aV58iaMt6O8+8chKVh0Eg1XFxA==", + "associated_data": "TmFjaHJpY2h0IDM=", + "tag": "+/aDjsAzTseDLuM4jt5Q6Q==" + }, + "forgery": { + "ciphertext": "AXe/ZQ==", + "associated_data": "" + } + } + } } - } }