/rust/registry/src/index.crates.io-1949cf8c6b5b557f/openssl-0.10.62/src/pkcs5.rs
Line | Count | Source |
1 | | #[cfg(not(boringssl))] |
2 | | use libc::c_int; |
3 | | use std::convert::TryInto; |
4 | | #[cfg(not(boringssl))] |
5 | | use std::ptr; |
6 | | |
7 | | use crate::cvt; |
8 | | use crate::error::ErrorStack; |
9 | | use crate::hash::MessageDigest; |
10 | | #[cfg(not(boringssl))] |
11 | | use crate::symm::Cipher; |
12 | | use openssl_macros::corresponds; |
13 | | |
14 | | #[derive(Clone, Eq, PartialEq, Hash, Debug)] |
15 | | pub struct KeyIvPair { |
16 | | pub key: Vec<u8>, |
17 | | pub iv: Option<Vec<u8>>, |
18 | | } |
19 | | |
20 | | /// Derives a key and an IV from various parameters. |
21 | | /// |
22 | | /// If specified, `salt` must be 8 bytes in length. |
23 | | /// |
24 | | /// If the total key and IV length is less than 16 bytes and MD5 is used then |
25 | | /// the algorithm is compatible with the key derivation algorithm from PKCS#5 |
26 | | /// v1.5 or PBKDF1 from PKCS#5 v2.0. |
27 | | /// |
28 | | /// New applications should not use this and instead use |
29 | | /// `pbkdf2_hmac` or another more modern key derivation algorithm. |
30 | | #[corresponds(EVP_BytesToKey)] |
31 | | #[allow(clippy::useless_conversion)] |
32 | | #[cfg(not(boringssl))] |
33 | 0 | pub fn bytes_to_key( |
34 | 0 | cipher: Cipher, |
35 | 0 | digest: MessageDigest, |
36 | 0 | data: &[u8], |
37 | 0 | salt: Option<&[u8]>, |
38 | 0 | count: i32, |
39 | 0 | ) -> Result<KeyIvPair, ErrorStack> { |
40 | | unsafe { |
41 | 0 | assert!(data.len() <= c_int::max_value() as usize); |
42 | 0 | let salt_ptr = match salt { |
43 | 0 | Some(salt) => { |
44 | 0 | assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize); |
45 | 0 | salt.as_ptr() |
46 | | } |
47 | 0 | None => ptr::null(), |
48 | | }; |
49 | | |
50 | 0 | ffi::init(); |
51 | | |
52 | 0 | let mut iv = cipher.iv_len().map(|l| vec![0; l]); |
53 | | |
54 | 0 | let cipher = cipher.as_ptr(); |
55 | 0 | let digest = digest.as_ptr(); |
56 | | |
57 | 0 | let len = cvt(ffi::EVP_BytesToKey( |
58 | 0 | cipher, |
59 | 0 | digest, |
60 | 0 | salt_ptr, |
61 | 0 | ptr::null(), |
62 | 0 | data.len() as c_int, |
63 | 0 | count.into(), |
64 | 0 | ptr::null_mut(), |
65 | 0 | ptr::null_mut(), |
66 | 0 | ))?; |
67 | | |
68 | 0 | let mut key = vec![0; len as usize]; |
69 | 0 | let iv_ptr = iv |
70 | 0 | .as_mut() |
71 | 0 | .map(|v| v.as_mut_ptr()) |
72 | 0 | .unwrap_or(ptr::null_mut()); |
73 | | |
74 | 0 | cvt(ffi::EVP_BytesToKey( |
75 | 0 | cipher, |
76 | 0 | digest, |
77 | 0 | salt_ptr, |
78 | 0 | data.as_ptr(), |
79 | 0 | data.len() as c_int, |
80 | 0 | count as c_int, |
81 | 0 | key.as_mut_ptr(), |
82 | 0 | iv_ptr, |
83 | 0 | ))?; |
84 | | |
85 | 0 | Ok(KeyIvPair { key, iv }) |
86 | | } |
87 | 0 | } |
88 | | |
89 | | /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. |
90 | | #[corresponds(PKCS5_PBKDF2_HMAC)] |
91 | 0 | pub fn pbkdf2_hmac( |
92 | 0 | pass: &[u8], |
93 | 0 | salt: &[u8], |
94 | 0 | iter: usize, |
95 | 0 | hash: MessageDigest, |
96 | 0 | key: &mut [u8], |
97 | 0 | ) -> Result<(), ErrorStack> { |
98 | | unsafe { |
99 | 0 | ffi::init(); |
100 | 0 | cvt(ffi::PKCS5_PBKDF2_HMAC( |
101 | 0 | pass.as_ptr() as *const _, |
102 | 0 | pass.len().try_into().unwrap(), |
103 | 0 | salt.as_ptr(), |
104 | 0 | salt.len().try_into().unwrap(), |
105 | 0 | iter.try_into().unwrap(), |
106 | 0 | hash.as_ptr(), |
107 | 0 | key.len().try_into().unwrap(), |
108 | 0 | key.as_mut_ptr(), |
109 | | )) |
110 | 0 | .map(|_| ()) |
111 | | } |
112 | 0 | } |
113 | | |
114 | | /// Derives a key from a password and salt using the scrypt algorithm. |
115 | | /// |
116 | | /// Requires OpenSSL 1.1.0 or newer. |
117 | | #[corresponds(EVP_PBE_scrypt)] |
118 | | #[cfg(all(any(ossl110, boringssl), not(osslconf = "OPENSSL_NO_SCRYPT")))] |
119 | | #[allow(clippy::useless_conversion)] |
120 | 0 | pub fn scrypt( |
121 | 0 | pass: &[u8], |
122 | 0 | salt: &[u8], |
123 | 0 | n: u64, |
124 | 0 | r: u64, |
125 | 0 | p: u64, |
126 | 0 | maxmem: u64, |
127 | 0 | key: &mut [u8], |
128 | 0 | ) -> Result<(), ErrorStack> { |
129 | | unsafe { |
130 | 0 | ffi::init(); |
131 | 0 | cvt(ffi::EVP_PBE_scrypt( |
132 | 0 | pass.as_ptr() as *const _, |
133 | 0 | pass.len(), |
134 | 0 | salt.as_ptr() as *const _, |
135 | 0 | salt.len(), |
136 | 0 | n, |
137 | 0 | r, |
138 | 0 | p, |
139 | 0 | maxmem.try_into().unwrap(), |
140 | 0 | key.as_mut_ptr() as *mut _, |
141 | 0 | key.len(), |
142 | | )) |
143 | 0 | .map(|_| ()) |
144 | | } |
145 | 0 | } |
146 | | |
147 | | #[cfg(test)] |
148 | | mod tests { |
149 | | use crate::hash::MessageDigest; |
150 | | #[cfg(not(boringssl))] |
151 | | use crate::symm::Cipher; |
152 | | |
153 | | // Test vectors from |
154 | | // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c |
155 | | #[test] |
156 | | fn pbkdf2_hmac_sha256() { |
157 | | let mut buf = [0; 16]; |
158 | | |
159 | | super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap(); |
160 | | assert_eq!( |
161 | | buf, |
162 | | &[ |
163 | | 0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, 0xec_u8, |
164 | | 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8, |
165 | | ][..] |
166 | | ); |
167 | | |
168 | | super::pbkdf2_hmac( |
169 | | b"Password", |
170 | | b"NaCl", |
171 | | 80000, |
172 | | MessageDigest::sha256(), |
173 | | &mut buf, |
174 | | ) |
175 | | .unwrap(); |
176 | | assert_eq!( |
177 | | buf, |
178 | | &[ |
179 | | 0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, 0x83_u8, |
180 | | 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8, |
181 | | ][..] |
182 | | ); |
183 | | } |
184 | | |
185 | | // Test vectors from |
186 | | // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c |
187 | | #[test] |
188 | | fn pbkdf2_hmac_sha512() { |
189 | | let mut buf = [0; 64]; |
190 | | |
191 | | super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap(); |
192 | | assert_eq!( |
193 | | &buf[..], |
194 | | &[ |
195 | | 0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, 0x94_u8, |
196 | | 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8, |
197 | | 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8, |
198 | | 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, |
199 | | 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, |
200 | | 0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, |
201 | | 0x5e_u8, 0x9f_u8, 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, |
202 | | 0x06_u8, |
203 | | ][..] |
204 | | ); |
205 | | |
206 | | super::pbkdf2_hmac( |
207 | | b"pass\0word", |
208 | | b"sa\0lt", |
209 | | 1, |
210 | | MessageDigest::sha512(), |
211 | | &mut buf, |
212 | | ) |
213 | | .unwrap(); |
214 | | assert_eq!( |
215 | | &buf[..], |
216 | | &[ |
217 | | 0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, 0x8b_u8, |
218 | | 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8, |
219 | | 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8, |
220 | | 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, |
221 | | 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, |
222 | | 0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, |
223 | | 0x5a_u8, 0xb5_u8, 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, |
224 | | 0xa7_u8, |
225 | | ][..] |
226 | | ); |
227 | | |
228 | | super::pbkdf2_hmac( |
229 | | b"passwordPASSWORDpassword", |
230 | | b"salt\0\0\0", |
231 | | 50, |
232 | | MessageDigest::sha512(), |
233 | | &mut buf, |
234 | | ) |
235 | | .unwrap(); |
236 | | assert_eq!( |
237 | | &buf[..], |
238 | | &[ |
239 | | 0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, 0x85_u8, |
240 | | 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8, |
241 | | 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8, |
242 | | 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, |
243 | | 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, |
244 | | 0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, |
245 | | 0x4b_u8, 0x1a_u8, 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, |
246 | | 0x39_u8, |
247 | | ][..] |
248 | | ); |
249 | | } |
250 | | |
251 | | #[test] |
252 | | #[cfg(not(boringssl))] |
253 | | fn bytes_to_key() { |
254 | | let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; |
255 | | |
256 | | let data = [ |
257 | | 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, |
258 | | 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, |
259 | | 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, |
260 | | ]; |
261 | | |
262 | | let expected_key = vec![ |
263 | | 249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8, 87_u8, 234_u8, |
264 | | 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, |
265 | | 229_u8, 161_u8, 183_u8, 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8, |
266 | | ]; |
267 | | let expected_iv = vec![ |
268 | | 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, |
269 | | 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, |
270 | | ]; |
271 | | |
272 | | assert_eq!( |
273 | | super::bytes_to_key( |
274 | | Cipher::aes_256_cbc(), |
275 | | MessageDigest::sha1(), |
276 | | &data, |
277 | | Some(&salt), |
278 | | 1, |
279 | | ) |
280 | | .unwrap(), |
281 | | super::KeyIvPair { |
282 | | key: expected_key, |
283 | | iv: Some(expected_iv), |
284 | | } |
285 | | ); |
286 | | } |
287 | | |
288 | | #[test] |
289 | | #[cfg(any(ossl110, boringssl))] |
290 | | fn scrypt() { |
291 | | let pass = "pleaseletmein"; |
292 | | let salt = "SodiumChloride"; |
293 | | let expected = |
294 | | "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\ |
295 | | f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"; |
296 | | |
297 | | let mut actual = [0; 64]; |
298 | | super::scrypt( |
299 | | pass.as_bytes(), |
300 | | salt.as_bytes(), |
301 | | 16384, |
302 | | 8, |
303 | | 1, |
304 | | 0, |
305 | | &mut actual, |
306 | | ) |
307 | | .unwrap(); |
308 | | assert_eq!(hex::encode(&actual[..]), expected); |
309 | | } |
310 | | } |