use aes_gcm::aead::{Aead, KeyInit};
use aes_gcm::{Aes256Gcm, Key, Nonce};
use std::time::Duration;
use tacet::{helpers, AttackerModel, Outcome, TimingOracle};
fn main() {
let key = Key::<Aes256Gcm>::from_slice(&[0u8; 32]);
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(&[0u8; 12]);
let plaintexts = helpers::byte_vecs(1024);
println!("Testing AES-256-GCM encryption for timing leaks...");
let outcome = TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
.time_budget(Duration::from_secs(30))
.test(plaintexts, |input| {
std::hint::black_box(
cipher
.encrypt(nonce, input.as_slice())
.expect("encryption should succeed"),
);
});
match outcome {
Outcome::Pass {
leak_probability,
effect,
..
} => {
println!("Result: PASS");
println!("Leak probability: {:.2}%", leak_probability * 100.0);
println!(
"Max effect: {:.1}ns (95% CI: {:.1}–{:.1}ns)",
effect.max_effect_ns, effect.credible_interval_ns.0, effect.credible_interval_ns.1
);
}
Outcome::Fail {
leak_probability,
effect,
exploitability,
..
} => {
println!("Result: FAIL");
println!("Leak probability: {:.2}%", leak_probability * 100.0);
println!("Max effect: {:.1}ns", effect.max_effect_ns);
println!("Exploitability: {:?}", exploitability);
}
Outcome::Inconclusive {
leak_probability,
reason,
..
} => {
println!("Result: INCONCLUSIVE");
println!("Leak probability: {:.2}%", leak_probability * 100.0);
println!("Reason: {:?}", reason);
}
Outcome::Unmeasurable { recommendation, .. } => {
println!("Could not measure: {}", recommendation);
}
Outcome::Research(research) => {
println!("Result: RESEARCH MODE");
println!("Max effect: {:.1}ns", research.max_effect_ns);
println!("Status: {:?}", research.status);
}
}
}