hkdf/
lib.rs

1//! This crate implements the [RFC5869] hash based key derivation function using
2//! [`bitcoin_hashes`].
3//!
4//! [RFC5869]: https://www.rfc-editor.org/rfc/rfc5869
5//! [`bitcoin_hashes`]: https://docs.rs/bitcoin_hashes/latest/bitcoin_hashes/
6
7use 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/// Implements the [RFC5869] hash based key derivation function using the hash
24/// function `H`.
25///
26/// [RFC5869]: https://www.rfc-editor.org/rfc/rfc5869
27#[derive(Clone)]
28pub struct Hkdf<H: BitcoinHash> {
29    prk: Hmac<H>,
30}
31
32impl<H: BitcoinHash> Hkdf<H> {
33    /// Run HKDF-extract and keep the resulting pseudo random key as internal
34    /// state
35    ///
36    /// ## Inputs
37    /// * `ikm`: Input keying material, secret key material our keys will be
38    ///   derived from
39    /// * `salt`: Optional salt value, if not required set to `&[0; H::LEN]`. As
40    ///   noted in the RFC the salt value can also be a secret.
41    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    /// Construct the HKDF from a pseudo random key that has the correct
51    /// distribution and length already (e.g. because it's the output of a
52    /// previous HKDF round), skipping the HKDF-extract step. **If in doubt,
53    /// please use `Hkdf::new` instead!**
54    ///
55    /// See also [`Hkdf::derive_hmac`].
56    pub fn from_prk(prk: Hmac<H>) -> Self {
57        Hkdf { prk }
58    }
59
60    /// Run HKDF-expand to generate new key material
61    ///
62    /// ## Inputs
63    /// * `info`: Defines which key to derive. Different values lead to
64    ///   different keys.
65    /// * `LEN`: Defines the length of the key material to generate in octets.
66    ///   Note that `LEN <= H::LEN * 255` has to be true.
67    ///
68    /// ## Panics
69    /// If `LEN > H::LEN * 255`.
70    pub fn derive<const LEN: usize>(&self, info: &[u8]) -> [u8; LEN] {
71        // TODO: make const once rust allows
72        let iterations = if LEN % H::LEN == 0 {
73            LEN / H::LEN
74        } else {
75            LEN / H::LEN + 1
76        };
77
78        // Make sure we can cast iteration numbers to u8 later
79        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            // TODO: re-use midstate
94            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    /// Run HKDF-expand to generate new key material with `L = H::LEN`
108    ///
109    /// See [`Hkdf::derive`] for more information.
110    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        // Addition to test derive_hkdf
169        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}