Add gcm aes and modified gfmul #6
8 changed files with 221 additions and 8 deletions
|
|
@ -1,10 +1,14 @@
|
|||
use base64::prelude::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, env::args};
|
||||
|
||||
use crate::utils::parse::{Responses, Testcase, Testcases};
|
||||
use crate::utils::{
|
||||
ciphers::gcm_encrypt_aes,
|
||||
parse::{Responses, Testcase, Testcases},
|
||||
};
|
||||
use tasks01::{
|
||||
block2poly::block2poly,
|
||||
gcm::gcm_encrypt,
|
||||
gfmul::gfmul_task,
|
||||
poly2block::poly2block,
|
||||
sea128::sea128,
|
||||
|
|
@ -53,6 +57,17 @@ pub fn task_deploy(testcase: &Testcase) -> Result<Value> {
|
|||
|
||||
Ok(json)
|
||||
}
|
||||
"gcm_encrypt" => {
|
||||
let (ciphertext, auth_tag, l_field, auth_key_h) = gcm_encrypt(args)?;
|
||||
let out_ciph = BASE64_STANDARD.encode(&ciphertext);
|
||||
let out_tag = BASE64_STANDARD.encode(&auth_tag);
|
||||
let out_l = BASE64_STANDARD.encode(&l_field);
|
||||
let out_h = BASE64_STANDARD.encode(&auth_key_h);
|
||||
|
||||
let json = json!({"ciphertext" : out_ciph, "tag" : out_tag, "L" : out_l, "H" : out_h});
|
||||
|
||||
Ok(json)
|
||||
}
|
||||
_ => Err(anyhow!(
|
||||
"Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}",
|
||||
testcase,
|
||||
|
|
@ -166,4 +181,24 @@ mod tests {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task_gcm_encrypt_aes_case() -> Result<()> {
|
||||
let json = fs::read_to_string("test_json/gcm_encrypt.json").unwrap();
|
||||
let parsed = parse_json(json).unwrap();
|
||||
|
||||
let expected = json!({ "responses" : { "b856d760-023d-4b00-bad2-15d2b6da22fe" : {
|
||||
"ciphertext": "ET3RmvH/Hbuxba63EuPRrw==",
|
||||
"tag": "Mp0APJb/ZIURRwQlMgNN/w==",
|
||||
"L": "AAAAAAAAAEAAAAAAAAAAgA==",
|
||||
"H": "Bu6ywbsUKlpmZXMQyuGAng=="
|
||||
}}});
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(task_distrubute(&parsed)?).unwrap(),
|
||||
serde_json::to_value(expected).unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
26
src/tasks/tasks01/gcm.rs
Normal file
26
src/tasks/tasks01/gcm.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use base64::prelude::*;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::utils::ciphers::gcm_encrypt_aes;
|
||||
|
||||
pub fn gcm_encrypt(args: &Value) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)> {
|
||||
let nonce_text: String = serde_json::from_value(args["nonce"].clone())?;
|
||||
let nonce = BASE64_STANDARD.decode(nonce_text)?;
|
||||
|
||||
let key_text: String = serde_json::from_value(args["key"].clone())?;
|
||||
let key = BASE64_STANDARD.decode(key_text)?;
|
||||
|
||||
let plaintext_text: String = serde_json::from_value(args["plaintext"].clone())?;
|
||||
let plaintext = BASE64_STANDARD.decode(plaintext_text)?;
|
||||
|
||||
let ad_text: String = serde_json::from_value(args["ad"].clone())?;
|
||||
let ad = BASE64_STANDARD.decode(ad_text)?;
|
||||
|
||||
let alg_text: String = serde_json::from_value(args["algorithm"].clone())?;
|
||||
|
||||
match alg_text.as_str() {
|
||||
"aes128" => Ok(gcm_encrypt_aes(nonce, key, plaintext, ad)?),
|
||||
_ => Err(anyhow!("No compatible algorithm found")),
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod block2poly;
|
||||
pub mod gcm;
|
||||
pub mod gfmul;
|
||||
pub mod poly2block;
|
||||
pub mod sea128;
|
||||
|
|
|
|||
|
|
@ -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<u8>, tweak: &Vec<u8>, input: &Vec<u8>) -> Result
|
|||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn gcm_encrypt_aes(
|
||||
mut nonce: Vec<u8>,
|
||||
key: Vec<u8>,
|
||||
plaintext: Vec<u8>,
|
||||
ad: Vec<u8>,
|
||||
) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>)> {
|
||||
let mut ciphertext: Vec<u8> = 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<Vec<u8>> = 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<u8> = ((ad.len() * 8) as u64).to_be_bytes().to_vec();
|
||||
let mut c_len: Vec<u8> = ((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<u8>,
|
||||
mut ad: Vec<u8>,
|
||||
mut ciphertext: Vec<u8>,
|
||||
l_field: Vec<u8>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let output: Vec<u8> = 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,36 @@ 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),
|
||||
"ET3RmvH/Hbuxba63EuPRrw=="
|
||||
);
|
||||
assert_eq!(BASE64_STANDARD.encode(auth_tag), "Mp0APJb/ZIURRwQlMgNN/w==");
|
||||
assert_eq!(BASE64_STANDARD.encode(l_field), "AAAAAAAAAEAAAAAAAAAAgA==");
|
||||
assert_eq!(
|
||||
BASE64_STANDARD.encode(auth_key_h),
|
||||
"Bu6ywbsUKlpmZXMQyuGAng=="
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -10,3 +10,9 @@ pub fn xor_bytes(vec1: &Vec<u8>, mut vec2: Vec<u8>) -> Result<Vec<u8>> {
|
|||
|
||||
Ok(vec2)
|
||||
}
|
||||
|
||||
pub fn reverse_bits_in_bytevec(mut vec: Vec<u8>) -> Vec<u8> {
|
||||
vec = vec.iter_mut().map(|byte| byte.reverse_bits()).collect();
|
||||
|
||||
vec
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<u8>, poly_b: Vec<u8>, semantic: &str) -> Result<Vec<u8>> {
|
||||
|
|
@ -17,15 +17,20 @@ pub fn gfmul(poly_a: Vec<u8>, poly_b: Vec<u8>, semantic: &str) -> Result<Vec<u8>
|
|||
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<u8>, poly_b: Vec<u8>, semantic: &str) -> Result<Vec<u8>
|
|||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
14
test_json/gcm_encrypt.json
Normal file
14
test_json/gcm_encrypt.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"testcases": {
|
||||
"b856d760-023d-4b00-bad2-15d2b6da22fe": {
|
||||
"action": "gcm_encrypt",
|
||||
"arguments": {
|
||||
"algorithm": "aes128",
|
||||
"nonce": "4gF+BtR3ku/PUQci",
|
||||
"key": "Xjq/GkpTSWoe3ZH0F+tjrQ==",
|
||||
"plaintext": "RGFzIGlzdCBlaW4gVGVzdA==",
|
||||
"ad": "QUQtRGF0ZW4="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue