Skip to main content

libcrux_hmac/
hmac.rs

1//! HMAC
2//!
3//! This crate implements HMAC on SHA 2 (except for SHA 224) and SHA 3.
4#![no_std]
5
6#[cfg(not(feature = "expose-hacl"))]
7mod hacl {
8    pub(crate) mod hmac;
9}
10
11#[cfg(feature = "expose-hacl")]
12pub mod hacl {
13    pub mod hmac;
14}
15
16mod impl_hacl;
17mod incremental;
18
19pub use impl_hacl::*;
20pub use incremental::*;
21
22/// Streaming HMAC state.
23///
24/// Initialize with the concrete type's `new(key)` constructor, feed data
25/// fragments with [`update`](HmacState::update), and obtain the tag with
26/// [`finalize`](HmacState::finalize).
27///
28/// Implementations are available as [`HmacSha256`], [`HmacSha384`], and
29/// [`HmacSha512`].
30pub trait HmacState<const OUTLEN: usize> {
31    /// Create a new [`HmacState`].
32    fn new(key: &[u8]) -> Result<Self, Error>
33    where
34        Self: Sized;
35
36    /// Feed a data fragment into the HMAC computation.
37    fn update(&mut self, data: &[u8]) -> Result<(), Error>;
38
39    /// Finalize the HMAC and write the tag into `dst`.
40    fn finalize(self, dst: &mut [u8; OUTLEN]);
41}
42
43/// HMAC Errors
44#[derive(Debug)]
45pub enum Error {
46    InvalidInputLength,
47}
48
49/// The HMAC algorithm defining the used hash function.
50///
51/// * `Sha256`, `Sha384`, and `Sha512` are SHA-2.
52/// * SHA-3 variants are prefixed with `Sha3_`.
53#[derive(Copy, Clone, Debug, PartialEq)]
54pub enum Algorithm {
55    // Not implemented
56    // Sha224
57    Sha256,
58    Sha384,
59    Sha512,
60    Sha3_224,
61    Sha3_256,
62    Sha3_384,
63    Sha3_512,
64}
65
66const SHA256_TAG_SIZE: usize = 32;
67const SHA384_TAG_SIZE: usize = 48;
68const SHA512_TAG_SIZE: usize = 64;
69const SHA3_224_TAG_SIZE: usize = 28;
70const SHA3_256_TAG_SIZE: usize = 32;
71const SHA3_384_TAG_SIZE: usize = 48;
72const SHA3_512_TAG_SIZE: usize = 64;
73
74/// Get the tag size for a given algorithm.
75pub const fn tag_size(alg: Algorithm) -> usize {
76    match alg {
77        Algorithm::Sha256 => SHA256_TAG_SIZE,
78        Algorithm::Sha384 => SHA384_TAG_SIZE,
79        Algorithm::Sha512 => SHA512_TAG_SIZE,
80        Algorithm::Sha3_224 => SHA3_224_TAG_SIZE,
81        Algorithm::Sha3_256 => SHA3_256_TAG_SIZE,
82        Algorithm::Sha3_384 => SHA3_384_TAG_SIZE,
83        Algorithm::Sha3_512 => SHA3_512_TAG_SIZE,
84    }
85}
86
87/// Compute the HMAC value with the given `alg` and `key` on `data`.
88/// Writes the tag into the provided output buffer `tag`.
89///
90/// If the output buffer is shorter than the native output length of
91/// `alg` the tag will be truncated to the output buffer's length. If
92/// the output buffer is longer than the native output length of
93/// `alg`, the tag will be written to the beginning of the output
94/// buffer, leaving the rest unchanged.  Panics if either `key` or
95/// `data` are longer than `u32::MAX`.
96pub fn hmac(alg: Algorithm, key: &[u8], data: &[u8], tag: &mut [u8]) {
97    let tag_len = core::cmp::min(tag.len(), tag_size(alg));
98    match alg {
99        Algorithm::Sha256 => {
100            let mut buf = [0u8; SHA256_TAG_SIZE];
101            hmac_sha2_256(&mut buf, key, data);
102            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
103        }
104        Algorithm::Sha384 => {
105            let mut buf = [0u8; SHA384_TAG_SIZE];
106            hmac_sha2_384(&mut buf, key, data);
107            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
108        }
109        Algorithm::Sha512 => {
110            let mut buf = [0u8; SHA512_TAG_SIZE];
111            hmac_sha2_512(&mut buf, key, data);
112            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
113        }
114        Algorithm::Sha3_224 => {
115            let mut buf = [0u8; SHA3_224_TAG_SIZE];
116            hmac_sha3_224(&mut buf, key, data).expect("HMAC-SHA3 input too long");
117            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
118        }
119        Algorithm::Sha3_256 => {
120            let mut buf = [0u8; SHA3_256_TAG_SIZE];
121            hmac_sha3_256(&mut buf, key, data).expect("HMAC-SHA3 input too long");
122            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
123        }
124        Algorithm::Sha3_384 => {
125            let mut buf = [0u8; SHA3_384_TAG_SIZE];
126            hmac_sha3_384(&mut buf, key, data).expect("HMAC-SHA3 input too long");
127            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
128        }
129        Algorithm::Sha3_512 => {
130            let mut buf = [0u8; SHA3_512_TAG_SIZE];
131            hmac_sha3_512(&mut buf, key, data).expect("HMAC-SHA3 input too long");
132            tag[..tag_len].copy_from_slice(&buf[..tag_len]);
133        }
134    };
135}