Skip to main content

simoom_tls/crypto/
sha2.rs

1//! SHA-256, SHA-384 and SHA-512 (FIPS 180-4), HMAC (RFC 2104) and HKDF (RFC 5869).
2//!
3//! SHA-256 uses the CPU's SHA instructions (SHA-NI, ARMv8 SHA-2) when present. Outputs are
4//! fixed-size [`Output`] values, so hashing never allocates.
5
6use simoom_sys::arch;
7
8/// A digest of up to 64 bytes.
9#[derive(Clone, Copy)]
10pub struct Output {
11    buf: [u8; 64],
12    len: u8,
13}
14
15impl Output {
16    fn new(bytes: &[u8]) -> Output {
17        let mut buf = [0u8; 64];
18        buf[..bytes.len()].copy_from_slice(bytes);
19        Output { buf, len: bytes.len() as u8 }
20    }
21}
22
23impl core::ops::Deref for Output {
24    type Target = [u8];
25    fn deref(&self) -> &[u8] {
26        &self.buf[..self.len as usize]
27    }
28}
29
30impl AsRef<[u8]> for Output {
31    fn as_ref(&self) -> &[u8] {
32        self
33    }
34}
35
36impl PartialEq for Output {
37    fn eq(&self, o: &Output) -> bool {
38        crate::util::ct_eq(self, o)
39    }
40}
41
42impl core::fmt::Debug for Output {
43    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44        f.write_str(&crate::util::hex(self))
45    }
46}
47
48const K256: [u32; 64] = [
49    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
50    0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
51    0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
52    0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
53    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
54    0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
55    0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
56    0xc67178f2,
57];
58
59fn compress256_soft(state: &mut [u32; 8], blocks: &[u8]) {
60    for block in blocks.chunks_exact(64) {
61        let mut w = [0u32; 64];
62        for i in 0..16 {
63            w[i] = u32::from_be_bytes(block[4 * i..4 * i + 4].try_into().unwrap());
64        }
65        for i in 16..64 {
66            let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
67            let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
68            w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1);
69        }
70        let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
71        for i in 0..64 {
72            let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
73            let ch = (e & f) ^ (!e & g);
74            let t1 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(K256[i]).wrapping_add(w[i]);
75            let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
76            let maj = (a & b) ^ (a & c) ^ (b & c);
77            let t2 = s0.wrapping_add(maj);
78            h = g;
79            g = f;
80            f = e;
81            e = d.wrapping_add(t1);
82            d = c;
83            c = b;
84            b = a;
85            a = t1.wrapping_add(t2);
86        }
87        for (s, v) in state.iter_mut().zip([a, b, c, d, e, f, g, h]) {
88            *s = s.wrapping_add(v);
89        }
90    }
91}
92
93fn compress256(state: &mut [u32; 8], blocks: &[u8]) {
94    if !arch::sha256_blocks(state, blocks) {
95        compress256_soft(state, blocks);
96    }
97}
98
99const K512: [u64; 80] = [
100    0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
101    0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
102    0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
103    0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
104    0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
105    0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
106    0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
107    0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
108    0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
109    0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
110    0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
111    0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
112    0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
113    0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
114    0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
115    0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
116];
117
118fn compress512(state: &mut [u64; 8], blocks: &[u8]) {
119    for block in blocks.chunks_exact(128) {
120        let mut w = [0u64; 80];
121        for i in 0..16 {
122            w[i] = u64::from_be_bytes(block[8 * i..8 * i + 8].try_into().unwrap());
123        }
124        for i in 16..80 {
125            let s0 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
126            let s1 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
127            w[i] = w[i - 16].wrapping_add(s0).wrapping_add(w[i - 7]).wrapping_add(s1);
128        }
129        let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state;
130        for i in 0..80 {
131            let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
132            let ch = (e & f) ^ (!e & g);
133            let t1 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(K512[i]).wrapping_add(w[i]);
134            let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
135            let maj = (a & b) ^ (a & c) ^ (b & c);
136            let t2 = s0.wrapping_add(maj);
137            h = g;
138            g = f;
139            f = e;
140            e = d.wrapping_add(t1);
141            d = c;
142            c = b;
143            b = a;
144            a = t1.wrapping_add(t2);
145        }
146        for (s, v) in state.iter_mut().zip([a, b, c, d, e, f, g, h]) {
147            *s = s.wrapping_add(v);
148        }
149    }
150}
151
152/// Block buffering shared by the hash functions.
153#[derive(Clone)]
154struct Buf<const B: usize> {
155    buf: [u8; B],
156    len: usize,
157    total: u128,
158}
159
160impl<const B: usize> Buf<B> {
161    const fn new() -> Self {
162        Buf { buf: [0; B], len: 0, total: 0 }
163    }
164
165    fn update(&mut self, mut data: &[u8], mut compress: impl FnMut(&[u8])) {
166        self.total += data.len() as u128;
167        if self.len > 0 {
168            let n = (B - self.len).min(data.len());
169            self.buf[self.len..self.len + n].copy_from_slice(&data[..n]);
170            self.len += n;
171            data = &data[n..];
172            if self.len < B {
173                return;
174            }
175            compress(&self.buf);
176            self.len = 0;
177        }
178        let whole = data.len() - data.len() % B;
179        if whole > 0 {
180            compress(&data[..whole]);
181        }
182        let rest = &data[whole..];
183        self.buf[..rest.len()].copy_from_slice(rest);
184        self.len = rest.len();
185    }
186
187    /// Appends the padding and the bit length (`lenbytes` wide) and compresses.
188    fn pad(&mut self, lenbytes: usize, mut compress: impl FnMut(&[u8])) {
189        let bits = self.total * 8;
190        self.buf[self.len] = 0x80;
191        self.buf[self.len + 1..].fill(0);
192        if self.len + 1 > B - lenbytes {
193            compress(&self.buf);
194            self.buf.fill(0);
195        }
196        let lb = bits.to_be_bytes();
197        self.buf[B - lenbytes..].copy_from_slice(&lb[16 - lenbytes..]);
198        compress(&self.buf);
199    }
200}
201
202/// SHA-256.
203#[derive(Clone)]
204pub struct Sha256 {
205    state: [u32; 8],
206    buf: Buf<64>,
207}
208
209impl Default for Sha256 {
210    fn default() -> Self {
211        Self::new()
212    }
213}
214
215impl Sha256 {
216    pub const fn new() -> Sha256 {
217        Sha256 {
218            state: [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19],
219            buf: Buf::new(),
220        }
221    }
222    pub fn update(&mut self, data: &[u8]) {
223        let st = &mut self.state;
224        self.buf.update(data, |b| compress256(st, b));
225    }
226    pub fn finish(mut self) -> [u8; 32] {
227        let st = &mut self.state;
228        self.buf.pad(8, |b| compress256(st, b));
229        let mut out = [0u8; 32];
230        for (o, w) in out.chunks_exact_mut(4).zip(self.state) {
231            o.copy_from_slice(&w.to_be_bytes());
232        }
233        out
234    }
235    pub fn digest(data: &[u8]) -> [u8; 32] {
236        let mut h = Sha256::new();
237        h.update(data);
238        h.finish()
239    }
240}
241
242/// SHA-512 core, also used (with another IV and a truncated output) for SHA-384 and
243/// SHA-512/256 (HTTP Digest `SHA-512-256`, RFC 7616).
244#[derive(Clone)]
245pub struct Sha512 {
246    state: [u64; 8],
247    buf: Buf<128>,
248    out_words: usize,
249}
250
251const IV512: [u64; 8] = [
252    0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1,
253    0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
254];
255const IV384: [u64; 8] = [
256    0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31,
257    0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
258];
259/// FIPS 180-4 section 5.3.6.2.
260const IV512_256: [u64; 8] = [
261    0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd, 0x96283ee2a88effe3,
262    0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
263];
264
265impl Sha512 {
266    pub const fn new() -> Sha512 {
267        Sha512 { state: IV512, buf: Buf::new(), out_words: 8 }
268    }
269    pub const fn new384() -> Sha512 {
270        Sha512 { state: IV384, buf: Buf::new(), out_words: 6 }
271    }
272    /// SHA-512/256 (FIPS 180-4): SHA-512 with its own IV, truncated to 32 bytes.
273    pub const fn new512_256() -> Sha512 {
274        Sha512 { state: IV512_256, buf: Buf::new(), out_words: 4 }
275    }
276    pub fn update(&mut self, data: &[u8]) {
277        let st = &mut self.state;
278        self.buf.update(data, |b| compress512(st, b));
279    }
280    pub fn finish(mut self) -> Output {
281        let st = &mut self.state;
282        self.buf.pad(16, |b| compress512(st, b));
283        let mut out = [0u8; 64];
284        for (o, w) in out.chunks_exact_mut(8).zip(self.state) {
285            o.copy_from_slice(&w.to_be_bytes());
286        }
287        Output::new(&out[..8 * self.out_words])
288    }
289    pub fn digest(data: &[u8]) -> [u8; 64] {
290        let mut h = Sha512::new();
291        h.update(data);
292        let mut o = [0u8; 64];
293        o.copy_from_slice(&h.finish());
294        o
295    }
296}
297
298impl Default for Sha512 {
299    fn default() -> Self {
300        Self::new()
301    }
302}
303
304/// A hash function chosen at run time (cipher suites, signature schemes, certificates).
305#[derive(Clone, Copy, Debug, PartialEq, Eq)]
306pub enum HashAlg {
307    Sha256,
308    Sha384,
309    Sha512,
310}
311
312/// A running hash of a [`HashAlg`].
313#[derive(Clone)]
314pub enum Hasher {
315    Sha256(Sha256),
316    Sha512(Sha512),
317}
318
319impl Hasher {
320    #[inline(never)]
321    pub fn new(alg: HashAlg) -> Hasher {
322        match alg {
323            HashAlg::Sha256 => Hasher::Sha256(Sha256::new()),
324            HashAlg::Sha384 => Hasher::Sha512(Sha512::new384()),
325            HashAlg::Sha512 => Hasher::Sha512(Sha512::new()),
326        }
327    }
328    #[inline(never)]
329    pub fn update(&mut self, data: &[u8]) {
330        match self {
331            Hasher::Sha256(h) => h.update(data),
332            Hasher::Sha512(h) => h.update(data),
333        }
334    }
335    #[inline(never)]
336    pub fn finish(self) -> Output {
337        match self {
338            Hasher::Sha256(h) => Output::new(&h.finish()),
339            Hasher::Sha512(h) => h.finish(),
340        }
341    }
342    /// The digest of everything so far, leaving the hasher usable.
343    pub fn current(&self) -> Output {
344        self.clone().finish()
345    }
346}
347
348impl HashAlg {
349    pub const fn output_len(self) -> usize {
350        match self {
351            HashAlg::Sha256 => 32,
352            HashAlg::Sha384 => 48,
353            HashAlg::Sha512 => 64,
354        }
355    }
356    const fn block_len(self) -> usize {
357        match self {
358            HashAlg::Sha256 => 64,
359            _ => 128,
360        }
361    }
362    pub fn hash(self, data: &[u8]) -> Output {
363        let mut h = Hasher::new(self);
364        h.update(data);
365        h.finish()
366    }
367    /// HMAC over the concatenation of `parts`.
368    pub fn hmac(self, key: &[u8], parts: &[&[u8]]) -> Output {
369        let bl = self.block_len();
370        let mut k = [0u8; 128];
371        if key.len() > bl {
372            let d = self.hash(key);
373            k[..d.len()].copy_from_slice(&d);
374        } else {
375            k[..key.len()].copy_from_slice(key);
376        }
377        let mut pad = [0u8; 128];
378        for (p, x) in pad.iter_mut().zip(k.iter()) {
379            *p = x ^ 0x36;
380        }
381        let mut inner = Hasher::new(self);
382        inner.update(&pad[..bl]);
383        for p in parts {
384            inner.update(p);
385        }
386        let ih = inner.finish();
387        for (p, x) in pad.iter_mut().zip(k.iter()) {
388            *p = x ^ 0x5c;
389        }
390        let mut outer = Hasher::new(self);
391        outer.update(&pad[..bl]);
392        outer.update(&ih);
393        crate::util::zeroize(&mut k);
394        crate::util::zeroize(&mut pad);
395        outer.finish()
396    }
397    /// HKDF-Extract; an empty salt means HashLen zero bytes.
398    pub fn hkdf_extract(self, salt: &[u8], ikm: &[u8]) -> Output {
399        let zeros = [0u8; 64];
400        let salt = if salt.is_empty() { &zeros[..self.output_len()] } else { salt };
401        self.hmac(salt, &[ikm])
402    }
403    /// HKDF-Expand into `out` (at most 255 * HashLen bytes).
404    pub fn hkdf_expand(self, prk: &[u8], info: &[&[u8]], out: &mut [u8]) {
405        assert!(out.len() <= 255 * self.output_len(), "HKDF output too long");
406        let mut t = Output::new(&[]);
407        for (i, chunk) in out.chunks_mut(self.output_len()).enumerate() {
408            let ctr = [i as u8 + 1];
409            let next = {
410                let mut parts: Vec<&[u8]> = Vec::with_capacity(info.len() + 2);
411                parts.push(&t);
412                parts.extend_from_slice(info);
413                parts.push(&ctr);
414                self.hmac(prk, &parts)
415            };
416            chunk.copy_from_slice(&next[..chunk.len()]);
417            t = next;
418        }
419    }
420}
421
422#[cfg(test)]
423mod tests {
424    use super::*;
425    use crate::util::{hex, unhex};
426
427    #[test]
428    fn sha256_vectors_hardware_and_soft() {
429        let million = vec![b'a'; 1_000_000];
430        for soft in [false, true] {
431            let digest = |d: &[u8]| -> [u8; 32] {
432                if soft {
433                    let mut st = Sha256::new().state;
434                    let mut b = Buf::<64>::new();
435                    b.update(d, |x| compress256_soft(&mut st, x));
436                    b.pad(8, |x| compress256_soft(&mut st, x));
437                    let mut out = [0u8; 32];
438                    for (o, w) in out.chunks_exact_mut(4).zip(st) {
439                        o.copy_from_slice(&w.to_be_bytes());
440                    }
441                    out
442                } else {
443                    Sha256::digest(d)
444                }
445            };
446            assert_eq!(hex(&digest(b"")), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
447            assert_eq!(hex(&digest(b"abc")), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
448            assert_eq!(
449                hex(&digest(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")),
450                "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
451            );
452            assert_eq!(hex(&digest(&million)), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
453        }
454        // Incremental updates across block boundaries, including the 55/56/64-byte padding edges.
455        for len in [55usize, 56, 63, 64, 65, 119, 120, 1000] {
456            let data: Vec<u8> = (0..len).map(|i| i as u8).collect();
457            let mut h = Sha256::new();
458            for c in data.chunks(7) {
459                h.update(c);
460            }
461            assert_eq!(h.finish(), Sha256::digest(&data));
462        }
463        let mut h = Sha256::new();
464        for c in million.chunks(37) {
465            h.update(c);
466        }
467        assert_eq!(hex(&h.finish()), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
468    }
469
470    #[test]
471    fn sha384_sha512_vectors() {
472        assert_eq!(
473            hex(&HashAlg::Sha384.hash(b"abc")),
474            "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"
475        );
476        assert_eq!(
477            hex(&HashAlg::Sha384.hash(b"")),
478            "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
479        );
480        assert_eq!(
481            hex(&HashAlg::Sha384.hash(b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")),
482            "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"
483        );
484        assert_eq!(
485            hex(&{
486                let mut h = Sha512::new512_256();
487                h.update(b"abc");
488                h.finish()
489            }),
490            "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"
491        );
492        assert_eq!(
493            hex(&HashAlg::Sha512.hash(b"abc")),
494            "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
495        );
496        let data = vec![0x61u8; 1000];
497        let mut h = Hasher::new(HashAlg::Sha512);
498        for c in data.chunks(111) {
499            h.update(c);
500        }
501        assert_eq!(h.finish(), HashAlg::Sha512.hash(&data));
502    }
503
504    #[test]
505    fn hmac_rfc4231() {
506        let key = [0x0bu8; 20];
507        assert_eq!(
508            hex(&HashAlg::Sha256.hmac(&key, &[b"Hi There"])),
509            "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
510        );
511        assert_eq!(
512            hex(&HashAlg::Sha384.hmac(&key, &[b"Hi ", b"There"])),
513            "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"
514        );
515        assert_eq!(
516            hex(&HashAlg::Sha512.hmac(&key, &[b"Hi There"])),
517            "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
518        );
519        assert_eq!(
520            hex(&HashAlg::Sha256.hmac(b"Jefe", &[b"what do ya want for nothing?"])),
521            "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
522        );
523        let key = [0xaau8; 131];
524        assert_eq!(
525            hex(&HashAlg::Sha256.hmac(&key, &[b"Test Using Larger Than Block-Size Key - Hash Key First"])),
526            "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"
527        );
528    }
529
530    #[test]
531    fn hkdf_rfc5869() {
532        let ikm = [0x0bu8; 22];
533        let prk = HashAlg::Sha256.hkdf_extract(&unhex("000102030405060708090a0b0c"), &ikm);
534        assert_eq!(hex(&prk), "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5");
535        let mut okm = [0u8; 42];
536        HashAlg::Sha256.hkdf_expand(&prk, &[&unhex("f0f1f2f3f4"), &unhex("f5f6f7f8f9")], &mut okm);
537        assert_eq!(hex(&okm), "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865");
538        let prk = HashAlg::Sha256.hkdf_extract(&[], &ikm);
539        assert_eq!(hex(&prk), "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04");
540        HashAlg::Sha256.hkdf_expand(&prk, &[], &mut okm);
541        assert_eq!(hex(&okm), "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8");
542    }
543}