1use crate::hmac;
32
33pub fn extract_sha256(salt: &[u8], ikm: &[u8]) -> [u8; 32] {
54    hmac::hmac_sha256(salt, ikm)
55}
56
57pub fn extract<T: AsRef<[u8]>>(salt: &[u8], ikm: &[u8], hmac: fn(&[u8], &[u8]) -> T) -> T {
59    hmac(salt, ikm)
60}
61
62pub fn expand_sha256(prk: &[u8], info: &[u8], l: usize) -> Box<[u8]> {
84    let mut result: Vec<u8> = Vec::with_capacity(l);
86    let text_max_len = 32 + info.len() + 1;
87
88    let mut t: Vec<u8> = Vec::with_capacity(text_max_len);
89    let mut i = 0usize;
90    while result.len() < l {
91        t.extend_from_slice(info);
92        i += 1;
93        t.push(i as u8);
94        let hmac_hash = hmac::hmac_sha256(prk, &t);
95        t.truncate(0);
96        t.extend_from_slice(&hmac_hash);
97        result.extend_from_slice(&hmac_hash);
98    }
99
100    result.truncate(l);
101    result.into_boxed_slice()
102}
103
104pub fn expand<T: AsRef<[u8]>>(
105    prk: &[u8],
106    info: &[u8],
107    l: usize,
108    hmac: fn(&[u8], &[u8]) -> T,
109) -> Box<[u8]> {
110    let mut result: Vec<u8> = Vec::with_capacity(l);
112    let text_max_len = 64 + info.len() + 1;
113
114    let mut t: Vec<u8> = Vec::with_capacity(text_max_len);
115    let mut i = 0usize;
116    while result.len() < l {
117        t.extend_from_slice(info);
118        i += 1;
119        t.push(i as u8);
120        let hmac_hash = hmac(prk, &t);
121        t.truncate(0);
122        t.extend_from_slice(&hmac_hash.as_ref());
123        result.extend_from_slice(&hmac_hash.as_ref());
124    }
125
126    result.truncate(l);
127    result.into_boxed_slice()
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133    use crate::hmac::hmac_sha256;
134
135    #[test]
136    fn test_extract_expand_sha256_1() {
137        let ikm: [u8; 80] = [
139            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
140            0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
141            0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
142            0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
143            0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
144            0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
145        ];
146        let salt: [u8; 80] = [
148            0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
149            0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b,
150            0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
151            0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
152            0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
153            0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
154        ];
155
156        let info: [u8; 80] = [
157            0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd,
158            0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
159            0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
160            0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
161            0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
162            0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
163        ];
164
165        let l = 82usize;
166
167        let prk: [u8; 32] = [
168            0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35,
169            0xb4, 0x5c, 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, 0x4a, 0x19, 0x3f, 0x40,
170            0xc1, 0x5f, 0xc2, 0x44,
171        ];
172
173        let okm: [u8; 82] = [
174            0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a,
175            0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c,
176            0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb,
177            0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
178            0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec,
179            0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87,
180        ];
181
182        let result = extract(&salt, &ikm, hmac_sha256);
183        assert_eq!(result, prk);
184
185        let result: &[u8] = &expand(&prk, &info, l, hmac_sha256);
186        assert_eq!(result.len(), l);
187        assert_eq!(result, &okm[..]);
188    }
189
190    #[test]
191    fn test_extract_expand_sha256_2() {
192        let ikm: [u8; 22] = [
193            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
194            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
195        ];
196        let salt: [u8; 13] = [
198            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
199        ];
200
201        let info: [u8; 10] = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9];
202
203        let l = 42usize;
204
205        let prk: [u8; 32] = [
206            0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b,
207            0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, 0x22, 0xec, 0x84, 0x4a,
208            0xd7, 0xc2, 0xb3, 0xe5,
209        ];
210
211        let okm: [u8; 42] = [
212            0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36,
213            0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56,
214            0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65,
215        ];
216
217        let result = extract(&salt, &ikm, hmac_sha256);
218        assert_eq!(result, prk);
219
220        let result: &[u8] = &expand(&prk, &info, l, hmac_sha256);
221        assert_eq!(result.len(), l);
222        assert_eq!(result, &okm[..]);
223    }
224
225    #[test]
226    fn test_extract_expand_sha256_3() {
227        let ikm: [u8; 22] = [
228            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
229            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
230        ];
231        let l = 42usize;
232
233        let prk: [u8; 32] = [
234            0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64,
235            0x8b, 0xdf, 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, 0xac, 0x43, 0x4c, 0x1c,
236            0x29, 0x3c, 0xcb, 0x04,
237        ];
238
239        let okm: [u8; 42] = [
240            0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c,
241            0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f,
242            0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8,
243        ];
244
245        let result = extract(&[], &ikm, hmac_sha256);
246        assert_eq!(result, prk);
247
248        let result: &[u8] = &expand(&prk, &[], l, hmac_sha256);
249        assert_eq!(result.len(), l);
250        assert_eq!(result, &okm[..]);
251    }
252}