Merge gcm_crack #32
7 changed files with 253 additions and 24 deletions
|
|
@ -6,6 +6,7 @@ use crate::utils::parse::{Responses, Testcase, Testcases};
|
||||||
use tasks01::{
|
use tasks01::{
|
||||||
block2poly::block2poly,
|
block2poly::block2poly,
|
||||||
gcm::{gcm_decrypt, gcm_encrypt},
|
gcm::{gcm_decrypt, gcm_encrypt},
|
||||||
|
gcm_crack::gcm_crack,
|
||||||
gfmul::gfmul_task,
|
gfmul::gfmul_task,
|
||||||
pad_oracle::padding_oracle,
|
pad_oracle::padding_oracle,
|
||||||
pfmath::{
|
pfmath::{
|
||||||
|
|
@ -176,6 +177,12 @@ pub fn task_deploy(testcase: &Testcase) -> Result<Value> {
|
||||||
|
|
||||||
Ok(json)
|
Ok(json)
|
||||||
}
|
}
|
||||||
|
"gcm_crack" => {
|
||||||
|
let result = gcm_crack(args)?;
|
||||||
|
let json = json!({"factors" : result});
|
||||||
|
|
||||||
|
Ok(json)
|
||||||
|
}
|
||||||
|
|
||||||
_ => Err(anyhow!(
|
_ => Err(anyhow!(
|
||||||
"Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}",
|
"Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}",
|
||||||
|
|
@ -234,7 +241,7 @@ pub fn task_distribute_st(testcases: &Testcases) -> Result<Responses> {
|
||||||
|
|
||||||
pub fn task_distribute(testcases: &Testcases) -> Result<Responses> {
|
pub fn task_distribute(testcases: &Testcases) -> Result<Responses> {
|
||||||
let cpus = num_cpus::get();
|
let cpus = num_cpus::get();
|
||||||
if cpus > 1 {
|
if cpus > 1000000 {
|
||||||
task_distribute_mt(testcases)
|
task_distribute_mt(testcases)
|
||||||
} else {
|
} else {
|
||||||
task_distribute_st(testcases)
|
task_distribute_st(testcases)
|
||||||
|
|
|
||||||
197
src/tasks/tasks01/gcm_crack.rs
Normal file
197
src/tasks/tasks01/gcm_crack.rs
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
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<u8>,
|
||||||
|
ad: Vec<u8>,
|
||||||
|
tag: Vec<u8>,
|
||||||
|
l_field: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_message(val: &Value) -> Result<(Message, Polynomial)> {
|
||||||
|
let ciphertext_text: String = serde_json::from_value(val["ciphertext"].clone())?;
|
||||||
|
let ciphertext_bytes: Vec<u8> = BASE64_STANDARD.decode(ciphertext_text)?;
|
||||||
|
let mut ciphertext_chunks: Vec<FieldElement> = ciphertext_bytes
|
||||||
|
.chunks(16)
|
||||||
|
.into_iter()
|
||||||
|
.map(|chunk| FieldElement::new(chunk.to_vec()))
|
||||||
|
.collect();
|
||||||
|
//ciphertext_chunks;
|
||||||
|
let ciphertext: Polynomial = Polynomial::new(ciphertext_chunks.clone());
|
||||||
|
|
||||||
|
let ad_text: String = serde_json::from_value(val["associated_data"].clone())?;
|
||||||
|
let mut ad_bytes: Vec<u8> = BASE64_STANDARD.decode(ad_text)?;
|
||||||
|
let mut l_field: Vec<u8> = ((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 mut ad_chunks: Vec<FieldElement> = ad_bytes
|
||||||
|
.chunks(16)
|
||||||
|
.into_iter()
|
||||||
|
.map(|chunk| FieldElement::new(chunk.to_vec()))
|
||||||
|
.collect();
|
||||||
|
//ad_chunks;
|
||||||
|
let ad: Polynomial = Polynomial::new(ad_chunks.clone());
|
||||||
|
|
||||||
|
let tag_text: String = serde_json::from_value(val["tag"].clone()).unwrap_or("".to_string());
|
||||||
|
let tag_bytes: Vec<u8> = BASE64_STANDARD.decode(tag_text)?;
|
||||||
|
let tag_field: FieldElement = FieldElement::new(tag_bytes.clone());
|
||||||
|
let tag: Polynomial = Polynomial::new(vec![tag_field.clone()]);
|
||||||
|
|
||||||
|
let mut c_len: Vec<u8> = ((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<FieldElement> =
|
||||||
|
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<CrackAnswer> {
|
||||||
|
let nonce: String = serde_json::from_value(args["nonce"].clone())?;
|
||||||
|
|
||||||
|
let crack_poly: Polynomial = Polynomial::empty();
|
||||||
|
|
||||||
|
// Prepare first equation
|
||||||
|
let (m1_data, m1_h_poly) = parse_message(&args["m1"])?;
|
||||||
|
|
||||||
|
let (m2_data, m2_h_poly) = parse_message(&args["m2"])?;
|
||||||
|
|
||||||
|
let (m3_data, m3_h_poly) = 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<Polynomial> = 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<u8> = vec![];
|
||||||
|
let mut h_candidate: FieldElement = FieldElement::zero();
|
||||||
|
let mut eky0: Vec<u8> = 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),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod block2poly;
|
pub mod block2poly;
|
||||||
pub mod gcm;
|
pub mod gcm;
|
||||||
|
pub mod gcm_crack;
|
||||||
pub mod gfmul;
|
pub mod gfmul;
|
||||||
pub mod pad_oracle;
|
pub mod pad_oracle;
|
||||||
pub mod pfmath;
|
pub mod pfmath;
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,14 @@ pub fn ddf(f: Polynomial) -> Vec<(Polynomial, u128)> {
|
||||||
|
|
||||||
let g = gcd(&h, &f_star);
|
let g = gcd(&h, &f_star);
|
||||||
if g != one_cmp {
|
if g != one_cmp {
|
||||||
eprintln!("d is: {}", d);
|
|
||||||
eprintln!("g is: {:?}", &g.clone().to_c_array());
|
|
||||||
|
|
||||||
z.push((g.clone(), d));
|
z.push((g.clone(), d));
|
||||||
f_star = f_star.div(&g).0;
|
f_star = f_star.div(&g).0;
|
||||||
}
|
}
|
||||||
eprintln!("d outer is: {}", d);
|
|
||||||
eprintln!("F star degree is {:?}", &f_star.degree());
|
|
||||||
|
|
||||||
d += 1;
|
d += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if f_star != one_cmp {
|
if f_star != one_cmp {
|
||||||
eprintln!("fstar not one");
|
|
||||||
z.push((f_star.clone(), f_star.degree() as u128));
|
z.push((f_star.clone(), f_star.degree() as u128));
|
||||||
} else if z.len() == 0 {
|
} else if z.len() == 0 {
|
||||||
z.push((f.clone(), 1));
|
z.push((f.clone(), 1));
|
||||||
|
|
|
||||||
|
|
@ -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])
|
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<u8> {
|
||||||
|
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<u8>) -> Self {
|
pub fn new(field_element: Vec<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
field_element: reverse_bits_in_bytevec(field_element),
|
field_element: reverse_bits_in_bytevec(field_element),
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::utils::field::ByteArray;
|
use crate::utils::field::ByteArray;
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
|
|
||||||
use num::traits::FromBytes;
|
use num::traits::{FromBytes, ToBytes};
|
||||||
use num::{BigInt, BigUint, One, Zero};
|
use num::{BigInt, BigUint, One, Zero};
|
||||||
|
|
||||||
use std::{str::FromStr, u128, u8, usize};
|
use std::{str::FromStr, u128, u8, usize};
|
||||||
|
|
@ -31,6 +31,10 @@ impl Polynomial {
|
||||||
self.polynomial.len() - 1
|
self.polynomial.len() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Polynomial {
|
||||||
|
Polynomial::new(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn one() -> Self {
|
pub fn one() -> Self {
|
||||||
Polynomial::new(vec![FieldElement::one()])
|
Polynomial::new(vec![FieldElement::one()])
|
||||||
}
|
}
|
||||||
|
|
@ -373,6 +377,10 @@ impl Polynomial {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extract_component(&self, i: u32) -> FieldElement {
|
||||||
|
self.polynomial[i as usize].clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Polynomial {
|
impl Clone for Polynomial {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,29 @@
|
||||||
{
|
{
|
||||||
"testcases": {
|
"testcases": {
|
||||||
"sandbox": {
|
"gcm_crack1": {
|
||||||
"action": "gfpoly_factor_edf",
|
"action": "gcm_crack",
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"F": [
|
"nonce": "4gF+BtR3ku/PUQci",
|
||||||
"mmAAAAAAAAAAAAAAAAAAAA==",
|
"m1": {
|
||||||
"AbAAAAAAAAAAAAAAAAAAAA==",
|
"ciphertext": "CGOkZDnJEt24aVV8mqQq+P4pouVDWhAYj0SN5MDAgg==",
|
||||||
"zgAAAAAAAAAAAAAAAAAAAA==",
|
"associated_data": "TmFjaHJpY2h0IDE=",
|
||||||
"FwAAAAAAAAAAAAAAAAAAAA==",
|
"tag": "GC9neV3aZLnmznTIWqCC4A=="
|
||||||
"AAAAAAAAAAAAAAAAAAAAAA==",
|
},
|
||||||
"wAAAAAAAAAAAAAAAAAAAAA==",
|
"m2": {
|
||||||
"gAAAAAAAAAAAAAAAAAAAAA=="
|
"ciphertext": "FnWyLSTfRrO8Y1MuhLIs6A==",
|
||||||
],
|
"associated_data": "",
|
||||||
"d": 3
|
"tag": "gb2ph1vzwU85/FsUg51t3Q=="
|
||||||
}
|
},
|
||||||
|
"m3": {
|
||||||
|
"ciphertext": "CGOkZDnJEt25aV58iaMt6O8+8chKVh0Eg1XFxA==",
|
||||||
|
"associated_data": "TmFjaHJpY2h0IDM=",
|
||||||
|
"tag": "+/aDjsAzTseDLuM4jt5Q6Q=="
|
||||||
|
},
|
||||||
|
"forgery": {
|
||||||
|
"ciphertext": "AXe/ZQ==",
|
||||||
|
"associated_data": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue