libcrux_hmac/
hmac.rs

1//! HMAC
2//!
3//! This crate implements HMAC on SHA 1 and SHA 2 (except for SHA 224).
4#![no_std]
5
6extern crate alloc;
7
8use alloc::vec::Vec;
9
10#[cfg(not(feature = "expose-hacl"))]
11mod hacl {
12    pub(crate) mod hash_sha1;
13    pub(crate) mod hmac;
14}
15
16#[cfg(feature = "expose-hacl")]
17pub mod hacl {
18    pub mod hash_sha1;
19    pub mod hmac;
20}
21
22mod impl_hacl;
23
24pub use impl_hacl::*;
25
26/// The HMAC algorithm defining the used hash function.
27#[derive(Copy, Clone, Debug, PartialEq)]
28pub enum Algorithm {
29    Sha1,
30    // Not implemented
31    // Sha224
32    Sha256,
33    Sha384,
34    Sha512,
35}
36
37/// Get the tag size for a given algorithm.
38pub const fn tag_size(alg: Algorithm) -> usize {
39    match alg {
40        Algorithm::Sha1 => 20,
41        Algorithm::Sha256 => 32,
42        Algorithm::Sha384 => 48,
43        Algorithm::Sha512 => 64,
44    }
45}
46
47/// Compute the HMAC value with the given `alg` and `key` on `data` with an
48/// output tag length of `tag_length`.
49/// Returns a vector of length `tag_length`.
50/// Panics if either `key` or `data` are longer than `u32::MAX`.
51pub fn hmac(alg: Algorithm, key: &[u8], data: &[u8], tag_length: Option<usize>) -> Vec<u8> {
52    let native_tag_length = tag_size(alg);
53    let tag_length = match tag_length {
54        Some(v) => v,
55        None => native_tag_length,
56    };
57    let mut dst: Vec<_> = match alg {
58        Algorithm::Sha1 => wrap_bufalloc(|buf| hmac_sha1(buf, key, data)),
59        Algorithm::Sha256 => wrap_bufalloc(|buf| hmac_sha2_256(buf, key, data)),
60        Algorithm::Sha384 => wrap_bufalloc(|buf| hmac_sha2_384(buf, key, data)),
61        Algorithm::Sha512 => wrap_bufalloc(|buf| hmac_sha2_512(buf, key, data)),
62    };
63    dst.truncate(tag_length);
64    dst
65}
66
67#[inline(always)]
68fn wrap_bufalloc<const N: usize, F: Fn(&mut [u8; N])>(f: F) -> Vec<u8> {
69    let mut buf = [0u8; N];
70    f(&mut buf);
71    buf.to_vec()
72}