diff --git a/Cargo.toml b/Cargo.toml index b1440e6..dc14c4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aes-gcm-stream" -version = "0.2.2" +version = "0.2.3" edition = "2021" authors = ["Hatter Jiang"] repository = "https://git.hatter.ink/hatter/aes-gcm-stream" diff --git a/src/lib.rs b/src/lib.rs index a8d6f36..23e9181 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -446,3 +446,24 @@ fn test256_stream_and_array() { assert_eq!(ciphertext, encrypted); assert_eq!(plaintext, decrypted); } + +#[test] +fn test125_ab_nonce() { + let key = hex::decode("faf6a891866fac550ef548b4e5f6fbc98fccc6827cd943cc8d7539747f1d87bd").unwrap(); + let key: [u8; 32] = key.try_into().map_err(|_| format!("Bad key length")).unwrap(); + let nonce = hex::decode("cea500817694e16e734f07df422f6f52582d844e623746a96c5fbb4be2a38a6e").unwrap(); + let ciphertext = hex::decode("c52dadf683c02e81d842f6563b").unwrap(); + let tag = hex::decode("cc9062944525de37d3aa588c6a5676a2").unwrap(); + let aad = b"firstName:"; + + let mut gcm_stream = Aes256GcmStreamDecryptor::new(key, &nonce); + gcm_stream.init_adata(&aad[..]); + let mut first_block = gcm_stream.update(&ciphertext); + let second_block = gcm_stream.update(&tag); + let final_block = gcm_stream.finalize().unwrap(); + + first_block.extend_from_slice(&second_block); + first_block.extend_from_slice(&final_block); + + assert_eq!("John --- TEST", String::from_utf8(first_block).unwrap()); +} diff --git a/src/util.rs b/src/util.rs index c03a37c..f8ce191 100644 --- a/src/util.rs +++ b/src/util.rs @@ -39,18 +39,29 @@ pub(crate) fn ghash(key: u128, messages: &[u128]) -> u128 { } pub(crate) fn normalize_nonce(ghash_key: u128, nonce_bytes: &[u8]) -> (u128, u128) { - let nonce = u8to128(nonce_bytes); let normalized_nonce = match nonce_bytes.len() == 12 { true => { + let nonce = u8to128(nonce_bytes); nonce << 32 | 0x00000001 } false => { let mut iv_padding = vec![]; - // s = 128[len(iv) / 128] - len(iv) - let s = 128 * (((nonce_bytes.len() * 8) + 128 - 1) / 128) - (nonce_bytes.len() * 8); - iv_padding.push(nonce << s); - iv_padding.push((nonce_bytes.len() * 8) as u128); - ghash(ghash_key, &iv_padding) + iv_padding.extend_from_slice(nonce_bytes); + let left_len = nonce_bytes.len() - 16 * (nonce_bytes.len() / 16); + let tobe_padding_len = if left_len == 0 { 0 } else { 16 - left_len }; + for _ in 0..tobe_padding_len { iv_padding.push(0); } + + let mut block = ghash::Block::default(); + let nonce_bits = (nonce_bytes.len() as u64) * 8; + block[8..].copy_from_slice(&nonce_bits.to_be_bytes()); + iv_padding.extend_from_slice(block.as_slice()); + + let mut iv_padding_u128 = vec![]; + let block_count = iv_padding.len() / 16; + for i in 0..block_count { + iv_padding_u128.push(u8to128(&iv_padding[i * 16..(i + 1) * 16])); + } + ghash(ghash_key, &iv_padding_u128) } }; (ghash_key, normalized_nonce) @@ -81,4 +92,30 @@ pub(crate) fn inc_32(bits: u128) -> u128 { let mut lsb = (bits & 0xffffffff) as u32; lsb = lsb.wrapping_add(1); msb << 32 | lsb as u128 +} + +#[test] +fn test_normalize_nonce() { + use aes_gcm::KeyInit; + use ghash::Key; + use ghash::GHash; + use ghash::universal_hash::UniversalHash; + let ghash_key = [1u8; 16]; + let key = Key::from(ghash_key); + let mut ghash = GHash::new(&key); + + let nonce = [1u8; 22]; + ghash.update_padded(&nonce); + + let mut block = ghash::Block::default(); + let nonce_bits = (nonce.len() as u64) * 8; + block[8..].copy_from_slice(&nonce_bits.to_be_bytes()); + ghash.update(&[block]); + let final_nonce = ghash.finalize(); + let final_nonce_bytes = final_nonce.as_slice(); + let final_nonce1 = u8to128(final_nonce_bytes); + + let (_, final_nonce2) = normalize_nonce(u8to128(&ghash_key), &nonce); + + assert_eq!(final_nonce1, final_nonce2); } \ No newline at end of file