#![cfg(any(feature = "signing", feature = "encryption"))]
#![allow(clippy::print_stdout)]
#![allow(clippy::unwrap_used)]
use hardware_enclave::{create_tamper_evident, create_tamper_evident_ephemeral, VerifyOutcome};
fn interactive() -> bool {
std::env::var("ENCLAVE_INTERACTIVE").is_ok()
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive(tracing::Level::INFO.into()),
)
.init();
if interactive() {
println!("Mode: INTERACTIVE (real platform secure store — prompts may appear)");
println!("Note: unsigned binaries will show a password prompt on macOS.");
println!(" Signed binaries with keychain-access-groups use biometrics.");
} else {
println!("Mode: EPHEMERAL (in-memory key, no platform secure store, no prompts)");
println!(" Set ENCLAVE_INTERACTIVE=1 to test with real Keychain/DPAPI.");
}
println!("\n=== Sidecar mode: single file ===");
demo_single_file()?;
println!("\n=== Sidecar mode: directory of files ===");
demo_directory()?;
println!("\n=== Legacy file migration ===");
demo_migration()?;
if interactive() {
println!("\n=== TrustAnchor mode (low-volume, high-value file) ===");
demo_trust_anchor()?;
} else {
println!("\n=== TrustAnchor mode: skipped in ephemeral mode ===");
println!(" (TrustAnchor stores per-file tags in the platform secure store)");
}
println!("\nIntegrity example complete.");
Ok(())
}
fn make_handle(
app: &str,
) -> Result<hardware_enclave::TamperEvidentHandle, Box<dyn std::error::Error>> {
if interactive() {
Ok(create_tamper_evident(app)?)
} else {
Ok(create_tamper_evident_ephemeral(app))
}
}
fn demo_single_file() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempfile::TempDir::new()?;
let path = tmp.path().join("config.toml");
let content = b"[app]\nname = \"myapp\"\n";
let handle = make_handle("integrity-example")?;
handle.write(&path, content)?;
println!(" Written: {}", path.display());
match handle.verify(&path)? {
VerifyOutcome::Match => println!(" Verify: Match ✓"),
VerifyOutcome::StoreUnavailable => println!(" Verify: StoreUnavailable (ephemeral key)"),
other => println!(" Verify: unexpected outcome {other:?}"),
}
let read_back = handle.read(&path)?;
assert_eq!(read_back, content);
println!(" Read: roundtrip verified ✓");
std::fs::write(&path, b"[app]\nname = \"attacker\"\n")?;
println!(" Tampered: file overwritten externally");
match handle.verify(&path)? {
VerifyOutcome::Tamper => println!(" Verify: Tamper detected ✓"),
VerifyOutcome::StoreUnavailable => {
println!(" Verify: StoreUnavailable (expected in ephemeral mode with TrustAnchor)");
}
other => println!(" Verify: {other:?}"),
}
let missing = tmp.path().join("nonexistent.toml");
assert_eq!(handle.verify(&missing)?, VerifyOutcome::NotFound);
println!(" NotFound: missing file detected ✓");
handle.remove_integrity_data(&path)?;
Ok(())
}
fn demo_directory() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempfile::TempDir::new()?;
let handle = make_handle("integrity-example-dir")?;
for i in 0..10_u32 {
let path = tmp.path().join(format!("config-{i:02}.toml"));
handle.write(&path, format!("value = {i}").as_bytes())?;
}
println!(" Written: 10 config files");
let mut matches = 0_u32;
for i in 0..10_u32 {
let path = tmp.path().join(format!("config-{i:02}.toml"));
match handle.verify(&path)? {
VerifyOutcome::Match | VerifyOutcome::StoreUnavailable => matches += 1,
other => println!(" Unexpected: config-{i:02}.toml → {other:?}"),
}
}
println!(" All {matches}/10 files verified ✓");
let victim = tmp.path().join("config-05.toml");
std::fs::write(&victim, b"value = 999")?;
let mut tampers = 0_u32;
for i in 0..10_u32 {
let path = tmp.path().join(format!("config-{i:02}.toml"));
if handle.verify(&path)? == VerifyOutcome::Tamper {
tampers += 1;
}
}
assert_eq!(tampers, 1, "exactly one file should be tampered");
println!(" Tamper in config-05.toml detected, {tampers}/10 tampered ✓");
Ok(())
}
fn demo_migration() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempfile::TempDir::new()?;
let path = tmp.path().join("legacy.toml");
let content = b"[legacy]\nformat = 1\n";
std::fs::write(&path, content)?;
println!(" Pre-existing file written without integrity API");
let handle = make_handle("integrity-example-legacy")?;
assert_eq!(handle.verify(&path)?, VerifyOutcome::Legacy);
println!(" Verify: Legacy (no sidecar yet) ✓");
handle.migrate(&path)?;
println!(" Migrate: sidecar written");
match handle.verify(&path)? {
VerifyOutcome::Match => println!(" Verify after migrate: Match ✓"),
VerifyOutcome::StoreUnavailable => {
println!(" Verify after migrate: StoreUnavailable (ephemeral, sidecar mode)")
}
other => println!(" Verify after migrate: {other:?}"),
}
Ok(())
}
fn demo_trust_anchor() -> Result<(), Box<dyn std::error::Error>> {
let tmp = tempfile::TempDir::new()?;
let path = tmp.path().join("secret.json");
let content = br#"{"api_key":"sk-test-12345"}"#;
let handle = create_tamper_evident("integrity-trust-anchor")?.with_trust_anchor();
println!(
" Mode: {:?} (per-file tag in platform secure store)",
handle.mode()
);
handle.write(&path, content)?;
let sidecar = {
let mut s = path.as_os_str().to_owned();
s.push(".hmac");
std::path::PathBuf::from(s)
};
if sidecar.exists() {
std::fs::remove_file(&sidecar)?;
println!(" Sidecar deleted — trust anchor in secure store still authoritative");
}
match handle.verify(&path)? {
VerifyOutcome::Match => println!(" Verify: Match (sidecar deletion did not bypass) ✓"),
VerifyOutcome::Legacy => println!(" Verify: Legacy (no trust anchor in store yet)"),
other => println!(" Verify: {other:?}"),
}
handle.remove_integrity_data(&path)?;
println!(" Trust anchor removed from platform secure store ✓");
Ok(())
}