//! MAC example — HMAC-SHA-256 and CMAC-AES-128.
//!
//! Run with: cargo run --example mac -p native-ossl

use native_ossl::cipher::CipherAlg;
use native_ossl::digest::DigestAlg;
use native_ossl::mac::{CmacCtx, HmacCtx, MacAlg, MacCtx};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let message = b"authenticate this message";

    // ── HMAC-SHA-256 ─────────────────────────────────────────────────────────

    let hmac_key = b"super secret key - 32 bytes long";
    let sha256 = DigestAlg::fetch(c"SHA2-256", None)?;

    // One-shot convenience method writes into a caller-supplied buffer.
    let mut tag = [0u8; 32];
    HmacCtx::oneshot(&sha256, hmac_key, message, &mut tag)?;
    println!(
        "HMAC-SHA-256 (one-shot): {}",
        native_ossl::util::hex_encode(tag)
    );

    // Streaming: identical result.
    let mut ctx = HmacCtx::new(&sha256, hmac_key)?;
    ctx.update(b"authenticate ")?;
    ctx.update(b"this message")?;
    let tag2 = ctx.finish_to_vec()?;
    assert_eq!(
        tag.as_ref(),
        tag2.as_slice(),
        "streaming and one-shot must agree"
    );
    println!("HMAC-SHA-256 (streaming matches one-shot): OK");

    // ── HMAC via generic MacCtx ──────────────────────────────────────────────

    let hmac_alg = MacAlg::fetch(c"HMAC", None)?;
    let mut mac_ctx = MacCtx::new(&hmac_alg)?;

    let params = native_ossl::params::ParamBuilder::new()?
        .push_utf8_string(c"digest", c"SHA2-256")?
        .build()?;
    mac_ctx.init(hmac_key, Some(&params))?;
    mac_ctx.update(message)?;

    let size = mac_ctx.mac_size();
    let mut out = vec![0u8; size];
    let written = mac_ctx.finish(&mut out)?;
    println!(
        "HMAC via MacCtx: {} bytes — {}",
        written,
        native_ossl::util::hex_encode(&out[..written])
    );

    // ── CMAC-AES-128 ─────────────────────────────────────────────────────────

    let aes128 = CipherAlg::fetch(c"AES-128-CBC", None)?;
    let cmac_key = b"0123456789abcdef"; // 16 bytes = AES-128
    let mut cmac = CmacCtx::new(&aes128, cmac_key)?;
    cmac.update(message)?;
    let mut cmac_out = [0u8; 16];
    cmac.finish(&mut cmac_out)?;
    println!("CMAC-AES-128: {}", native_ossl::util::hex_encode(cmac_out));

    Ok(())
}
