From e33a26adab062b873f9a34fd6199f822d01e92fd Mon Sep 17 00:00:00 2001 From: 0xalivecow Date: Sun, 3 Nov 2024 10:58:52 +0100 Subject: [PATCH] feat: gfmul and aes gcm working --- src/utils/ciphers.rs | 116 ++++++++++++++++++++++++++++++++++++++++++- src/utils/field.rs | 4 ++ src/utils/math.rs | 6 +++ src/utils/poly.rs | 17 +++++-- 4 files changed, 137 insertions(+), 6 deletions(-) diff --git a/src/utils/ciphers.rs b/src/utils/ciphers.rs index 885b1c3..8b5e831 100644 --- a/src/utils/ciphers.rs +++ b/src/utils/ciphers.rs @@ -1,9 +1,9 @@ -use std::io::BufRead; +use std::{io::BufRead, process::Output}; use anyhow::Result; use openssl::symm::{Cipher, Crypter, Mode}; -use crate::utils::field::ByteArray; +use crate::utils::{field::ByteArray, math::reverse_bits_in_bytevec, poly::gfmul}; use super::math::xor_bytes; @@ -122,6 +122,92 @@ pub fn xex_decrypt(mut key: Vec, tweak: &Vec, input: &Vec) -> Result Ok(output) } +pub fn gcm_encrypt_aes( + mut nonce: Vec, + key: Vec, + plaintext: Vec, + ad: Vec, +) -> Result<(Vec, Vec, Vec, Vec)> { + let mut ciphertext: Vec = vec![]; + + let mut counter: u32 = 1; + nonce.append(counter.to_be_bytes().to_vec().as_mut()); + //nonce.append(0u8.to_le_bytes().to_vec().as_mut()); + eprintln!("{:001X?}", nonce); + + let auth_tag_xor = aes_128_encrypt(&key, &nonce)?; + + let auth_key_h = aes_128_encrypt(&key, &0u128.to_be_bytes().to_vec())?; + + let plaintext_chunks: Vec> = plaintext.chunks(16).map(|x| x.to_vec()).collect(); + + counter = 2; + for chunk in plaintext_chunks { + nonce.drain(12..); + nonce.append(counter.to_be_bytes().to_vec().as_mut()); + + eprintln!("{:001X?}", nonce); + + let inter1 = aes_128_encrypt(&key, &nonce)?; + + let mut inter2 = xor_bytes(&inter1, chunk.clone())?; + + ciphertext.append(inter2.as_mut()); + counter += 1; + } + + let mut l_field: Vec = ((ad.len() * 8) as u64).to_be_bytes().to_vec(); + let mut c_len: Vec = ((ciphertext.len() * 8) as u64).to_be_bytes().to_vec(); + l_field.append(c_len.as_mut()); + + let auth_tag = xor_bytes( + &ghash(auth_key_h.clone(), ad, ciphertext.clone(), l_field.clone())?, + auth_tag_xor, + )?; + + Ok((ciphertext, auth_tag, l_field, auth_key_h)) +} + +pub fn ghash( + auth_key_h: Vec, + mut ad: Vec, + mut ciphertext: Vec, + l_field: Vec, +) -> Result> { + let output: Vec = vec![0; 16]; + + eprintln!("{:?}", (ad.len() % 16) as u8); + eprintln!("{:001X?}", ad); + + if ad.len() % 16 != 0 { + ad.append(vec![0u8; ad.len() % 16].as_mut()); + } + + if ciphertext.len() % 16 != 0 { + ciphertext.append(vec![0u8; ciphertext.len() % 16].as_mut()); + } + + eprintln!("{:001X?}", ad); + eprintln!("{:001X?}", ciphertext); + + let inter1 = xor_bytes(&output, ad)?; + let mut inter_loop = gfmul(inter1, auth_key_h.clone(), "gcm")?; + + inter_loop = inter_loop; + + let cipher_chunks = ciphertext.chunks(16); + + for chunk in cipher_chunks { + let inter3 = xor_bytes(&inter_loop, chunk.to_vec())?; + inter_loop = gfmul(inter3, auth_key_h.clone(), "gcm")?; + } + + let inter4 = xor_bytes(&inter_loop, l_field)?; + inter_loop = gfmul(inter4, auth_key_h.clone(), "gcm")?; + + Ok(inter_loop) +} + /* * let mut bytes: [u8; 16] = [0u8; 16]; bytes.copy_from_slice(&ciphertext); @@ -180,4 +266,30 @@ mod tests { Ok(()) } + + #[test] + fn test_gcm_encrypt_aes() -> Result<()> { + let nonce = BASE64_STANDARD.decode("4gF+BtR3ku/PUQci")?; + let key = BASE64_STANDARD.decode("Xjq/GkpTSWoe3ZH0F+tjrQ==")?; + let plaintext = BASE64_STANDARD.decode("RGFzIGlzdCBlaW4gVGVzdA==")?; + let ad = BASE64_STANDARD.decode("QUQtRGF0ZW4=")?; + + let (ciphertext, auth_tag, l_field, auth_key_h) = + gcm_encrypt_aes(nonce, key, plaintext, ad)?; + + eprintln!( + "Cipher: {:001X?} \n Tag: {:001X?} \n L_Field: {:001X?} \n H: {:001X?}", + BASE64_STANDARD.encode(&ciphertext), + BASE64_STANDARD.encode(&auth_tag), + BASE64_STANDARD.encode(&l_field), + BASE64_STANDARD.encode(&auth_key_h) + ); + + assert_eq!(BASE64_STANDARD.encode(ciphertext), ""); + assert_eq!(BASE64_STANDARD.encode(auth_tag), ""); + assert_eq!(BASE64_STANDARD.encode(l_field), ""); + assert_eq!(BASE64_STANDARD.encode(auth_key_h), ""); + + Ok(()) + } } diff --git a/src/utils/field.rs b/src/utils/field.rs index afa9b06..5645b04 100644 --- a/src/utils/field.rs +++ b/src/utils/field.rs @@ -96,6 +96,10 @@ impl ByteArray { } true } + + pub fn reverse_bits_in_bytevec(&mut self) { + self.0 = self.0.iter_mut().map(|byte| byte.reverse_bits()).collect(); + } } #[cfg(test)] diff --git a/src/utils/math.rs b/src/utils/math.rs index 4021522..cf87e0c 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -10,3 +10,9 @@ pub fn xor_bytes(vec1: &Vec, mut vec2: Vec) -> Result> { Ok(vec2) } + +pub fn reverse_bits_in_bytevec(mut vec: Vec) -> Vec { + vec = vec.iter_mut().map(|byte| byte.reverse_bits()).collect(); + + vec +} diff --git a/src/utils/poly.rs b/src/utils/poly.rs index ec316a4..78889c8 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -4,7 +4,7 @@ use base64::prelude::*; use serde_json::Value; use std::{str::FromStr, u128, u8, usize}; -use super::field; +use super::{field, math::reverse_bits_in_bytevec}; pub const RED_POLY: u128 = 0x87000000_00000000_00000000_00000000; pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result> { @@ -17,15 +17,20 @@ pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result let mut poly2: ByteArray = ByteArray(poly_b); poly2.0.push(0x00); + if semantic == "gcm" { + poly1.reverse_bits_in_bytevec(); + poly2.reverse_bits_in_bytevec(); + } + 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)?; + poly2.right_shift("xex")?; while !poly2.is_empty() { - poly1.left_shift(semantic)?; + poly1.left_shift("xex")?; if poly1.msb_is_one() { poly1.xor_byte_arrays(&red_poly_bytes); @@ -35,11 +40,15 @@ pub fn gfmul(poly_a: Vec, poly_b: Vec, semantic: &str) -> Result result.xor_byte_arrays(&poly1); } - poly2.right_shift(semantic)?; + poly2.right_shift("xex")?; } result.0.remove(16); + if semantic == "gcm" { + result.reverse_bits_in_bytevec(); + } + Ok(result.0) }