diff --git a/Cargo.toml b/Cargo.toml index fbc525e..b3ef5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ zeroize = { version = "1.6.0", features = ["zeroize_derive"] } [dev-dependencies] aes-gcm = { version = "0.10.2", features = ["zeroize"] } +benchmark-simple = "0.1.8" diff --git a/README.md b/README.md index 18374df..f97030a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,34 @@ # aes-gcm-stream +## Encrypt + +```rust + // IMPORTANT! key and nonce SHOULD generate by random + let mut key = [0u8; 32]; + let mut nonce = [0; 12]; + + let mut encryptor = Aes256GcmStreamEncryptor::new(key.clone(), &nonce); + + let mut ciphertext = vec![]; + ciphertext.extend_from_slice(&encryptor.update(b"Hello ")); + ciphertext.extend_from_slice(&encryptor.update(b" World")); + ciphertext.extend_from_slice(&encryptor.update(b"!")); + let (last_block, tag) = encryptor.finalize(); + ciphertext.extend_from_slice(&last_block); + ciphertext.extend_from_slice(&tag); + + println!("Ciphertext: {}", hex::encode(&ciphertext)); +``` + +## Run Example + +```shell +$ cargo run --example encrypt_and_decrypt + Finished dev [unoptimized + debuginfo] target(s) in 0.10s + Running `target/debug/examples/encrypt_and_decrypt` +Ciphertext: 86c22c5122404b39683ca9b79b889fd00a6212d1be2ebc3f4f8f22f90b +Plaintext: Hello World! +``` > Thanks: https://developer.aliyun.com/article/952809 diff --git a/examples/bench.rs b/examples/bench.rs new file mode 100644 index 0000000..0c2e272 --- /dev/null +++ b/examples/bench.rs @@ -0,0 +1,53 @@ +use benchmark_simple::{Bench, Options}; + +use aes_gcm_stream::{Aes128GcmStreamEncryptor, Aes192GcmStreamEncryptor, Aes256GcmStreamEncryptor}; + +fn test_aes128_encrypt(m: &mut [u8]) { + let key = [0u8; 16]; + let nonce = [0u8; 12]; + let mut encryptor = Aes128GcmStreamEncryptor::new(key, &nonce); + + encryptor.update(m); + encryptor.finalize(); +} + +fn test_aes192_encrypt(m: &mut [u8]) { + let key = [0u8; 24]; + let nonce = [0u8; 12]; + let mut encryptor = Aes192GcmStreamEncryptor::new(key, &nonce); + + encryptor.update(m); + encryptor.finalize(); +} + +fn test_aes256_encrypt(m: &mut [u8]) { + let key = [0u8; 32]; + let nonce = [0u8; 12]; + let mut encryptor = Aes256GcmStreamEncryptor::new(key, &nonce); + + encryptor.update(m); + encryptor.finalize(); +} + +fn main() { + let bench = Bench::new(); + let mut m = vec![0xd0u8; 16384]; + + let options = &Options { + iterations: 1_000, + warmup_iterations: 1_00, + min_samples: 5, + max_samples: 10, + max_rsd: 1.0, + ..Default::default() + }; + + let res = bench.run(options, || test_aes128_encrypt(&mut m)); + println!("AES128 encrypt : {}", res.throughput(m.len() as _)); + + let res = bench.run(options, || test_aes192_encrypt(&mut m)); + println!("AES192 encrypt : {}", res.throughput(m.len() as _)); + + let res = bench.run(options, || test_aes256_encrypt(&mut m)); + println!("AES256 encrypt : {}", res.throughput(m.len() as _)); +} \ No newline at end of file diff --git a/examples/encrypt_and_decrypt.rs b/examples/encrypt_and_decrypt.rs new file mode 100644 index 0000000..5b5f2bd --- /dev/null +++ b/examples/encrypt_and_decrypt.rs @@ -0,0 +1,30 @@ +use aes_gcm_stream::{Aes256GcmStreamDecryptor, Aes256GcmStreamEncryptor}; +use zeroize::Zeroize; + +fn main() { + // IMPORTANT! key and nonce SHOULD generate by random + let mut key = [0u8; 32]; + let mut nonce = [0; 12]; + + let mut encryptor = Aes256GcmStreamEncryptor::new(key.clone(), &nonce); + + let mut ciphertext = vec![]; + ciphertext.extend_from_slice(&encryptor.update(b"Hello ")); + ciphertext.extend_from_slice(&encryptor.update(b" World")); + ciphertext.extend_from_slice(&encryptor.update(b"!")); + let (last_block, tag) = encryptor.finalize(); + ciphertext.extend_from_slice(&last_block); + ciphertext.extend_from_slice(&tag); + + println!("Ciphertext: {}", hex::encode(&ciphertext)); + + let mut decryptor = Aes256GcmStreamDecryptor::new(key.clone(), &nonce); + + let mut plaintext = vec![]; + plaintext.extend_from_slice(decryptor.update(&ciphertext).as_slice()); + plaintext.extend_from_slice(&decryptor.finalize().expect("decrypt error")); + + println!("Plaintext: {}", String::from_utf8_lossy(&plaintext)); + key.zeroize(); + nonce.zeroize(); +} \ No newline at end of file diff --git a/src/decryptor.rs b/src/decryptor.rs index 0fc6d72..8025150 100644 --- a/src/decryptor.rs +++ b/src/decryptor.rs @@ -62,7 +62,7 @@ impl $module { let message_buffer_slice = self.message_buffer.as_slice(); let message_buffer_len = message_buffer_slice.len(); if message_buffer_len < 32 { - return vec![]; + return Vec::with_capacity(0); } let blocks_count = (message_buffer_len / 16) - 1; let mut plaintext_message = Vec::with_capacity(blocks_count * 16); @@ -91,7 +91,7 @@ impl $module { // last block and this block len is less than 128 bits self.encryption_nonce = inc_32(self.encryption_nonce); let mut ctr = self.encryption_nonce.to_be_bytes(); - let block = Block::::from_mut_slice(&mut ctr); + let block = Block::<$aesn>::from_mut_slice(&mut ctr); self.crypto.encrypt_block(block); let chunk = &self.message_buffer[0..message_buffer_len - 16]; diff --git a/src/encryptor.rs b/src/encryptor.rs index 9fa4f32..9a01b47 100644 --- a/src/encryptor.rs +++ b/src/encryptor.rs @@ -62,14 +62,14 @@ impl $module { let message_buffer_slice = self.message_buffer.as_slice(); let message_buffer_len = message_buffer_slice.len(); if message_buffer_len < 16 { - return vec![]; + return Vec::with_capacity(0); } let blocks_count = message_buffer_len / 16; let mut encrypted_message = Vec::with_capacity(blocks_count * 16); for i in 0..blocks_count { self.encryption_nonce = inc_32(self.encryption_nonce); let mut ctr = self.encryption_nonce.to_be_bytes(); - let block = Block::::from_mut_slice(&mut ctr); + let block = Block::<$aesn>::from_mut_slice(&mut ctr); self.crypto.encrypt_block(block); let chunk = &message_buffer_slice[i * 16..(i + 1) * 16]; let y = u8to128(chunk) ^ u8to128(&block.as_slice()); @@ -90,7 +90,7 @@ impl $module { // last block and this block len is less than 128 bits self.encryption_nonce = inc_32(self.encryption_nonce); let mut ctr = self.encryption_nonce.to_be_bytes(); - let block = Block::::from_mut_slice(&mut ctr); + let block = Block::<$aesn>::from_mut_slice(&mut ctr); self.crypto.encrypt_block(block); let chunk = self.message_buffer.as_slice(); diff --git a/src/util.rs b/src/util.rs index 8b403bc..c92e04d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -44,6 +44,7 @@ pub(crate) fn normalize_nonce(ghash_key: u128, nonce_bytes: &[u8]) -> (u128, u12 (ghash_key, normalized_nonce) } +#[inline] pub(crate) fn u8to128(bytes: &[u8]) -> u128 { bytes.iter().rev().enumerate().fold(0, |acc, (i, &byte)| { acc | (byte as u128) << (i * 8) @@ -62,6 +63,7 @@ pub(crate) fn msb_s(s: usize, bytes: &[u8]) -> Vec { } // incs(X)=MSBlen(X)-s(X) || [int(LSBs(X))+1 mod 2^s]s +#[inline] pub(crate) fn inc_32(bits: u128) -> u128 { let msb = bits >> 32; let mut lsb = (bits & 0xffffffff) as u32;