hmac_sha256/
lib.rs

1//! A small, self-contained SHA256 and HMAC-SHA256 implementation
2//! (C) Frank Denis <fdenis [at] fastly [dot] com>, public domain
3
4#![no_std]
5#![allow(
6    non_snake_case,
7    clippy::cast_lossless,
8    clippy::eq_op,
9    clippy::identity_op,
10    clippy::many_single_char_names,
11    clippy::unreadable_literal
12)]
13
14#[inline(always)]
15fn load_be(base: &[u8], offset: usize) -> u32 {
16    let addr = &base[offset..];
17    (addr[3] as u32) | (addr[2] as u32) << 8 | (addr[1] as u32) << 16 | (addr[0] as u32) << 24
18}
19
20#[inline(always)]
21fn store_be(base: &mut [u8], offset: usize, x: u32) {
22    let addr = &mut base[offset..];
23    addr[3] = x as u8;
24    addr[2] = (x >> 8) as u8;
25    addr[1] = (x >> 16) as u8;
26    addr[0] = (x >> 24) as u8;
27}
28
29struct W([u32; 16]);
30
31#[derive(Copy, Clone)]
32struct State([u32; 8]);
33
34impl W {
35    fn new(input: &[u8]) -> Self {
36        let mut w = [0u32; 16];
37        for (i, e) in w.iter_mut().enumerate() {
38            *e = load_be(input, i * 4)
39        }
40        W(w)
41    }
42
43    #[inline(always)]
44    fn Ch(x: u32, y: u32, z: u32) -> u32 {
45        (x & y) ^ (!x & z)
46    }
47
48    #[inline(always)]
49    fn Maj(x: u32, y: u32, z: u32) -> u32 {
50        (x & y) ^ (x & z) ^ (y & z)
51    }
52
53    #[inline(always)]
54    fn Sigma0(x: u32) -> u32 {
55        x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22)
56    }
57
58    #[inline(always)]
59    fn Sigma1(x: u32) -> u32 {
60        x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25)
61    }
62
63    #[inline(always)]
64    fn sigma0(x: u32) -> u32 {
65        x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
66    }
67
68    #[inline(always)]
69    fn sigma1(x: u32) -> u32 {
70        x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
71    }
72
73    #[cfg_attr(feature = "opt_size", inline(never))]
74    #[cfg_attr(not(feature = "opt_size"), inline(always))]
75    fn M(&mut self, a: usize, b: usize, c: usize, d: usize) {
76        let w = &mut self.0;
77        w[a] = w[a]
78            .wrapping_add(Self::sigma1(w[b]))
79            .wrapping_add(w[c])
80            .wrapping_add(Self::sigma0(w[d]));
81    }
82
83    #[inline]
84    fn expand(&mut self) {
85        self.M(0, (0 + 14) & 15, (0 + 9) & 15, (0 + 1) & 15);
86        self.M(1, (1 + 14) & 15, (1 + 9) & 15, (1 + 1) & 15);
87        self.M(2, (2 + 14) & 15, (2 + 9) & 15, (2 + 1) & 15);
88        self.M(3, (3 + 14) & 15, (3 + 9) & 15, (3 + 1) & 15);
89        self.M(4, (4 + 14) & 15, (4 + 9) & 15, (4 + 1) & 15);
90        self.M(5, (5 + 14) & 15, (5 + 9) & 15, (5 + 1) & 15);
91        self.M(6, (6 + 14) & 15, (6 + 9) & 15, (6 + 1) & 15);
92        self.M(7, (7 + 14) & 15, (7 + 9) & 15, (7 + 1) & 15);
93        self.M(8, (8 + 14) & 15, (8 + 9) & 15, (8 + 1) & 15);
94        self.M(9, (9 + 14) & 15, (9 + 9) & 15, (9 + 1) & 15);
95        self.M(10, (10 + 14) & 15, (10 + 9) & 15, (10 + 1) & 15);
96        self.M(11, (11 + 14) & 15, (11 + 9) & 15, (11 + 1) & 15);
97        self.M(12, (12 + 14) & 15, (12 + 9) & 15, (12 + 1) & 15);
98        self.M(13, (13 + 14) & 15, (13 + 9) & 15, (13 + 1) & 15);
99        self.M(14, (14 + 14) & 15, (14 + 9) & 15, (14 + 1) & 15);
100        self.M(15, (15 + 14) & 15, (15 + 9) & 15, (15 + 1) & 15);
101    }
102
103    #[cfg_attr(feature = "opt_size", inline(never))]
104    #[cfg_attr(not(feature = "opt_size"), inline(always))]
105    fn F(&mut self, state: &mut State, i: usize, k: u32) {
106        let t = &mut state.0;
107        t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
108            .wrapping_add(Self::Sigma1(t[(16 - i + 4) & 7]))
109            .wrapping_add(Self::Ch(
110                t[(16 - i + 4) & 7],
111                t[(16 - i + 5) & 7],
112                t[(16 - i + 6) & 7],
113            ))
114            .wrapping_add(k)
115            .wrapping_add(self.0[i]);
116        t[(16 - i + 3) & 7] = t[(16 - i + 3) & 7].wrapping_add(t[(16 - i + 7) & 7]);
117        t[(16 - i + 7) & 7] = t[(16 - i + 7) & 7]
118            .wrapping_add(Self::Sigma0(t[(16 - i + 0) & 7]))
119            .wrapping_add(Self::Maj(
120                t[(16 - i + 0) & 7],
121                t[(16 - i + 1) & 7],
122                t[(16 - i + 2) & 7],
123            ));
124    }
125
126    fn G(&mut self, state: &mut State, s: usize) {
127        const ROUND_CONSTANTS: [u32; 64] = [
128            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
129            0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
130            0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
131            0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
132            0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
133            0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
134            0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
135            0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
136            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
137            0xc67178f2,
138        ];
139        let rc = &ROUND_CONSTANTS[s * 16..];
140        self.F(state, 0, rc[0]);
141        self.F(state, 1, rc[1]);
142        self.F(state, 2, rc[2]);
143        self.F(state, 3, rc[3]);
144        self.F(state, 4, rc[4]);
145        self.F(state, 5, rc[5]);
146        self.F(state, 6, rc[6]);
147        self.F(state, 7, rc[7]);
148        self.F(state, 8, rc[8]);
149        self.F(state, 9, rc[9]);
150        self.F(state, 10, rc[10]);
151        self.F(state, 11, rc[11]);
152        self.F(state, 12, rc[12]);
153        self.F(state, 13, rc[13]);
154        self.F(state, 14, rc[14]);
155        self.F(state, 15, rc[15]);
156    }
157}
158
159impl State {
160    fn new() -> Self {
161        const IV: [u8; 32] = [
162            0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f,
163            0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab,
164            0x5b, 0xe0, 0xcd, 0x19,
165        ];
166        let mut t = [0u32; 8];
167        for (i, e) in t.iter_mut().enumerate() {
168            *e = load_be(&IV, i * 4)
169        }
170        State(t)
171    }
172
173    #[inline(always)]
174    fn add(&mut self, x: &State) {
175        let sx = &mut self.0;
176        let ex = &x.0;
177        sx[0] = sx[0].wrapping_add(ex[0]);
178        sx[1] = sx[1].wrapping_add(ex[1]);
179        sx[2] = sx[2].wrapping_add(ex[2]);
180        sx[3] = sx[3].wrapping_add(ex[3]);
181        sx[4] = sx[4].wrapping_add(ex[4]);
182        sx[5] = sx[5].wrapping_add(ex[5]);
183        sx[6] = sx[6].wrapping_add(ex[6]);
184        sx[7] = sx[7].wrapping_add(ex[7]);
185    }
186
187    fn store(&self, out: &mut [u8]) {
188        for (i, &e) in self.0.iter().enumerate() {
189            store_be(out, i * 4, e);
190        }
191    }
192
193    fn blocks(&mut self, mut input: &[u8]) -> usize {
194        let mut t = *self;
195        let mut inlen = input.len();
196        while inlen >= 64 {
197            let mut w = W::new(input);
198            w.G(&mut t, 0);
199            w.expand();
200            w.G(&mut t, 1);
201            w.expand();
202            w.G(&mut t, 2);
203            w.expand();
204            w.G(&mut t, 3);
205            t.add(self);
206            self.0 = t.0;
207            input = &input[64..];
208            inlen -= 64;
209        }
210        inlen
211    }
212}
213
214#[derive(Copy, Clone)]
215pub struct Hash {
216    state: State,
217    w: [u8; 64],
218    r: usize,
219    len: usize,
220}
221
222impl Hash {
223    pub fn new() -> Hash {
224        Hash {
225            state: State::new(),
226            r: 0,
227            w: [0u8; 64],
228            len: 0,
229        }
230    }
231
232    fn _update(&mut self, input: impl AsRef<[u8]>) {
233        let input = input.as_ref();
234        let mut n = input.len();
235        self.len += n;
236        let av = 64 - self.r;
237        let tc = ::core::cmp::min(n, av);
238        self.w[self.r..self.r + tc].copy_from_slice(&input[0..tc]);
239        self.r += tc;
240        n -= tc;
241        let pos = tc;
242        if self.r == 64 {
243            self.state.blocks(&self.w);
244            self.r = 0;
245        }
246        if self.r == 0 && n > 0 {
247            let rb = self.state.blocks(&input[pos..]);
248            if rb > 0 {
249                self.w[..rb].copy_from_slice(&input[pos + n - rb..]);
250                self.r = rb;
251            }
252        }
253    }
254
255    /// Absorb content
256    pub fn update(&mut self, input: impl AsRef<[u8]>) {
257        self._update(input)
258    }
259
260    /// Compute SHA256(absorbed content)
261    pub fn finalize(mut self) -> [u8; 32] {
262        let mut padded = [0u8; 128];
263        padded[..self.r].copy_from_slice(&self.w[..self.r]);
264        padded[self.r] = 0x80;
265        let r = if self.r < 56 { 64 } else { 128 };
266        let bits = self.len * 8;
267        for i in 0..8 {
268            padded[r - 8 + i] = (bits as u64 >> (56 - i * 8)) as u8;
269        }
270        self.state.blocks(&padded[..r]);
271        let mut out = [0u8; 32];
272        self.state.store(&mut out);
273        out
274    }
275
276    /// Compute SHA256(`input`)
277    pub fn hash(input: &[u8]) -> [u8; 32] {
278        let mut h = Hash::new();
279        h.update(input);
280        h.finalize()
281    }
282}
283
284impl Default for Hash {
285    fn default() -> Self {
286        Self::new()
287    }
288}
289
290#[derive(Clone)]
291pub struct HMAC {
292    ih: Hash,
293    padded: [u8; 64],
294}
295
296impl HMAC {
297    /// Compute HMAC-SHA256(`input`, `k`)
298    pub fn mac(input: impl AsRef<[u8]>, k: impl AsRef<[u8]>) -> [u8; 32] {
299        let input = input.as_ref();
300        let k = k.as_ref();
301        let mut hk = [0u8; 32];
302        let k2 = if k.len() > 64 {
303            hk.copy_from_slice(&Hash::hash(k));
304            &hk
305        } else {
306            k
307        };
308        let mut padded = [0x36; 64];
309        for (p, &k) in padded.iter_mut().zip(k2.iter()) {
310            *p ^= k;
311        }
312        let mut ih = Hash::new();
313        ih.update(&padded[..]);
314        ih.update(input);
315
316        for p in padded.iter_mut() {
317            *p ^= 0x6a;
318        }
319        let mut oh = Hash::new();
320        oh.update(&padded[..]);
321        oh.update(ih.finalize());
322        oh.finalize()
323    }
324
325    pub fn new(k: impl AsRef<[u8]>) -> HMAC {
326        let k = k.as_ref();
327        let mut hk = [0u8; 32];
328        let k2 = if k.len() > 64 {
329            hk.copy_from_slice(&Hash::hash(k));
330            &hk
331        } else {
332            k
333        };
334        let mut padded = [0x36; 64];
335        for (p, &k) in padded.iter_mut().zip(k2.iter()) {
336            *p ^= k;
337        }
338        let mut ih = Hash::new();
339        ih.update(&padded[..]);
340        HMAC { ih, padded }
341    }
342
343    /// Absorb content
344    pub fn update(&mut self, input: impl AsRef<[u8]>) {
345        self.ih.update(input);
346    }
347
348    /// Compute HMAC-SHA256 over the entire input
349    pub fn finalize(mut self) -> [u8; 32] {
350        for p in self.padded.iter_mut() {
351            *p ^= 0x6a;
352        }
353        let mut oh = Hash::new();
354        oh.update(&self.padded[..]);
355        oh.update(self.ih.finalize());
356        oh.finalize()
357    }
358}
359
360pub struct HKDF;
361
362impl HKDF {
363    pub fn extract(salt: impl AsRef<[u8]>, ikm: impl AsRef<[u8]>) -> [u8; 32] {
364        HMAC::mac(ikm, salt)
365    }
366
367    pub fn expand(out: &mut [u8], prk: impl AsRef<[u8]>, info: impl AsRef<[u8]>) {
368        let info = info.as_ref();
369        let mut counter: u8 = 1;
370        assert!(out.len() < 0xff * 32);
371        let mut i: usize = 0;
372        while i < out.len() {
373            let mut hmac = HMAC::new(&prk);
374            if i != 0 {
375                hmac.update(&out[i - 32..][..32]);
376            }
377            hmac.update(info);
378            hmac.update([counter]);
379            let left = core::cmp::min(32, out.len() - i);
380            out[i..][..left].copy_from_slice(&hmac.finalize()[..left]);
381            counter += 1;
382            i += 32;
383        }
384    }
385}
386
387/// Wrapped `Hash` type for the `Digest` trait.
388#[cfg(feature = "traits010")]
389pub type WrappedHash = digest010::core_api::CoreWrapper<Hash>;
390
391#[cfg(feature = "traits010")]
392mod digest_trait010 {
393    use core::fmt;
394
395    use digest010::{
396        block_buffer::Eager,
397        const_oid::{AssociatedOid, ObjectIdentifier},
398        consts::{U32, U64},
399        core_api::{
400            AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
401            OutputSizeUser, Reset, UpdateCore,
402        },
403        FixedOutput, FixedOutputReset, HashMarker, Output, Update,
404    };
405
406    use super::Hash;
407
408    impl AssociatedOid for Hash {
409        const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
410    }
411
412    impl AlgorithmName for Hash {
413        fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
414            f.write_str("Sha256")
415        }
416    }
417
418    impl HashMarker for Hash {}
419
420    impl BufferKindUser for Hash {
421        type BufferKind = Eager;
422    }
423
424    impl BlockSizeUser for Hash {
425        type BlockSize = U64;
426    }
427
428    impl OutputSizeUser for Hash {
429        type OutputSize = U32;
430    }
431
432    impl UpdateCore for Hash {
433        #[inline]
434        fn update_blocks(&mut self, blocks: &[Block<Self>]) {
435            for block in blocks {
436                self._update(block);
437            }
438        }
439    }
440
441    impl Update for Hash {
442        #[inline]
443        fn update(&mut self, data: &[u8]) {
444            self._update(data);
445        }
446    }
447
448    impl FixedOutputCore for Hash {
449        fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
450            self._update(buffer.get_data());
451            self.finalize_into(out);
452        }
453    }
454
455    impl FixedOutput for Hash {
456        fn finalize_into(self, out: &mut Output<Self>) {
457            let h = self.finalize();
458            out.copy_from_slice(&h);
459        }
460    }
461
462    impl Reset for Hash {
463        fn reset(&mut self) {
464            *self = Self::new()
465        }
466    }
467
468    impl FixedOutputReset for Hash {
469        fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
470            self.finalize_into(out);
471            self.reset();
472        }
473    }
474}
475
476#[cfg(feature = "traits09")]
477mod digest_trait09 {
478    use digest09::consts::{U32, U64};
479    use digest09::{BlockInput, FixedOutputDirty, Output, Reset, Update};
480
481    use super::Hash;
482
483    impl BlockInput for Hash {
484        type BlockSize = U64;
485    }
486
487    impl Update for Hash {
488        fn update(&mut self, input: impl AsRef<[u8]>) {
489            self._update(input)
490        }
491    }
492
493    impl FixedOutputDirty for Hash {
494        type OutputSize = U32;
495
496        fn finalize_into_dirty(&mut self, out: &mut Output<Self>) {
497            let h = self.finalize();
498            out.copy_from_slice(&h);
499        }
500    }
501
502    impl Reset for Hash {
503        fn reset(&mut self) {
504            *self = Self::new()
505        }
506    }
507}
508
509#[test]
510fn main() {
511    let h = HMAC::mac([], [0u8; 32]);
512    assert_eq!(
513        &h[..],
514        &[
515            182, 19, 103, 154, 8, 20, 217, 236, 119, 47, 149, 215, 120, 195, 95, 197, 255, 22, 151,
516            196, 147, 113, 86, 83, 198, 199, 18, 20, 66, 146, 197, 173
517        ]
518    );
519
520    let h = HMAC::mac([42u8; 69], []);
521    assert_eq!(
522        &h[..],
523        &[
524            225, 88, 35, 8, 78, 185, 165, 6, 235, 124, 28, 250, 112, 124, 159, 119, 159, 88, 184,
525            61, 7, 37, 166, 229, 71, 154, 83, 153, 151, 181, 182, 72
526        ]
527    );
528
529    let h = HMAC::mac([69u8; 250], [42u8; 50]);
530    assert_eq!(
531        &h[..],
532        &[
533            112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
534            41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
535        ]
536    );
537
538    let mut s = HMAC::new([42u8; 50]);
539    s.update([69u8; 150]);
540    s.update([69u8; 100]);
541    let h = s.finalize();
542    assert_eq!(
543        &h[..],
544        &[
545            112, 156, 120, 216, 86, 25, 79, 210, 155, 193, 32, 120, 116, 134, 237, 14, 198, 1, 64,
546            41, 124, 196, 103, 91, 109, 216, 36, 133, 4, 234, 218, 228
547        ]
548    );
549
550    let ikm = [0x0bu8; 22];
551    let salt = [
552        0x00u8, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
553    ];
554    let context = [0xf0u8, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
555    let prk = HKDF::extract(salt, ikm);
556    let mut k = [0u8; 40];
557    HKDF::expand(&mut k, prk, context);
558    assert_eq!(
559        &k[..],
560        &[
561            60, 178, 95, 37, 250, 172, 213, 122, 144, 67, 79, 100, 208, 54, 47, 42, 45, 45, 10,
562            144, 207, 26, 90, 76, 93, 176, 45, 86, 236, 196, 197, 191, 52, 0, 114, 8, 213, 184,
563            135, 24
564        ]
565    );
566}