//! Utilities example — `SecretBuf` for secure key material storage.
//!
//! `SecretBuf` wraps a `Vec<u8>` and calls `OPENSSL_cleanse` on drop,
//! ensuring sensitive bytes are zeroed even under compiler optimisation.
//!
//! Run with: cargo run --example util -p native-ossl

use native_ossl::digest::DigestAlg;
use native_ossl::kdf::HkdfBuilder;
use native_ossl::rand::Rand;
use native_ossl::util::SecretBuf;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ── Fill a secure buffer with random key material ─────────────────────────

    let mut key = SecretBuf::with_len(32);
    Rand::fill(key.as_mut_slice())?;
    println!(
        "Random key ({} bytes): {}",
        key.len(),
        native_ossl::util::hex_encode(key.as_ref())
    );

    // ── Derive key material directly into a SecretBuf ─────────────────────────

    let sha256 = DigestAlg::fetch(c"SHA2-256", None)?;
    let mut derived = SecretBuf::with_len(32);
    HkdfBuilder::new(&sha256)
        .key(key.as_ref())
        .salt(b"application-specific-salt")
        .info(b"encryption key")
        .derive(derived.as_mut_slice())?;
    println!(
        "Derived key ({} bytes): {}",
        derived.len(),
        native_ossl::util::hex_encode(derived.as_ref())
    );

    // ── Wrap an existing allocation ───────────────────────────────────────────

    let raw: Vec<u8> = vec![0x42u8; 16];
    let secret = SecretBuf::new(raw);
    // `raw` is consumed — only `secret` owns the bytes now.
    println!(
        "Wrapped allocation ({} bytes): {}",
        secret.len(),
        native_ossl::util::hex_encode(secret.as_ref())
    );

    // ── Copy from a borrowed slice ────────────────────────────────────────────

    let source = b"password";
    let copy = SecretBuf::from_slice(source);
    assert_eq!(copy.as_ref(), source.as_ref());
    println!("from_slice copy: {:?}", std::str::from_utf8(copy.as_ref())?);

    // When `key`, `derived`, `secret`, and `copy` are dropped here,
    // OPENSSL_cleanse zeroes each allocation before the heap memory is freed.

    Ok(())
}
