1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6 
7 //! This module implements the HMAC-based Extract-and-Expand Key
8 //! Derivation Function as specified by  https://tools.ietf.org/html/rfc5869.
9 
10 use std::iter::repeat;
11 use cryptoutil::copy_memory;
12 
13 use digest::Digest;
14 use hmac::Hmac;
15 use mac::Mac;
16 
17 /// Execute the HKDF-Extract function.  Applications MUST NOT use this for
18 /// password hashing.
19 ///
20 /// # Arguments
21 /// * digest - The digest function to use.
22 /// * salt - The optional salt value (a non-secret random value) to use.
23 /// * ikm - The input keying material to use.
24 /// * prk - The output buffer to fill with a digest.output_bytes() length
25 ///         pseudo random key.
hkdf_extract<D: Digest>(mut digest: D, salt: &[u8], ikm: &[u8], prk: &mut [u8])26 pub fn hkdf_extract<D: Digest>(mut digest: D, salt: &[u8], ikm: &[u8], prk: &mut [u8]) {
27     assert!(prk.len() == digest.output_bytes());
28     digest.reset();
29 
30     let mut mac = Hmac::new(digest, salt);
31     mac.input(ikm);
32     mac.raw_result(prk);
33     mac.reset();
34 }
35 
36 /// Execute the HKDF-Expand function.  Applications MUST NOT use this for
37 /// password hashing.
38 ///
39 /// # Arguments
40 /// * digest - The digest function to use.
41 /// * prk - The pseudorandom key of at least digest.output_bytes() octets.
42 /// * info - The optional context and application specific information to use.
43 /// * okm - The output buffer to fill with the derived key value.
hkdf_expand<D: Digest>(mut digest: D, prk: &[u8], info: &[u8], okm: &mut [u8])44 pub fn hkdf_expand<D: Digest>(mut digest: D, prk: &[u8], info: &[u8], okm: &mut [u8]) {
45     digest.reset();
46 
47     let mut mac = Hmac::new(digest, prk);
48     let os = mac.output_bytes();
49     let mut t: Vec<u8> = repeat(0).take(os).collect();
50     let mut n: u8 = 0;
51 
52     for chunk in okm.chunks_mut(os) {
53         // The block index starts at 1. So, this is supposed to run on the first execution.
54         n = n.checked_add(1).expect("HKDF size limit exceeded.");
55 
56         if n != 1 {
57             mac.input(&t[..]);
58         }
59         let nbuf = [n];
60         mac.input(info);
61         mac.input(&nbuf);
62         mac.raw_result(&mut t);
63         mac.reset();
64         let chunk_len = chunk.len();
65         copy_memory(&t[..chunk_len], chunk);
66     }
67 }
68 
69 #[cfg(test)]
70 mod test {
71     use std::iter::repeat;
72 
73     use digest::Digest;
74     use sha1::Sha1;
75     use sha2::Sha256;
76     use hkdf::{hkdf_extract, hkdf_expand};
77 
78     struct TestVector<D: Digest>{
79         digest: D,
80         ikm: Vec<u8>,
81         salt: Vec<u8>,
82         info: Vec<u8>,
83         l: usize,
84 
85         prk: Vec<u8>,
86         okm: Vec<u8>,
87     }
88 
89     #[test]
test_hkdf_rfc5869_sha256_vectors()90     fn test_hkdf_rfc5869_sha256_vectors() {
91         let test_vectors = vec!(
92             TestVector{
93                 digest: Sha256::new(),
94                 ikm: repeat(0x0b).take(22).collect(),
95                 salt: (0x00..0x0c + 1).collect(),
96                 info: (0xf0..0xf9 + 1).collect(),
97                 l: 42,
98                 prk: vec![
99                     0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
100                     0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
101                     0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
102                     0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5 ],
103                 okm: vec![
104                     0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
105                     0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
106                     0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
107                     0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
108                     0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
109                     0x58, 0x65 ],
110             },
111             TestVector{
112                 digest: Sha256::new(),
113                 ikm: (0x00..0x4f + 1).collect(),
114                 salt: (0x60..0xaf + 1).collect(),
115                 info: (0xb0..0xff + 1).map(|x| x as u8).collect(),
116                 l: 82,
117                 prk: vec![
118                     0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
119                     0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
120                     0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
121                     0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44 ],
122                 okm: vec![
123                     0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
124                     0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
125                     0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
126                     0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
127                     0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
128                     0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
129                     0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
130                     0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
131                     0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
132                     0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
133                     0x1d, 0x87 ],
134             },
135             TestVector{
136                 digest: Sha256::new(),
137                 ikm: repeat(0x0b).take(22).collect(),
138                 salt: vec![],
139                 info: vec![],
140                 l:42,
141                 prk: vec![
142                     0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16,
143                     0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
144                     0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
145                     0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04 ],
146                 okm: vec![
147                     0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
148                     0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
149                     0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
150                     0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
151                     0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
152                     0x96, 0xc8 ],
153             },
154         );
155 
156         for t in test_vectors.iter() {
157             let mut prk: Vec<u8> = repeat(0).take(t.prk.len()).collect();
158             hkdf_extract(t.digest, &t.salt[..], &t.ikm[..], &mut prk);
159             assert!(prk == t.prk);
160 
161             let mut okm: Vec<u8> = repeat(0).take(t.okm.len()).collect();
162             assert!(okm.len() == t.l);
163             hkdf_expand(t.digest, &prk[..], &t.info[..], &mut okm);
164             assert!(okm == t.okm);
165         }
166     }
167 
168     #[test]
test_hkdf_rfc5869_sha1_vectors()169     fn test_hkdf_rfc5869_sha1_vectors() {
170         let test_vectors = vec!(
171             TestVector{
172                 digest: Sha1::new(),
173                 ikm: repeat(0x0b).take(11).collect(),
174                 salt: (0x00..0x0c + 1).collect(),
175                 info: (0xf0..0xf9 + 1).collect(),
176                 l: 42,
177                 prk: vec![
178                     0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f,
179                     0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b,
180                     0xaa, 0x2b, 0xa2, 0x43 ],
181                 okm: vec![
182                     0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69,
183                     0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81,
184                     0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15,
185                     0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2,
186                     0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3,
187                     0xf8, 0x96 ],
188             },
189             TestVector{
190                 digest: Sha1::new(),
191                 ikm: (0x00..0x4f + 1).collect(),
192                 salt: (0x60..0xaf + 1).collect(),
193                 info: (0xb0..0xff + 1).map(|x| x as u8).collect(),
194                 l: 82,
195                 prk: vec![
196                     0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59,
197                     0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a,
198                     0x22, 0x4c, 0xfa, 0xf6 ],
199                 okm: vec![
200                     0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7,
201                     0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb,
202                     0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19,
203                     0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe,
204                     0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3,
205                     0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c,
206                     0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed,
207                     0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e,
208                     0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43,
209                     0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52,
210                     0xd3, 0xb4 ],
211             },
212             TestVector{
213                 digest: Sha1::new(),
214                 ikm: repeat(0x0b).take(22).collect(),
215                 salt: vec![],
216                 info: vec![],
217                 l:42,
218                 prk: vec![
219                     0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28,
220                     0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a,
221                     0xa0, 0xd3, 0x2d, 0x01 ],
222                 okm: vec![
223                     0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61,
224                     0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06,
225                     0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06,
226                     0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0,
227                     0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3,
228                     0x49, 0x18 ],
229             },
230         );
231 
232         for t in test_vectors.iter() {
233             let mut prk: Vec<u8> = repeat(0).take(t.prk.len()).collect();
234             hkdf_extract(t.digest, &t.salt[..], &t.ikm[..], &mut prk);
235             assert!(prk == t.prk);
236 
237             let mut okm: Vec<u8> = repeat(0).take(t.okm.len()).collect();
238             assert!(okm.len() == t.l);
239             hkdf_expand(t.digest, &prk[..], &t.info[..], &mut okm);
240             assert!(okm == t.okm);
241         }
242     }
243 }
244