`aes-gcm` decryption failing

⚓ rust    📅 2025-05-14    👤 surdeus    👁️ 2      

surdeus

I'm using aes-gcm for symetric encryption in my network protocol, and in the tests, the decrypt() method keeps failing:

Code:

/*!
	Implements the default symetric encryption scheme (AES-256-GCM).
	Encryption method 0.
*/

// External dependancies go here:
use aes_gcm::{self, aead::AeadMutInPlace, Aes256Gcm, Error, KeyInit, Nonce};
use arbitrary_int::u96;

// Internal dependancies go here:
use super::Crypto;
use super::Role;

pub struct AesGcmCrypto {

	// Cipher struct. Does all the exciting stuff:
	cipher: Aes256Gcm,

	// Used for the nonce (which will simply be incremented,
	// as it is safer than a random nonce and it would take
	// quintillions of years to count to 2^96, even if you
	// increment 1,000/s):
	nonce: u96,

}


impl Crypto for AesGcmCrypto {
	type Error = Error;

	fn new<T: crate::kex::KeyExchanger>(key_exchange: T, role: Role) -> Self {
		return Self {
			cipher: Aes256Gcm::new(key_exchange.shared_secret().into()),
			nonce: if let Role::Client = role { 0_u64.into() } else { 1_u64.into() },
		};
	}

	fn encrypt(&mut self, data: &mut Vec<u8>, adata: &[u8]) -> Result<(), Self::Error> {
		// We'll just call this function on the data:
		self.cipher.encrypt_in_place(Nonce::from_slice(&self.nonce.to_be_bytes()), adata, data)?;
		// And increment the nonce:
		self.nonce += 2_u64.into();	// TODO: nonce is not incremented securely; it should be incemented by 2, and the client and server need to alternate.
		
		return Ok(());
	}

	fn decrypt(&mut self, data: &mut Vec<u8>, adata: &[u8]) -> Result<(), Self::Error> {
		// Same thing, in reverse:
		self.cipher.decrypt_in_place(Nonce::from_slice(&self.nonce.to_be_bytes()), adata, data)?;
		// Increment the nonce:
		self.nonce += 2_u64.into();	// TODO: nonce is not incremented securely; it should be incemented by 2, and the client and server need to alternate.

		return Ok(());
	}

}

#[test]
fn test_aes_gcm_crypto() {
	use crate::kex::{KeyExchanger, KyberlibKeyExchanger};

	// Run a key exchange:

	let mut alice_kex: KyberlibKeyExchanger = KyberlibKeyExchanger::new().expect("Failed to create Alice in AES-GCM test");
	let mut bob_kex: KyberlibKeyExchanger = KyberlibKeyExchanger::new().expect("Failed to create Bob in AES-GCM test");

	alice_kex.set_remote_pubkey(bob_kex.get_local_pubkey()).expect("Failed to set Alice's remote pubkey in AES-GCM test");
	bob_kex.set_remote_pubkey(alice_kex.get_local_pubkey()).expect("Failed to set Bob's remote pubkey in AES-GCM test");

	let alice_init: [u8; 2272] = alice_kex.client_init().expect("Client init failed for Alice in AES-GCM test");
	alice_kex.client_confirm(bob_kex.server_init(alice_init).expect("Server init failed for Bob in AES-GCM test")).expect("Client confirm failed for Alice in AES-GCM test");


	// Let's go test it!

	let mut alice: AesGcmCrypto = AesGcmCrypto::new(alice_kex, Role::Client);
	let mut bob: AesGcmCrypto = AesGcmCrypto::new(bob_kex, Role::Server);

	let mut alice_msg: Vec<u8> = b"Hello, Bob!".into();
	let mut bob_response: Vec<u8> = b"Hello, Alice!".into();

	alice.encrypt(&mut alice_msg, b"").expect("Failed to encrypt Alice's message in AES-GCM test");
	bob.encrypt(&mut bob_response, b"").expect("Failed to encrypt Bob's message in AES-GCM test");

	alice.decrypt(&mut bob_response, b"").expect("Failed to decrypt Bob's response in AES-GCM test");
	bob.decrypt(&mut alice_msg, b"").expect("Failed to decrypt Alice's message in AES-GCM test");
}

Output of cargo test:


    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.03s
     Running unittests src/qshd/main.rs (target/debug/deps/qshd-d83de788b828dc28)

running 1 test
test encrypt::qsh_aes_gcm::test_aes_gcm_crypto ... FAILED

successes:

successes:

failures:

---- encrypt::qsh_aes_gcm::test_aes_gcm_crypto stdout ----

thread 'encrypt::qsh_aes_gcm::test_aes_gcm_crypto' panicked at src/qshd/encrypt/qsh_aes_gcm.rs:85:43:
Failed to decrypt Bob's response in AES-GCM test: Error
stack backtrace:
   0: rust_begin_unwind
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/std/src/panicking.rs:695:5
   1: core::panicking::panic_fmt
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/panicking.rs:75:14
   2: core::result::unwrap_failed
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/result.rs:1704:5
   3: core::result::Result<T,E>::expect
             at /opt/rust-bin-1.86.0/lib/rustlib/src/rust/library/core/src/result.rs:1061:23
   4: qshd::encrypt::qsh_aes_gcm::test_aes_gcm_crypto
             at ./src/qshd/encrypt/qsh_aes_gcm.rs:85:2
   5: qshd::encrypt::qsh_aes_gcm::test_aes_gcm_crypto::{{closure}}
             at ./src/qshd/encrypt/qsh_aes_gcm.rs:59:25
   6: core::ops::function::FnOnce::call_once
             at /opt/rust-bin-1.86.0/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    encrypt::qsh_aes_gcm::test_aes_gcm_crypto

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.01s

error: test failed, to rerun pass `-p qsh --bin qshd`

All the other tests are passing. One of the tricky parts of aes-gcm is that Errors don't come with descriptions (for security reasons), so I can't easily figure out what's wrong.
Does anyone know why it's failing to decrypt? Maybe I'm not using it right?

1 post - 1 participant

Read full topic

🏷️ rust_feed