Skip to main content

doido_controller/
signing.rs

1//! Shared HMAC-SHA256 signing helpers used by the cookie jar (and available to
2//! any value that needs tamper-evident transport). Signatures are base64url,
3//! no-pad, and verified in constant time.
4
5use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
6use hmac::{Hmac, KeyInit, Mac};
7use sha2::Sha256;
8
9type HmacSha256 = Hmac<Sha256>;
10
11/// Sign `msg` with `secret`, returning the base64url signature.
12pub fn sign(secret: &[u8], msg: &[u8]) -> String {
13    let mut mac = HmacSha256::new_from_slice(secret).expect("HMAC accepts a key of any length");
14    mac.update(msg);
15    URL_SAFE_NO_PAD.encode(mac.finalize().into_bytes())
16}
17
18/// Verify a base64url `signature` over `msg` under `secret` (constant time).
19pub fn verify(secret: &[u8], msg: &[u8], signature: &str) -> bool {
20    let Ok(sig) = URL_SAFE_NO_PAD.decode(signature) else {
21        return false;
22    };
23    let Ok(mut mac) = HmacSha256::new_from_slice(secret) else {
24        return false;
25    };
26    mac.update(msg);
27    mac.verify_slice(&sig).is_ok()
28}