Something went wrong. Try again.
Typelevel cryptographic algo tracking crates.io/crates/evidence
typelevel cryptography util
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133//! Property-based tests for Mac.
#![cfg(feature = "hmac")]
use bolero::check;use evidence::{ codec::Identity, mac::{Mac, MacUnchecked, hmac::HmacSha256},};use hmac::Hmac;
/// Helper to create a key from seed bytes (64 bytes for HMAC-SHA256 block size).fn key_from_seed(seed: [u8; 64]) -> hmac::digest::Key<Hmac<sha2::Sha256>> { *hmac::digest::Key::<Hmac<sha2::Sha256>>::from_slice(&seed)}
#[test]#[allow(clippy::expect_used)] // test should panic if verification failsfn mac_verify_roundtrip() { check!() .with_type::<([u8; 64], Vec<u8>)>() .for_each(|(seed, payload)| { let key = key_from_seed(*seed);
let mac: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, payload);
let verified = mac .try_verify(&key) .expect("verification should succeed for just-tagged payload");
assert_eq!(&verified, payload, "verified payload must match original"); });}
#[test]fn mac_deterministic() { check!() .with_type::<([u8; 64], Vec<u8>)>() .for_each(|(seed, payload)| { let key = key_from_seed(*seed);
let mac1: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, payload); let mac2: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, payload);
assert_eq!(mac1, mac2, "same input must produce same MAC"); });}
#[test]fn different_payloads_different_macs() { check!() .with_type::<([u8; 64], Vec<u8>, Vec<u8>)>() .filter(|(_, a, b)| a != b) .for_each(|(seed, payload_a, payload_b)| { let key = key_from_seed(*seed);
let mac_a: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, payload_a); let mac_b: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, payload_b);
assert_ne!( mac_a.mac_tag(), mac_b.mac_tag(), "different payloads should produce different MACs" ); });}
#[test]fn wrong_key_fails_verification() { check!() .with_type::<([u8; 64], [u8; 64], Vec<u8>)>() .filter(|(a, b, _)| a != b) .for_each(|(seed_correct, seed_wrong, payload)| { let correct_key = key_from_seed(*seed_correct); let wrong_key = key_from_seed(*seed_wrong);
let mac: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&correct_key, payload);
assert!( mac.try_verify(&wrong_key).is_err(), "verification must fail with wrong key" ); });}
#[test]#[allow(clippy::indexing_slicing)] // payload is non-empty (filter guarantees)fn tampered_payload_fails_verification() { check!() .with_type::<([u8; 64], Vec<u8>)>() .cloned() .filter(|(_, payload)| !payload.is_empty()) .for_each(|(seed, payload)| { let key = key_from_seed(seed);
let mac: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, &payload);
let mut tampered_bytes = mac.encoded_payload().to_vec(); tampered_bytes[0] = tampered_bytes[0].wrapping_add(1);
let tampered: Mac<Vec<u8>, HmacSha256, Identity> = Mac::from_unchecked_parts(*mac.mac_tag(), tampered_bytes);
assert!( tampered.try_verify(&key).is_err(), "verification must fail with tampered payload" ); });}
#[test]fn tampered_tag_fails_verification() { check!() .with_type::<([u8; 64], Vec<u8>)>() .cloned() .for_each(|(seed, payload)| { let key = key_from_seed(seed);
let mac: Mac<Vec<u8>, HmacSha256, Identity> = Mac::tag(&key, &payload);
let mut tampered_tag = *mac.mac_tag(); tampered_tag[0] = tampered_tag[0].wrapping_add(1);
let tampered: Mac<Vec<u8>, HmacSha256, Identity> = Mac::from_unchecked_parts(tampered_tag, mac.encoded_payload().to_vec());
assert!( tampered.try_verify(&key).is_err(), "verification must fail with tampered tag" ); });}