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