1use std::cmp::min;
8
9pub use bitcoin_hashes;
10pub use bitcoin_hashes::Hash as BitcoinHash;
11use bitcoin_hashes::{HashEngine, Hmac, HmacEngine};
12
13pub mod hashes {
14 pub use bitcoin_hashes::hash160::Hash as Hash160;
15 pub use bitcoin_hashes::ripemd160::Hash as Ripemd160;
16 pub use bitcoin_hashes::sha1::Hash as Sha1;
17 pub use bitcoin_hashes::sha256::Hash as Sha256;
18 pub use bitcoin_hashes::sha256d::Hash as Sha256d;
19 pub use bitcoin_hashes::sha512::Hash as Sha512;
20 pub use bitcoin_hashes::siphash24::Hash as Siphash24;
21}
22
23#[derive(Clone)]
28pub struct Hkdf<H: BitcoinHash> {
29 prk: Hmac<H>,
30}
31
32impl<H: BitcoinHash> Hkdf<H> {
33 pub fn new(ikm: &[u8], salt: Option<&[u8]>) -> Self {
42 let mut engine = HmacEngine::new(salt.unwrap_or(&vec![0x00; H::LEN]));
43 engine.input(ikm);
44
45 Hkdf {
46 prk: Hmac::from_engine(engine),
47 }
48 }
49
50 pub fn from_prk(prk: Hmac<H>) -> Self {
57 Hkdf { prk }
58 }
59
60 pub fn derive<const LEN: usize>(&self, info: &[u8]) -> [u8; LEN] {
71 let iterations = if LEN % H::LEN == 0 {
73 LEN / H::LEN
74 } else {
75 LEN / H::LEN + 1
76 };
77
78 assert!(
80 iterations <= 255,
81 "RFC5869 only supports output length of up to 255*HashLength"
82 );
83
84 let mut output = [0u8; LEN];
85 for iteration in 0..iterations {
86 let current_slice = (H::LEN * iteration)..min(H::LEN * (iteration + 1), LEN);
87 let last_slice = if iteration == 0 {
88 0..0
89 } else {
90 (H::LEN * (iteration - 1))..(H::LEN * iteration)
91 };
92
93 let mut engine = HmacEngine::<H>::new(&self.prk[..]);
95 engine.input(&output[last_slice]);
96 engine.input(info);
97 engine.input(&[(iteration + 1) as u8]);
98 let output_bytes = Hmac::from_engine(engine);
99
100 let bytes_to_copy = current_slice.end - current_slice.start;
101 output[current_slice].copy_from_slice(&output_bytes[0..bytes_to_copy]);
102 }
103
104 output
105 }
106
107 pub fn derive_hmac(&self, info: &[u8]) -> Hmac<H> {
111 let mut engine = HmacEngine::<H>::new(&self.prk[..]);
112 engine.input(info);
113 engine.input(&[1u8]);
114 Hmac::from_engine(engine)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use bitcoin_hashes::Hash as BitcoinHash;
121
122 use crate::Hkdf;
123
124 #[test]
125 #[should_panic(expected = "RFC5869 only supports output length of up to 255*HashLength")]
126 fn test_too_long_output_key() {
127 let hkdf = Hkdf::<crate::hashes::Sha512>::new("foo".as_bytes(), None);
128 hkdf.derive::<16321>(&[]);
129 }
130
131 #[test]
132 fn test_long_output_key_ok() {
133 let hkdf = Hkdf::<crate::hashes::Sha512>::new("foo".as_bytes(), None);
134 hkdf.derive::<16320>(&[]);
135 }
136
137 #[test]
138 fn rfc5896_test_vector_1() {
139 let input_key = [
140 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
141 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
142 ];
143 let salt = Some(
144 &[
145 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
146 ][..],
147 );
148 let info = &[0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
149 let hkdf = Hkdf::<crate::hashes::Sha256>::new(&input_key, salt);
150 let output_key = hkdf.derive::<42>(info);
151 assert_eq!(
152 &hkdf.prk[..],
153 &[
154 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b,
155 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a,
156 0xd7, 0xc2, 0xb3, 0xe5,
157 ]
158 );
159 assert_eq!(
160 output_key,
161 [
162 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36,
163 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56,
164 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65,
165 ]
166 );
167
168 let output_key_hkdf = hkdf.derive_hmac(info);
170 assert_eq!(
171 output_key[0..crate::hashes::Sha256::LEN],
172 output_key_hkdf[..]
173 )
174 }
175
176 #[test]
177 fn rfc5896_test_vector_2() {
178 let input_key = [
179 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
180 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
181 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
182 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
183 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
184 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
185 ];
186 let salt = Some(
187 &[
188 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
189 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
190 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
191 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
192 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
193 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
194 ][..],
195 );
196 let info = [
197 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd,
198 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
199 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
200 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
201 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
202 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
203 ];
204 let hkdf = Hkdf::<crate::hashes::Sha256>::new(&input_key, salt);
205 let output_key = hkdf.derive(&info);
206 assert_eq!(
207 &hkdf.prk[..],
208 &[
209 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35,
210 0xb4, 0x5c, 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, 0x4a, 0x19, 0x3f, 0x40,
211 0xc1, 0x5f, 0xc2, 0x44,
212 ]
213 );
214 assert_eq!(
215 output_key,
216 [
217 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a,
218 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c,
219 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb,
220 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
221 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec,
222 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87,
223 ]
224 );
225 }
226
227 #[test]
228 fn rfc5896_test_vector_3() {
229 let input_key = [
230 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
231 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
232 ];
233 let salt = Some(&[][..]);
234 let info = [];
235 let hkdf = Hkdf::<crate::hashes::Sha256>::new(&input_key, salt);
236 let output_key = hkdf.derive(&info);
237 assert_eq!(
238 &hkdf.prk[..],
239 &[
240 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64,
241 0x8b, 0xdf, 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, 0xac, 0x43, 0x4c, 0x1c,
242 0x29, 0x3c, 0xcb, 0x04,
243 ]
244 );
245 assert_eq!(
246 output_key,
247 [
248 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c,
249 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f,
250 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8,
251 ]
252 );
253 }
254
255 #[test]
256 fn rfc5896_test_vector_4() {
257 let input_key = [
258 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
259 ];
260 let salt = Some(
261 &[
262 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
263 ][..],
264 );
265 let info = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
266 let hkdf = Hkdf::<crate::hashes::Sha1>::new(&input_key, salt);
267 let output_key = hkdf.derive(&info);
268 assert_eq!(
269 &hkdf.prk[..],
270 &[
271 0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, 0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4,
272 0xb3, 0x0b, 0xaa, 0x2b, 0xa2, 0x43,
273 ]
274 );
275 assert_eq!(
276 output_key,
277 [
278 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5,
279 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4,
280 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96,
281 ]
282 );
283 }
284
285 #[test]
286 fn rfc5896_test_vector_5() {
287 let input_key = [
288 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
289 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
290 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
291 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
292 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
293 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
294 ];
295 let salt = Some(
296 &[
297 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
298 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
299 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
300 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
301 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
302 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
303 ][..],
304 );
305 let info = [
306 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd,
307 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
308 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
309 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
310 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
311 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
312 ];
313 let hkdf = Hkdf::<crate::hashes::Sha1>::new(&input_key, salt);
314 let output_key = hkdf.derive(&info);
315 assert_eq!(
316 &hkdf.prk[..],
317 &[
318 0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, 0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4,
319 0x11, 0x5a, 0x22, 0x4c, 0xfa, 0xf6,
320 ]
321 );
322 assert_eq!(
323 output_key,
324 [
325 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a,
326 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56,
327 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34,
328 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed,
329 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f,
330 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4,
331 ]
332 );
333 }
334
335 #[test]
336 fn rfc5896_test_vector_6() {
337 let input_key = [
338 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
339 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
340 ];
341 let salt = Some(&[][..]);
342 let info = [];
343 let hkdf = Hkdf::<crate::hashes::Sha1>::new(&input_key, salt);
344 let output_key = hkdf.derive(&info);
345 assert_eq!(
346 &hkdf.prk[..],
347 &[
348 0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, 0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97,
349 0x78, 0x6a, 0xa0, 0xd3, 0x2d, 0x01,
350 ]
351 );
352 assert_eq!(
353 output_key,
354 [
355 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d,
356 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87,
357 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18,
358 ]
359 );
360 }
361
362 #[test]
363 fn rfc5896_test_vector_7() {
364 let input_key = [
365 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
366 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
367 ];
368 let salt = None;
369 let info = [];
370 let hkdf = Hkdf::<crate::hashes::Sha1>::new(&input_key, salt);
371 let output_key = hkdf.derive(&info);
372 assert_eq!(
373 &hkdf.prk[..],
374 &[
375 0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, 0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d,
376 0x3f, 0x3e, 0x73, 0x13, 0x85, 0xdd,
377 ]
378 );
379 assert_eq!(
380 output_key,
381 [
382 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6,
383 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e,
384 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48,
385 ]
386 );
387 }
388}