From c95a566c584540dfb6453ce3ab959601723b065a Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 18 Feb 2023 00:12:33 +0800 Subject: [PATCH] feat: add aes gcm crypto --- __crypto/aes_gcm_crypto/Cargo.lock | 107 ++++++++++++++++++ __crypto/aes_gcm_crypto/Cargo.toml | 11 ++ __crypto/aes_gcm_crypto/src/main.rs | 161 ++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 __crypto/aes_gcm_crypto/Cargo.lock create mode 100644 __crypto/aes_gcm_crypto/Cargo.toml create mode 100644 __crypto/aes_gcm_crypto/src/main.rs diff --git a/__crypto/aes_gcm_crypto/Cargo.lock b/__crypto/aes_gcm_crypto/Cargo.lock new file mode 100644 index 0000000..890e672 --- /dev/null +++ b/__crypto/aes_gcm_crypto/Cargo.lock @@ -0,0 +1,107 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes_gcm_crypto" +version = "0.1.0" +dependencies = [ + "aes", + "hex", + "hex-literal", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/__crypto/aes_gcm_crypto/Cargo.toml b/__crypto/aes_gcm_crypto/Cargo.toml new file mode 100644 index 0000000..491de76 --- /dev/null +++ b/__crypto/aes_gcm_crypto/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "aes_gcm_crypto" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aes = "0.8.2" +hex = "0.4.3" +hex-literal = "0.3.4" diff --git a/__crypto/aes_gcm_crypto/src/main.rs b/__crypto/aes_gcm_crypto/src/main.rs new file mode 100644 index 0000000..a738fde --- /dev/null +++ b/__crypto/aes_gcm_crypto/src/main.rs @@ -0,0 +1,161 @@ +use aes::Aes256; +use aes::cipher::{BlockEncrypt, Key, KeyInit}; +use aes::cipher::generic_array::GenericArray; +use hex_literal::hex; + +pub struct GCM { + aes: Aes256, +} + +// R = 11100001 || 0(120) +const R: u128 = 0b11100001 << 120; + +fn gmul_128(x: u128, y: u128) -> u128 { + let mut z = 0u128; + let mut v = y; + for i in (0..128).rev() { + let xi = (x >> i) & 1; + if xi != 0 { + z ^= v; + } + v = match v & 1 == 0 { + true => { v >> 1 } + false => { (v >> 1) ^ R } + }; + } + z +} + +fn u8to128(bytes: &[u8]) -> u128 { + let result = bytes.iter().rev().enumerate().fold(0, |acc, (i, &byte)| { + acc | (byte as u128) << (i * 8) + }); + result +} + +fn msb_s(s: usize, bytes: &[u8]) -> Vec { + let mut result = vec![]; + let n = s / 8; + let remain = s % 8; + for i in 0..n { + result.push(bytes[i]); + } + if remain > 0 { + result.push(bytes[n] >> (8 - remain)); + } + result +} + +// incs(X)=MSBlen(X)-s(X) || [int(LSBs(X))+1 mod 2^s]s +fn inc_32(bits: u128) -> u128 { + let msb = bits >> 32; + let mut lsb = (bits & 0xffffffff) as u32; + lsb = lsb.wrapping_add(1); + msb << 32 | lsb as u128 +} + +fn ghash(key: u128, messages: &[u128]) -> u128 { + let mut y = 0u128; + for i in 0..messages.len() { + let yi = gmul_128(y ^ messages[i], key); + y = yi; + } + y +} + +impl GCM { + pub fn new(key: [u8; 32]) -> Self { + let key = Key::::from_slice(&key); + let aes = Aes256::new(&key); + Self { + aes, + } + } + + fn encrypt_block(&mut self, block: &[u8; 16]) -> Vec { + let mut block = GenericArray::from(block.clone()); + self.aes.encrypt_block(&mut block); + block.to_vec() + } + + fn ghash_key(&mut self) -> u128 { + u8to128(&self.encrypt_block(&[0u8; 16])) + } + + pub fn gctr(&mut self, iv: u128, message: &[u8]) -> Vec { + // 如果X是空串, 则直接返回 + if message.len() == 0 { + return vec![]; + } + let mut output = vec![]; + let mut cb = iv; + for chunk in message.chunks(16) { + if chunk.len() < 16 { + let msb = msb_s(chunk.len() * 8, &self.encrypt_block(&cb.to_be_bytes())); + let y = u8to128(chunk) ^ u8to128(&msb); + output.extend_from_slice(&y.to_be_bytes()[16 - chunk.len()..16]); + } else { + let y = u8to128(chunk) ^ u8to128(&self.encrypt_block(&cb.to_be_bytes())); + output.extend_from_slice(&y.to_be_bytes()); + } + // counter + 1 + cb = inc_32(cb); + } + output + } + + pub fn ae(&mut self, iv_bytes: &[u8], adata: &[u8], message: &[u8]) -> (Vec, Vec) { + let ghash_key = self.ghash_key(); + let mut iv_padding = vec![]; + let iv = u8to128(iv_bytes); + let j0 = match iv_bytes.len() == 12 { + true => { + iv << 32 | 0x00000001 + } + false => { + // s = 128[len(iv) / 128] - len(iv) + let s = 128 * (((iv_bytes.len() * 8) + 128 - 1) / 128) - (iv_bytes.len() * 8); + iv_padding.push(iv << s); + iv_padding.push((iv_bytes.len() * 8) as u128); + ghash(ghash_key, &iv_padding) + } + }; + let message_len = message.len() * 8; + let adata_len = adata.len() * 8; + let u = 128 * ((message_len + 128 - 1) / 128) - message_len; + let v = 128 * ((adata_len + 128 - 1) / 128) - adata_len; + // println!("u, v: {}, {}", u, v); + // println!("j0 = {:02x?}", j0); + let enc = self.gctr(inc_32(j0), &message); + let mut bit_string = Vec::::new(); + bit_string.extend_from_slice(adata); + bit_string.extend_from_slice(&vec![0x00; v / 8]); + // 这里认证的是密文 + bit_string.extend_from_slice(&enc); + bit_string.extend_from_slice(&vec![0x00; u / 8]); + bit_string.extend_from_slice(&(adata_len as u64).to_be_bytes()); + bit_string.extend_from_slice(&(message_len as u64).to_be_bytes()); + // println!("len = {}, bit_string[u8] = {:02x?}", bit_string.len(), bit_string); + let bit_string: Vec = bit_string.chunks(16).map(|it| u8to128(it)).collect(); + // println!("bit_string[u128] = {:02x?}", bit_string); + let s = ghash(ghash_key, &bit_string).to_be_bytes(); + // println!("{:02x?}", s); + let tag = self.gctr(j0, &s); + // println!("tag = {:02x?}", tag); + // println!("enc = {:02x?}", enc); + (tag, enc) + } +} + +fn main() { + let key: [u8; 32] = hex!("0001020304050607080910111213141516171819202122232425262728293031"); + let p: Vec = "Hello world!".as_bytes().to_vec(); + let iv = hex!("000102030405060708091011"); + let mut gcm = GCM::new(key); + // let h = gcm.ghash_key(); + // assert_eq!(h, u8to128(&hex!("66e94bd4ef8a2c3b884cfa59ca342b2e"))); + + let (tag, enc) = gcm.ae(&iv, &[], &p); + println!("{}{}", hex::encode(&enc), hex::encode(tag)); + println!("dce9511866417cff5123fa08c9e92cf156c5fc8bf6108ff28816fb58"); +}