1use libcrux_traits::digest::{arrayref, InitializeDigestState};
2
3use crate::{Error, HmacState};
4
5pub struct HmacStream<const OUTLEN: usize, const BLOCK: usize, D>
11where
12 D: arrayref::DigestIncremental<OUTLEN>,
13 D::IncrementalState: InitializeDigestState,
14{
15 pub(crate) inner: D::IncrementalState,
17 pub(crate) opad: [u8; BLOCK],
18}
19
20impl<const OUTLEN: usize, const BLOCK: usize, Digest> HmacState<OUTLEN>
21 for HmacStream<OUTLEN, BLOCK, Digest>
22where
23 Digest: arrayref::DigestIncremental<OUTLEN>,
24 Digest::IncrementalState: InitializeDigestState,
25{
26 fn new(key: &[u8]) -> Result<Self, Error> {
28 debug_assert!(OUTLEN <= BLOCK);
29 debug_assert!(BLOCK <= u32::MAX as usize);
30
31 if key.len() > u32::MAX as usize {
32 return Err(Error::InvalidInputLength);
33 }
34
35 let mut key_block = [0u8; BLOCK];
36 if key.len() <= BLOCK {
37 key_block[..key.len()].copy_from_slice(key);
38 } else {
39 let mut tmp = Digest::IncrementalState::new();
41 Digest::update(&mut tmp, key)
42 .expect("This can't fail because we checked that key.len() <= u32::MAX");
43 let mut hashed = [0u8; OUTLEN];
44 Digest::finish(tmp, &mut hashed);
45 key_block[..OUTLEN].copy_from_slice(&hashed);
46 }
47
48 let mut k_xor_ipad = [0u8; BLOCK];
49 let mut k_xor_opad = [0u8; BLOCK];
50
51 for i in 0..BLOCK {
52 k_xor_ipad[i] = key_block[i] ^ 0x36;
53 k_xor_opad[i] = key_block[i] ^ 0x5c;
54 }
55
56 let mut inner = Digest::IncrementalState::new();
60 Digest::update(&mut inner, &k_xor_ipad).expect("HMAC: ipad update failed");
61
62 Ok(Self {
63 inner,
64 opad: k_xor_opad,
65 })
66 }
67
68 fn update(&mut self, data: &[u8]) -> Result<(), Error> {
69 Digest::update(&mut self.inner, data).map_err(|_| Error::InvalidInputLength)
70 }
71
72 fn finalize(self, dst: &mut [u8; OUTLEN]) {
73 let mut inner_hash = [0u8; OUTLEN];
75 Digest::finish(self.inner, &mut inner_hash);
76
77 let mut outer = Digest::IncrementalState::new();
79 Digest::update(&mut outer, &self.opad).expect("self.opad.len() is always <= u32::MAX");
80 Digest::update(&mut outer, &inner_hash).expect("inner_hash.len() is always <= u32::MAX");
81 Digest::finish(outer, dst);
82 }
83}
84
85pub type HmacSha256 = HmacStream<32, 64, libcrux_sha2::Sha256Hash>;
87
88pub type HmacSha384 = HmacStream<48, 128, libcrux_sha2::Sha384Hash>;
90
91pub type HmacSha512 = HmacStream<64, 128, libcrux_sha2::Sha512Hash>;
93
94pub type HmacSha3_224 = HmacStream<28, 144, libcrux_sha3::Sha3_224>;
96
97pub type HmacSha3_256 = HmacStream<32, 136, libcrux_sha3::Sha3_256>;
99
100pub type HmacSha3_384 = HmacStream<48, 104, libcrux_sha3::Sha3_384>;
102
103pub type HmacSha3_512 = HmacStream<64, 72, libcrux_sha3::Sha3_512>;
105
106pub fn hmac_slices<const OUTLEN: usize, Hmac: HmacState<OUTLEN>>(
107 dst: &mut [u8; OUTLEN],
108 key: &[u8],
109 slices: &[&[u8]],
110) -> Result<(), Error> {
111 let mut state = Hmac::new(key)?;
112
113 for &s in slices {
114 state.update(s)?;
115 }
116
117 state.finalize(dst);
118 Ok(())
119}
120
121#[inline]
123pub fn hmac_sha2_256_slices(dst: &mut [u8; 32], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
124 hmac_slices::<32, HmacSha256>(dst, key, slices)
125}
126
127#[inline]
129pub fn hmac_sha2_384_slices(dst: &mut [u8; 48], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
130 hmac_slices::<48, HmacSha384>(dst, key, slices)
131}
132
133#[inline]
135pub fn hmac_sha2_512_slices(dst: &mut [u8; 64], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
136 hmac_slices::<64, HmacSha512>(dst, key, slices)
137}
138
139#[inline]
141pub fn hmac_sha3_224_slices(dst: &mut [u8; 28], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
142 hmac_slices::<28, HmacSha3_224>(dst, key, slices)
143}
144
145#[inline]
147pub fn hmac_sha3_256_slices(dst: &mut [u8; 32], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
148 hmac_slices::<32, HmacSha3_256>(dst, key, slices)
149}
150
151#[inline]
153pub fn hmac_sha3_384_slices(dst: &mut [u8; 48], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
154 hmac_slices::<48, HmacSha3_384>(dst, key, slices)
155}
156
157#[inline]
159pub fn hmac_sha3_512_slices(dst: &mut [u8; 64], key: &[u8], slices: &[&[u8]]) -> Result<(), Error> {
160 hmac_slices::<64, HmacSha3_512>(dst, key, slices)
161}
162
163#[inline]
165pub fn hmac_sha3_224(dst: &mut [u8; 28], key: &[u8], data: &[u8]) -> Result<(), Error> {
166 hmac_sha3_224_slices(dst, key, &[data])
167}
168
169#[inline]
171pub fn hmac_sha3_256(dst: &mut [u8; 32], key: &[u8], data: &[u8]) -> Result<(), Error> {
172 hmac_sha3_256_slices(dst, key, &[data])
173}
174
175#[inline]
177pub fn hmac_sha3_384(dst: &mut [u8; 48], key: &[u8], data: &[u8]) -> Result<(), Error> {
178 hmac_sha3_384_slices(dst, key, &[data])
179}
180
181#[inline]
183pub fn hmac_sha3_512(dst: &mut [u8; 64], key: &[u8], data: &[u8]) -> Result<(), Error> {
184 hmac_sha3_512_slices(dst, key, &[data])
185}