hmac_sha256/
lib.rs

1//! A small, self-contained SHA256, HMAC-SHA256, and HKDF-SHA256 implementation
2//! (C) Frank Denis <fdenis [at] fastly [dot] com>
3//!
4//! This library provides a lightweight implementation of SHA-256, HMAC-SHA256, and HKDF-SHA256
5//! cryptographic functions with no external dependencies (unless the `traits` feature is enabled).
6//!
7//! # Features
8//!
9//! - `traits`: Enables support for the `Digest` trait from the `digest` crate
10//! - `opt_size`: Enables size optimizations (reduces `.text` section size by ~75% with ~16% performance cost)
11//!
12//! # Examples
13//!
14//! ```
15//! // Calculate a SHA-256 hash
16//! let hash = hmac_sha256::Hash::hash(b"hello world");
17//!
18//! // Verify a hash in one shot
19//! let expected = hmac_sha256::Hash::hash(b"hello world");
20//! assert!(hmac_sha256::Hash::verify(b"hello world", &expected));
21//!
22//! // Create an HMAC-SHA256
23//! let mac = hmac_sha256::HMAC::mac(b"message", b"key");
24//!
25//! // Verify an HMAC-SHA256 in one shot
26//! let expected = hmac_sha256::HMAC::mac(b"message", b"key");
27//! assert!(hmac_sha256::HMAC::verify(b"message", b"key", &expected));
28//!
29//! // Use HKDF-SHA256 for key derivation
30//! let prk = hmac_sha256::HKDF::extract(b"salt", b"input key material");
31//! let mut output = [0u8; 32];
32//! hmac_sha256::HKDF::expand(&mut output, prk, b"context info");
33//! ```
34
35#![no_std]
36#![allow(
37    non_snake_case,
38    clippy::cast_lossless,
39    clippy::eq_op,
40    clippy::identity_op,
41    clippy::many_single_char_names,
42    clippy::unreadable_literal
43)]
44
45#[inline(always)]
46fn load_be(base: &[u8], offset: usize) -> u32 {
47    let addr = &base[offset..];
48    (addr[3] as u32) | (addr[2] as u32) << 8 | (addr[1] as u32) << 16 | (addr[0] as u32) << 24
49}
50
51#[inline(always)]
52fn store_be(base: &mut [u8], offset: usize, x: u32) {
53    let addr = &mut base[offset..];
54    addr[3] = x as u8;
55    addr[2] = (x >> 8) as u8;
56    addr[1] = (x >> 16) as u8;
57    addr[0] = (x >> 24) as u8;
58}
59
60fn verify(x: &[u8], y: &[u8]) -> bool {
61    if x.len() != y.len() {
62        return false;
63    }
64    let mut v: u32 = 0;
65
66    #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
67    {
68        let (mut h1, mut h2) = (0u32, 0u32);
69        for (b1, b2) in x.iter().zip(y.iter()) {
70            h1 ^= (h1 << 5).wrapping_add((h1 >> 2) ^ *b1 as u32);
71            h2 ^= (h2 << 5).wrapping_add((h2 >> 2) ^ *b2 as u32);
72        }
73        v |= h1 ^ h2;
74    }
75    for (a, b) in x.iter().zip(y.iter()) {
76        v |= (a ^ b) as u32;
77    }
78    let v = unsafe { core::ptr::read_volatile(&v) };
79    v == 0
80}
81
82struct W([u32; 16]);
83
84#[derive(Copy, Clone)]
85struct State([u32; 8]);
86
87impl W {
88    fn new(input: &[u8]) -> Self {
89        let mut w = [0u32; 16];
90        for (i, e) in w.iter_mut().enumerate() {
91            *e = load_be(input, i * 4)
92        }
93        W(w)
94    }
95
96    #[inline(always)]
97    fn Ch(x: u32, y: u32, z: u32) -> u32 {
98        (x & y) ^ (!x & z)
99    }
100
101    #[inline(always)]
102    fn Maj(x: u32, y: u32, z: u32) -> u32 {
103        (x & y) ^ (x & z) ^ (y & z)
104    }
105
106    #[inline(always)]
107    fn Sigma0(x: u32) -> u32 {
108        x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
109    }
110
111    #[inline(always)]
112    fn Sigma1(x: u32) -> u32 {
113        x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
114    }
115
116    #[inline(always)]
117    fn sigma0(x: u32) -> u32 {
118        x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
119    }
120
121    #[inline(always)]
122    fn sigma1(x: u32) -> u32 {
123        x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
124    }
125
126    #[cfg_attr(feature = "opt_size", inline(never))]
127    #[cfg_attr(not(feature = "opt_size"), inline(always))]
128    fn M(&mut self, a: usize, b: usize, c: usize, d: usize) {
129        let w = &mut self.0;
130        w[a] = w[a]
131            .wrapping_add(Self::sigma1(w[b]))
132            .wrapping_add(w[c])
133            .wrapping_add(Self::sigma0(w[d]));
134    }
135
136    #[inline]
137    fn expand(&mut self) {
138        self.M(0, (0 + 14) & 15, (0 + 9) & 15, (0 + 1) & 15);
139        self.M(1, (1 + 14) & 15, (1 + 9) & 15, (1 + 1) & 15);
140        self.M(2, (2 + 14) & 15, (2 + 9) & 15, (2 + 1) & 15);
141        self.M(3, (3 + 14) & 15, (3 + 9) & 15, (3 + 1) & 15);
142        self.M(4, (4 + 14) & 15, (4 + 9) & 15, (4 + 1) & 15);
143        self.M(5, (5 + 14) & 15, (5 + 9) & 15, (5 + 1) & 15);
144        self.M(6, (6 + 14) & 15, (6 + 9) & 15, (6 + 1) & 15);
145        self.M(7, (7 + 14) & 15, (7 + 9) & 15, (7 + 1) & 15);
146        self.M(8, (8 + 14) & 15, (8 + 9) & 15, (8 + 1) & 15);
147        self.M(9, (9 + 14) & 15, (9 + 9) & 15, (9 + 1) & 15);
148        self.M(10, (10 + 14) & 15, (10 + 9) & 15, (10 + 1) & 15);
149        self.M(11, (11 + 14) & 15, (11 + 9) & 15, (11 + 1) & 15);
150        self.M(12, (12 + 14) & 15, (12 + 9) & 15, (12 + 1) & 15);
151        self.M(13, (13 + 14) & 15, (13 + 9) & 15, (13 + 1) & 15);
152        self.M(14, (14 + 14) & 15, (14 + 9) & 15, (14 + 1) & 15);
153        self.M(15, (15 + 14) & 15, (15 + 9) & 15, (15 + 1) & 15);
154    }
155
156    #[cfg_attr(feature = "opt_size", inline(never))]
157    #[cfg_attr(not(feature = "opt_size"), inline(always))]
158    fn F(&mut self, state: &mut State, i: usize, k: u32) {
159        let t = &mut state.0;
160        t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
161            .wrapping_add(Self::Sigma1(t[(16 - i + 4) & 7]))
162            .wrapping_add(Self::Ch(
163                t[(16 - i + 4) & 7],
164                t[(16 - i + 5) & 7],
165                t[(16 - i + 6) & 7],
166            ))
167            .wrapping_add(k)
168            .wrapping_add(self.0[i]);
169        t[(16 - i + 3) & 7] = t[(16 - i + 3) & 7].wrapping_add(t[(16 - i + 7) & 7]);
170        t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
171            .wrapping_add(Self::Sigma0(t[(16 - i + 0) & 7]))
172            .wrapping_add(Self::Maj(
173                t[(16 - i + 0) & 7],
174                t[(16 - i + 1) & 7],
175                t[(16 - i + 2) & 7],
176            ));
177    }
178
179    fn G(&mut self, state: &mut State, s: usize) {
180        const ROUND_CONSTANTS: [u32; 64] = [
181            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
182            0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
183            0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
184            0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
185            0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
186            0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
187            0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
188            0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
189            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
190            0xc67178f2,
191        ];
192        let rc = &ROUND_CONSTANTS[s * 16..];
193        self.F(state, 0, rc[0]);
194        self.F(state, 1, rc[1]);
195        self.F(state, 2, rc[2]);
196        self.F(state, 3, rc[3]);
197        self.F(state, 4, rc[4]);
198        self.F(state, 5, rc[5]);
199        self.F(state, 6, rc[6]);
200        self.F(state, 7, rc[7]);
201        self.F(state, 8, rc[8]);
202        self.F(state, 9, rc[9]);
203        self.F(state, 10, rc[10]);
204        self.F(state, 11, rc[11]);
205        self.F(state, 12, rc[12]);
206        self.F(state, 13, rc[13]);
207        self.F(state, 14, rc[14]);
208        self.F(state, 15, rc[15]);
209    }
210}
211
212impl State {
213    fn new() -> Self {
214        const IV: [u8; 32] = [
215            0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f,
216            0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab,
217            0x5b, 0xe0, 0xcd, 0x19,
218        ];
219        let mut t = [0u32; 8];
220        for (i, e) in t.iter_mut().enumerate() {
221            *e = load_be(&IV, i * 4)
222        }
223        State(t)
224    }
225
226    #[inline(always)]
227    fn add(&mut self, x: &State) {
228        let sx = &mut self.0;
229        let ex = &x.0;
230        sx[0] = sx[0].wrapping_add(ex[0]);
231        sx[1] = sx[1].wrapping_add(ex[1]);
232        sx[2] = sx[2].wrapping_add(ex[2]);
233        sx[3] = sx[3].wrapping_add(ex[3]);
234        sx[4] = sx[4].wrapping_add(ex[4]);
235        sx[5] = sx[5].wrapping_add(ex[5]);
236        sx[6] = sx[6].wrapping_add(ex[6]);
237        sx[7] = sx[7].wrapping_add(ex[7]);
238    }
239
240    fn store(&self, out: &mut [u8]) {
241        for (i, &e) in self.0.iter().enumerate() {
242            store_be(out, i * 4, e);
243        }
244    }
245
246    fn blocks(&mut self, mut input: &[u8]) -> usize {
247        let mut t = *self;
248        let mut inlen = input.len();
249        while inlen >= 64 {
250            let mut w = W::new(input);
251            w.G(&mut t, 0);
252            w.expand();
253            w.G(&mut t, 1);
254            w.expand();
255            w.G(&mut t, 2);
256            w.expand();
257            w.G(&mut t, 3);
258            t.add(self);
259            self.0 = t.0;
260            input = &input[64..];
261            inlen -= 64;
262        }
263        inlen
264    }
265}
266
267#[derive(Copy, Clone)]
268/// SHA-256 hash implementation.
269///
270/// This struct provides both streaming and one-shot APIs for computing SHA-256 hashes.
271///
272/// # Examples
273///
274/// One-shot hashing:
275/// ```
276/// let hash = hmac_sha256::Hash::hash(b"hello world");
277/// ```
278///
279/// Incremental hashing:
280/// ```
281/// let mut hasher = hmac_sha256::Hash::new();
282/// hasher.update(b"hello ");
283/// hasher.update(b"world");
284/// let hash = hasher.finalize();
285/// ```
286pub struct Hash {
287    state: State,
288    w: [u8; 64],
289    r: usize,
290    len: usize,
291}
292
293impl Hash {
294    /// Creates a new SHA-256 hasher.
295    pub fn new() -> Hash {
296        Hash {
297            state: State::new(),
298            r: 0,
299            w: [0u8; 64],
300            len: 0,
301        }
302    }
303
304    fn _update(&mut self, input: impl AsRef<[u8]>) {
305        let input = input.as_ref();
306        let mut n = input.len();
307        self.len += n;
308        let av = 64 - self.r;
309        let tc = ::core::cmp::min(n, av);
310        self.w[self.r..self.r + tc].copy_from_slice(&input[0..tc]);
311        self.r += tc;
312        n -= tc;
313        let pos = tc;
314        if self.r == 64 {
315            self.state.blocks(&self.w);
316            self.r = 0;
317        }
318        if self.r == 0 && n > 0 {
319            let rb = self.state.blocks(&input[pos..]);
320            if rb > 0 {
321                self.w[..rb].copy_from_slice(&input[pos + n - rb..]);
322                self.r = rb;
323            }
324        }
325    }
326
327    /// Absorbs content into the hasher state.
328    ///
329    /// This method can be called multiple times to incrementally add data to be hashed.
330    ///
331    /// # Example
332    ///
333    /// ```
334    /// let mut hasher = hmac_sha256::Hash::new();
335    /// hasher.update(b"first chunk");
336    /// hasher.update(b"second chunk");
337    /// let hash = hasher.finalize();
338    /// ```
339    pub fn update(&mut self, input: impl AsRef<[u8]>) {
340        self._update(input)
341    }
342
343    /// Computes the SHA-256 hash of all previously absorbed content.
344    ///
345    /// This method consumes the hasher and returns the computed 32-byte digest.
346    ///
347    /// # Example
348    ///
349    /// ```
350    /// let mut hasher = hmac_sha256::Hash::new();
351    /// hasher.update(b"data to hash");
352    /// let hash: [u8; 32] = hasher.finalize();
353    /// ```
354    pub fn finalize(mut self) -> [u8; 32] {
355        let mut padded = [0u8; 128];
356        padded[..self.r].copy_from_slice(&self.w[..self.r]);
357        padded[self.r] = 0x80;
358        let r = if self.r < 56 { 64 } else { 128 };
359        let bits = self.len * 8;
360        for i in 0..8 {
361            padded[r - 8 + i] = (bits as u64 >> (56 - i * 8)) as u8;
362        }
363        self.state.blocks(&padded[..r]);
364        let mut out = [0u8; 32];
365        self.state.store(&mut out);
366        out
367    }
368
369    /// Verifies that the hash of absorbed content matches the expected digest.
370    ///
371    /// This provides constant-time comparison to prevent timing attacks.
372    ///
373    /// # Example
374    ///
375    /// ```
376    /// let expected = hmac_sha256::Hash::hash(b"original data");
377    ///
378    /// let mut hasher = hmac_sha256::Hash::new();
379    /// hasher.update(b"original data");
380    /// assert!(hasher.finalize_verify(&expected));
381    ///
382    /// let mut hasher = hmac_sha256::Hash::new();
383    /// hasher.update(b"modified data");
384    /// assert!(!hasher.finalize_verify(&expected));
385    /// ```
386    pub fn finalize_verify(self, expected: &[u8; 32]) -> bool {
387        let out = self.finalize();
388        verify(&out, expected)
389    }
390
391    /// Hashes the provided input and verifies it against the expected digest in a single operation.
392    ///
393    /// This is a convenience method that combines hashing and verification in a single call.
394    /// It provides constant-time comparison to prevent timing attacks.
395    ///
396    /// # Example
397    ///
398    /// ```
399    /// let expected = hmac_sha256::Hash::hash(b"original data");
400    ///
401    /// // Verify in one shot
402    /// assert!(hmac_sha256::Hash::verify(b"original data", &expected));
403    /// assert!(!hmac_sha256::Hash::verify(b"modified data", &expected));
404    /// ```
405    pub fn verify(input: impl AsRef<[u8]>, expected: &[u8; 32]) -> bool {
406        let hash = Self::hash(input.as_ref());
407        verify(&hash, expected)
408    }
409
410    /// Verifies that the hash of absorbed content matches the expected digest using a reference.
411    ///
412    /// This method accepts a reference to a slice of bytes and verifies against it using
413    /// constant-time comparison to prevent timing attacks. Unlike `finalize_verify`, this method
414    /// does not require the expected value to be exactly 32 bytes, but will return `false` if
415    /// the length is not 32 bytes.
416    ///
417    /// # Arguments
418    ///
419    /// * `expected` - The expected hash value to compare against
420    ///
421    /// # Returns
422    ///
423    /// `true` if the computed hash matches the expected value, `false` otherwise
424    ///
425    /// # Example
426    ///
427    /// ```
428    /// let expected = hmac_sha256::Hash::hash(b"original data");
429    ///
430    /// let mut hasher = hmac_sha256::Hash::new();
431    /// hasher.update(b"original data");
432    /// assert!(hasher.verify_with_ref(&expected));
433    ///
434    /// // Can also verify with a slice
435    /// let expected_slice = &expected[..];
436    /// let mut hasher2 = hmac_sha256::Hash::new();
437    /// hasher2.update(b"original data");
438    /// assert!(hasher2.verify_with_ref(expected_slice));
439    ///
440    /// // Or use the one-shot verification
441    /// assert!(hmac_sha256::Hash::verify(b"original data", &expected));
442    /// ```
443    pub fn verify_with_ref(self, expected: &[u8]) -> bool {
444        if expected.len() != 32 {
445            return false;
446        }
447        let out = self.finalize();
448        verify(&out, expected)
449    }
450
451    /// Computes the SHA-256 hash of the provided input in a single operation.
452    ///
453    /// This is a convenience method for simple hashing operations.
454    ///
455    /// # Example
456    ///
457    /// ```
458    /// let hash = hmac_sha256::Hash::hash(b"data to hash");
459    /// ```
460    pub fn hash(input: &[u8]) -> [u8; 32] {
461        let mut h = Hash::new();
462        h.update(input);
463        h.finalize()
464    }
465}
466
467impl Default for Hash {
468    fn default() -> Self {
469        Self::new()
470    }
471}
472
473#[derive(Clone)]
474/// HMAC-SHA256 implementation.
475///
476/// This struct provides both streaming and one-shot APIs for computing HMAC-SHA256.
477///
478/// # Examples
479///
480/// One-shot HMAC computation:
481/// ```
482/// let mac = hmac_sha256::HMAC::mac(b"message data", b"secret key");
483/// ```
484///
485/// Incremental HMAC computation:
486/// ```
487/// let mut hmac = hmac_sha256::HMAC::new(b"secret key");
488/// hmac.update(b"first part");
489/// hmac.update(b"second part");
490/// let mac = hmac.finalize();
491/// ```
492pub struct HMAC {
493    ih: Hash,
494    padded: [u8; 64],
495}
496
497impl HMAC {
498    /// Computes the HMAC-SHA256 of the provided input using the given key in a single operation.
499    ///
500    /// This is a convenience method for simple HMAC operations.
501    ///
502    /// # Arguments
503    ///
504    /// * `input` - The message data to authenticate
505    /// * `k` - The secret key
506    ///
507    /// # Returns
508    ///
509    /// A 32-byte HMAC-SHA256 message authentication code
510    ///
511    /// # Example
512    ///
513    /// ```
514    /// let mac = hmac_sha256::HMAC::mac(b"message data", b"secret key");
515    /// ```
516    pub fn mac(input: impl AsRef<[u8]>, k: impl AsRef<[u8]>) -> [u8; 32] {
517        let input = input.as_ref();
518        let k = k.as_ref();
519        let mut hk = [0u8; 32];
520        let k2 = if k.len() > 64 {
521            hk.copy_from_slice(&Hash::hash(k));
522            &hk
523        } else {
524            k
525        };
526        let mut padded = [0x36; 64];
527        for (p, &k) in padded.iter_mut().zip(k2.iter()) {
528            *p ^= k;
529        }
530        let mut ih = Hash::new();
531        ih.update(&padded[..]);
532        ih.update(input);
533
534        for p in padded.iter_mut() {
535            *p ^= 0x6a;
536        }
537        let mut oh = Hash::new();
538        oh.update(&padded[..]);
539        oh.update(ih.finalize());
540        oh.finalize()
541    }
542
543    /// Creates a new HMAC-SHA256 instance with the given key.
544    ///
545    /// # Arguments
546    ///
547    /// * `k` - The secret key
548    ///
549    /// # Example
550    ///
551    /// ```
552    /// let mut hmac = hmac_sha256::HMAC::new(b"secret key");
553    /// ```
554    pub fn new(k: impl AsRef<[u8]>) -> HMAC {
555        let k = k.as_ref();
556        let mut hk = [0u8; 32];
557        let k2 = if k.len() > 64 {
558            hk.copy_from_slice(&Hash::hash(k));
559            &hk
560        } else {
561            k
562        };
563        let mut padded = [0x36; 64];
564        for (p, &k) in padded.iter_mut().zip(k2.iter()) {
565            *p ^= k;
566        }
567        let mut ih = Hash::new();
568        ih.update(&padded[..]);
569        HMAC { ih, padded }
570    }
571
572    /// Absorbs content into the HMAC state.
573    ///
574    /// This method can be called multiple times to incrementally add data to be authenticated.
575    ///
576    /// # Example
577    ///
578    /// ```
579    /// let mut hmac = hmac_sha256::HMAC::new(b"secret key");
580    /// hmac.update(b"first chunk");
581    /// hmac.update(b"second chunk");
582    /// let mac = hmac.finalize();
583    /// ```
584    pub fn update(&mut self, input: impl AsRef<[u8]>) {
585        self.ih.update(input);
586    }
587
588    /// Computes the HMAC-SHA256 of all previously absorbed content.
589    ///
590    /// This method consumes the HMAC instance and returns the computed 32-byte authentication code.
591    ///
592    /// # Example
593    ///
594    /// ```
595    /// let mut hmac = hmac_sha256::HMAC::new(b"secret key");
596    /// hmac.update(b"message data");
597    /// let mac: [u8; 32] = hmac.finalize();
598    /// ```
599    pub fn finalize(mut self) -> [u8; 32] {
600        for p in self.padded.iter_mut() {
601            *p ^= 0x6a;
602        }
603        let mut oh = Hash::new();
604        oh.update(&self.padded[..]);
605        oh.update(self.ih.finalize());
606        oh.finalize()
607    }
608
609    /// Verifies that the HMAC of absorbed content matches the expected MAC.
610    ///
611    /// This provides constant-time comparison to prevent timing attacks.
612    ///
613    /// # Example
614    ///
615    /// ```
616    /// let expected = hmac_sha256::HMAC::mac(b"message", b"key");
617    ///
618    /// let mut hmac = hmac_sha256::HMAC::new(b"key");
619    /// hmac.update(b"message");
620    /// assert!(hmac.finalize_verify(&expected));
621    ///
622    /// let mut hmac = hmac_sha256::HMAC::new(b"key");
623    /// hmac.update(b"modified message");
624    /// assert!(!hmac.finalize_verify(&expected));
625    /// ```
626    pub fn finalize_verify(self, expected: &[u8; 32]) -> bool {
627        let out = self.finalize();
628        verify(&out, expected)
629    }
630
631    /// Verifies that the HMAC of the provided input using the given key matches the expected MAC.
632    ///
633    /// This is a convenience method that combines HMAC computation and verification in a single call.
634    /// It provides constant-time comparison to prevent timing attacks.
635    ///
636    /// # Arguments
637    ///
638    /// * `input` - The message data to authenticate
639    /// * `k` - The secret key
640    /// * `expected` - The expected HMAC value to compare against
641    ///
642    /// # Returns
643    ///
644    /// `true` if the computed HMAC matches the expected value, `false` otherwise
645    ///
646    /// # Example
647    ///
648    /// ```
649    /// let mac = hmac_sha256::HMAC::mac(b"message", b"key");
650    ///
651    /// // Verify in one shot
652    /// assert!(hmac_sha256::HMAC::verify(b"message", b"key", &mac));
653    /// assert!(!hmac_sha256::HMAC::verify(b"modified message", b"key", &mac));
654    /// ```
655    pub fn verify(input: impl AsRef<[u8]>, k: impl AsRef<[u8]>, expected: &[u8; 32]) -> bool {
656        let mac = Self::mac(input, k);
657        verify(&mac, expected)
658    }
659}
660
661/// HMAC-based Key Derivation Function (HKDF) implementation using SHA-256.
662///
663/// HKDF is a key derivation function based on HMAC, standardized in [RFC 5869](https://tools.ietf.org/html/rfc5869).
664/// It is used to derive one or more cryptographically strong keys from input keying material.
665///
666/// The HKDF process consists of two stages:
667/// 1. Extract: Takes input keying material and an optional salt, and produces a pseudorandom key (PRK)
668/// 2. Expand: Takes the PRK, optional context information, and desired output length to generate output keying material
669///
670/// # Examples
671///
672/// Basic usage:
673/// ```
674/// // Extract a pseudorandom key from input keying material using a salt
675/// let prk = hmac_sha256::HKDF::extract(b"salt value", b"input key material");
676///
677/// // Expand the PRK into output keying material of desired length
678/// let mut okm = [0u8; 64]; // 64 bytes of output keying material
679/// hmac_sha256::HKDF::expand(&mut okm, prk, b"application info");
680/// ```
681pub struct HKDF;
682
683impl HKDF {
684    /// Performs the HKDF-Extract function (first stage of HKDF).
685    ///
686    /// Extracts a pseudorandom key from the input keying material using the optional salt.
687    ///
688    /// # Arguments
689    ///
690    /// * `salt` - Optional salt value (a non-secret random value)
691    /// * `ikm` - Input keying material (the secret input)
692    ///
693    /// # Returns
694    ///
695    /// A 32-byte pseudorandom key
696    ///
697    /// # Example
698    ///
699    /// ```
700    /// let prk = hmac_sha256::HKDF::extract(b"salt value", b"input key material");
701    /// ```
702    pub fn extract(salt: impl AsRef<[u8]>, ikm: impl AsRef<[u8]>) -> [u8; 32] {
703        HMAC::mac(ikm, salt)
704    }
705
706    /// Performs the HKDF-Expand function (second stage of HKDF).
707    ///
708    /// Expands the pseudorandom key into output keying material of the desired length.
709    ///
710    /// # Arguments
711    ///
712    /// * `out` - Buffer to receive the output keying material
713    /// * `prk` - Pseudorandom key (from the extract step)
714    /// * `info` - Optional context and application specific information
715    ///
716    /// # Panics
717    ///
718    /// Panics if the requested output length is greater than 255 * 32 bytes (8160 bytes).
719    ///
720    /// # Example
721    ///
722    /// ```
723    /// let prk = hmac_sha256::HKDF::extract(b"salt", b"input key material");
724    /// let mut okm = [0u8; 64]; // 64 bytes of output keying material
725    /// hmac_sha256::HKDF::expand(&mut okm, prk, b"context info");
726    /// ```
727    pub fn expand(out: &mut [u8], prk: impl AsRef<[u8]>, info: impl AsRef<[u8]>) {
728        let info = info.as_ref();
729        let mut counter: u8 = 1;
730        assert!(out.len() < 0xff * 32);
731        let mut i: usize = 0;
732        while i < out.len() {
733            let mut hmac = HMAC::new(&prk);
734            if i != 0 {
735                hmac.update(&out[i - 32..][..32]);
736            }
737            hmac.update(info);
738            hmac.update([counter]);
739            let left = core::cmp::min(32, out.len() - i);
740            out[i..][..left].copy_from_slice(&hmac.finalize()[..left]);
741            counter += 1;
742            i += 32;
743        }
744    }
745}
746
747/// Wrapped `Hash` type for the `Digest` trait.
748#[cfg(feature = "traits010")]
749pub type WrappedHash = digest010::core_api::CoreWrapper<Hash>;
750
751#[cfg(feature = "traits010")]
752mod digest_trait010 {
753    use core::fmt;
754
755    use digest010::{
756        block_buffer::Eager,
757        const_oid::{AssociatedOid, ObjectIdentifier},
758        consts::{U32, U64},
759        core_api::{
760            AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
761            OutputSizeUser, Reset, UpdateCore,
762        },
763        FixedOutput, FixedOutputReset, HashMarker, Output, Update,
764    };
765
766    use super::Hash;
767
768    impl AssociatedOid for Hash {
769        const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
770    }
771
772    impl AlgorithmName for Hash {
773        fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
774            f.write_str("Sha256")
775        }
776    }
777
778    impl HashMarker for Hash {}
779
780    impl BufferKindUser for Hash {
781        type BufferKind = Eager;
782    }
783
784    impl BlockSizeUser for Hash {
785        type BlockSize = U64;
786    }
787
788    impl OutputSizeUser for Hash {
789        type OutputSize = U32;
790    }
791
792    impl UpdateCore for Hash {
793        #[inline]
794        fn update_blocks(&mut self, blocks: &[Block<Self>]) {
795            for block in blocks {
796                self._update(block);
797            }
798        }
799    }
800
801    impl Update for Hash {
802        #[inline]
803        fn update(&mut self, data: &[u8]) {
804            self._update(data);
805        }
806    }
807
808    impl FixedOutputCore for Hash {
809        fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
810            self._update(buffer.get_data());
811            self.finalize_into(out);
812        }
813    }
814
815    impl FixedOutput for Hash {
816        fn finalize_into(self, out: &mut Output<Self>) {
817            let h = self.finalize();
818            out.copy_from_slice(&h);
819        }
820    }
821
822    impl Reset for Hash {
823        fn reset(&mut self) {
824            *self = Self::new()
825        }
826    }
827
828    impl FixedOutputReset for Hash {
829        fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
830            self.finalize_into(out);
831            self.reset();
832        }
833    }
834}
835
836#[cfg(feature = "traits09")]
837mod digest_trait09 {
838    use digest09::consts::{U32, U64};
839    use digest09::{BlockInput, FixedOutputDirty, Output, Reset, Update};
840
841    use super::Hash;
842
843    impl BlockInput for Hash {
844        type BlockSize = U64;
845    }
846
847    impl Update for Hash {
848        fn update(&mut self, input: impl AsRef<[u8]>) {
849            self._update(input)
850        }
851    }
852
853    impl FixedOutputDirty for Hash {
854        type OutputSize = U32;
855
856        fn finalize_into_dirty(&mut self, out: &mut Output<Self>) {
857            let h = self.finalize();
858            out.copy_from_slice(&h);
859        }
860    }
861
862    impl Reset for Hash {
863        fn reset(&mut self) {
864            *self = Self::new()
865        }
866    }
867}
868
869#[test]
870fn main() {
871    let h = HMAC::mac([], [0u8; 32]);
872    assert_eq!(
873        &h[..],
874        &[
875            182, 19, 103, 154, 8, 20, 217, 236, 119, 47, 149, 215, 120, 195, 95, 197, 255, 22, 151,
876            196, 147, 113, 86, 83, 198, 199, 18, 20, 66, 146, 197, 173
877        ]
878    );
879
880    let h = HMAC::mac([42u8; 69], []);
881    assert_eq!(
882        &h[..],
883        &[
884            225, 88, 35, 8, 78, 185, 165, 6, 235, 124, 28, 250, 112, 124, 159, 119, 159, 88, 184,
885            61, 7, 37, 166, 229, 71, 154, 83, 153, 151, 181, 182, 72
886        ]
887    );
888
889    let h = HMAC::mac([69u8; 250], [42u8; 50]);
890    assert_eq!(
891        &h[..],
892        &[
893            112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
894            41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
895        ]
896    );
897
898    let mut s = HMAC::new([42u8; 50]);
899    s.update([69u8; 150]);
900    s.update([69u8; 100]);
901    let h = s.finalize();
902    assert_eq!(
903        &h[..],
904        &[
905            112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
906            41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
907        ]
908    );
909
910    // Test HMAC verify function
911    let expected_mac = HMAC::mac([69u8; 250], [42u8; 50]);
912    let mut hmac = HMAC::new([42u8; 50]);
913    hmac.update([69u8; 250]);
914    assert!(hmac.finalize_verify(&expected_mac));
915
916    let mut hmac = HMAC::new([42u8; 50]);
917    hmac.update([69u8; 251]); // Different data
918    assert!(!hmac.finalize_verify(&expected_mac));
919
920    // Test HMAC one-shot verify function
921    assert!(HMAC::verify([69u8; 250], [42u8; 50], &expected_mac));
922    assert!(!HMAC::verify([69u8; 251], [42u8; 50], &expected_mac)); // Different data
923    assert!(!HMAC::verify([69u8; 250], [43u8; 50], &expected_mac)); // Different key
924
925    // Test Hash verify function
926    let expected_hash = Hash::hash(&[42u8; 123]);
927    assert!(Hash::verify(&[42u8; 123], &expected_hash));
928    assert!(!Hash::verify(&[42u8; 124], &expected_hash));
929
930    // Test Hash finalize_verify function
931    let mut hasher = Hash::new();
932    hasher.update(&[42u8; 123]);
933    assert!(hasher.finalize_verify(&expected_hash));
934
935    let mut hasher = Hash::new();
936    hasher.update(&[42u8; 124]); // Different data
937    assert!(!hasher.finalize_verify(&expected_hash));
938
939    let ikm = [0x0bu8; 22];
940    let salt = [
941        0x00u8, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
942    ];
943    let context = [0xf0u8, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
944    let prk = HKDF::extract(salt, ikm);
945    let mut k = [0u8; 40];
946    HKDF::expand(&mut k, prk, context);
947    assert_eq!(
948        &k[..],
949        &[
950            60, 178, 95, 37, 250, 172, 213, 122, 144, 67, 79, 100, 208, 54, 47, 42, 45, 45, 10,
951            144, 207, 26, 90, 76, 93, 176, 45, 86, 236, 196, 197, 191, 52, 0, 114, 8, 213, 184,
952            135, 24
953        ]
954    );
955}