use anyhow::{Result, anyhow}; use chacha20poly1305::aead::{Aead, KeyInit, Payload}; use chacha20poly1305::{ChaCha20Poly1305, Key, Nonce}; use hkdf::Hkdf; use hmac::{Hmac, Mac}; use rand::RngCore; use sha2::{Digest, Sha256}; pub type HmacSha256 = Hmac; pub fn random_32() -> [u8; 32] { let mut out = [0u8; 32]; rand::thread_rng().fill_bytes(&mut out); out } pub fn random_16() -> [u8; 16] { let mut out = [0u8; 16]; rand::thread_rng().fill_bytes(&mut out); out } pub fn random_12() -> [u8; 12] { let mut out = [0u8; 12]; rand::thread_rng().fill_bytes(&mut out); out } pub fn hmac_sha256(key: &[u8], parts: &[&[u8]]) -> [u8; 32] { let mut mac = ::new_from_slice(key).expect("HMAC accepts any key size"); for part in parts { mac.update(part); } mac.finalize().into_bytes().into() } pub fn verify_hmac(key: &[u8], parts: &[&[u8]], expected: &[u8; 32]) -> bool { let actual = hmac_sha256(key, parts); constant_time_eq(&actual, expected) } pub fn sha256(data: &[u8]) -> [u8; 32] { Sha256::digest(data).into() } pub fn hkdf32(secret: &[u8], salt: &[u8], info: &[u8]) -> Result<[u8; 32]> { let hk = Hkdf::::new(Some(salt), secret); let mut out = [0u8; 32]; hk.expand(info, &mut out) .map_err(|_| anyhow!("HKDF expand failed"))?; Ok(out) } pub fn nonce_from(direction: u32, seq: u64) -> [u8; 12] { let mut nonce = [0u8; 12]; nonce[..4].copy_from_slice(&direction.to_be_bytes()); nonce[4..].copy_from_slice(&seq.to_be_bytes()); nonce } pub fn seal(key: &[u8; 32], nonce: &[u8; 12], aad: &[u8], plaintext: &[u8]) -> Result> { let cipher = ChaCha20Poly1305::new(Key::from_slice(key)); cipher .encrypt( Nonce::from_slice(nonce), Payload { msg: plaintext, aad, }, ) .map_err(|_| anyhow!("encrypt failed")) } pub fn open(key: &[u8; 32], nonce: &[u8; 12], aad: &[u8], ciphertext: &[u8]) -> Result> { let cipher = ChaCha20Poly1305::new(Key::from_slice(key)); cipher .decrypt( Nonce::from_slice(nonce), Payload { msg: ciphertext, aad, }, ) .map_err(|_| anyhow!("decrypt failed")) } fn constant_time_eq(a: &[u8], b: &[u8]) -> bool { if a.len() != b.len() { return false; } let mut diff = 0u8; for (x, y) in a.iter().zip(b.iter()) { diff |= x ^ y; } diff == 0 }