1212
1313use std:: path:: Path ;
1414
15- use anyhow:: Context ;
15+ use anyhow:: { bail , Context } ;
1616use libcryptsetup_rs:: consts:: flags:: { CryptActivate , CryptDeactivate , CryptVolumeKey } ;
1717use libcryptsetup_rs:: consts:: vals:: EncryptionFormat ;
1818use libcryptsetup_rs:: { CryptInit , CryptParamsLuks2 , CryptParamsLuks2Ref } ;
@@ -43,11 +43,11 @@ impl Luks2Formatter {
4343
4444 pub fn encrypt_device (
4545 & self ,
46- device_path : & str ,
46+ device_path : & Path ,
47+ header_path : Option < & Path > ,
4748 passphrase : Zeroizing < Vec < u8 > > ,
4849 ) -> anyhow:: Result < ( ) > {
49- let path = Path :: new ( device_path) ;
50- let mut device = CryptInit :: init ( path) ?;
50+ let mut device = init_device ( device_path, header_path) ?;
5151 let mut volume_key_length = LUKS2_VOLUME_KEY_SIZE_BIT_WITHOUT_INTEGRITY / 8 ;
5252 let mut params = CryptParamsLuks2 {
5353 pbkdf : None ,
@@ -81,12 +81,12 @@ impl Luks2Formatter {
8181
8282 pub fn open_device (
8383 & self ,
84- device_path : & str ,
84+ device_path : & Path ,
85+ header_path : Option < & Path > ,
8586 name : & str ,
8687 passphrase : Zeroizing < Vec < u8 > > ,
8788 ) -> anyhow:: Result < ( ) > {
88- let path = Path :: new ( device_path) ;
89- let mut device = CryptInit :: init ( path) ?;
89+ let mut device = init_device ( device_path, header_path) ?;
9090
9191 let mut params = CryptParamsLuks2 {
9292 pbkdf : None ,
@@ -130,18 +130,45 @@ impl Luks2Formatter {
130130 }
131131}
132132
133+ fn init_device (
134+ device_path : & Path ,
135+ header_path : Option < & Path > ,
136+ ) -> anyhow:: Result < libcryptsetup_rs:: CryptDevice > {
137+ let device_paths = match header_path {
138+ Some ( header_path) => {
139+ if !header_path. exists ( ) {
140+ bail ! ( "LUKS header file not found: {}" , header_path. display( ) ) ;
141+ }
142+ libcryptsetup_rs:: Either :: Right ( ( header_path, device_path) )
143+ }
144+ None => libcryptsetup_rs:: Either :: Left ( device_path) ,
145+ } ;
146+
147+ Ok ( CryptInit :: init_with_data_device ( device_paths) ?)
148+ }
149+
133150#[ cfg( test) ]
134151mod tests {
135152 use std:: io:: Write ;
153+ use std:: path:: PathBuf ;
136154
137155 use serial_test:: serial;
138156 use zeroize:: Zeroizing ;
139157
140158 use crate :: storage:: drivers:: luks2:: Luks2Formatter ;
159+ use crate :: storage:: volume_type:: blockdevice:: prepare_luks_header_file;
141160
142161 const TEST_PASSPHRASE : & [ u8 ] = b"test" ;
143162 const NAME : & str = "test" ;
144163
164+ /// Removes the LUKS header file on drop so tests don't leave files behind on panic.
165+ struct RemoveHeaderOnDrop ( PathBuf ) ;
166+ impl Drop for RemoveHeaderOnDrop {
167+ fn drop ( & mut self ) {
168+ let _ = std:: fs:: remove_file ( & self . 0 ) ;
169+ }
170+ }
171+
145172 #[ test]
146173 #[ serial]
147174 fn encrypt_open_device_no_integrity ( ) {
@@ -151,15 +178,17 @@ mod tests {
151178 . as_file_mut ( )
152179 . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
153180 . unwrap ( ) ;
154- let path = bin_file. path ( ) . to_str ( ) . unwrap ( ) ;
181+ let path = bin_file. path ( ) ;
155182
156183 let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
157184 let luks2_formatter = Luks2Formatter { integrity : false } ;
158185 luks2_formatter
159- . encrypt_device ( path, passphrase. clone ( ) )
186+ . encrypt_device ( path, None , passphrase. clone ( ) )
160187 . unwrap ( ) ;
161188
162- luks2_formatter. open_device ( path, NAME , passphrase) . unwrap ( ) ;
189+ luks2_formatter
190+ . open_device ( path, None , NAME , passphrase)
191+ . unwrap ( ) ;
163192
164193 luks2_formatter. close_device ( NAME ) . unwrap ( ) ;
165194 }
@@ -173,19 +202,113 @@ mod tests {
173202 . as_file_mut ( )
174203 . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
175204 . unwrap ( ) ;
176- let path = bin_file. path ( ) . to_str ( ) . unwrap ( ) ;
205+ let path = bin_file. path ( ) ;
177206
178207 let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
179208 let luks2_formatter = Luks2Formatter { integrity : true } ;
180209 luks2_formatter
181- . encrypt_device ( path, passphrase. clone ( ) )
210+ . encrypt_device ( path, None , passphrase. clone ( ) )
182211 . unwrap ( ) ;
183212
184- luks2_formatter. open_device ( path, NAME , passphrase) . unwrap ( ) ;
213+ luks2_formatter
214+ . open_device ( path, None , NAME , passphrase)
215+ . unwrap ( ) ;
185216
186217 luks2_formatter. close_device ( NAME ) . unwrap ( ) ;
187218 }
188219
220+ #[ test]
221+ #[ serial]
222+ fn encrypt_open_device_no_integrity_with_header ( ) {
223+ let mut bin_file = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
224+ bin_file
225+ . as_file_mut ( )
226+ . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
227+ . unwrap ( ) ;
228+ let path = bin_file. path ( ) ;
229+ let header_path = prepare_luks_header_file ( None , path) . unwrap ( ) ;
230+ let _guard = RemoveHeaderOnDrop ( header_path. clone ( ) ) ;
231+
232+ let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
233+ let luks2_formatter = Luks2Formatter { integrity : false } ;
234+ luks2_formatter
235+ . encrypt_device ( path, Some ( & header_path) , passphrase. clone ( ) )
236+ . unwrap ( ) ;
237+
238+ luks2_formatter
239+ . open_device ( path, Some ( & header_path) , NAME , passphrase)
240+ . unwrap ( ) ;
241+
242+ luks2_formatter. close_device ( NAME ) . unwrap ( ) ;
243+ }
244+
245+ #[ test]
246+ #[ serial]
247+ fn encrypt_open_device_integrity_with_header ( ) {
248+ let mut bin_file = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
249+ bin_file
250+ . as_file_mut ( )
251+ . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
252+ . unwrap ( ) ;
253+ let path = bin_file. path ( ) ;
254+ let header_path = prepare_luks_header_file ( None , path) . unwrap ( ) ;
255+ let _guard = RemoveHeaderOnDrop ( header_path. clone ( ) ) ;
256+
257+ let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
258+ let luks2_formatter = Luks2Formatter { integrity : true } ;
259+ luks2_formatter
260+ . encrypt_device ( path, Some ( & header_path) , passphrase. clone ( ) )
261+ . unwrap ( ) ;
262+
263+ luks2_formatter
264+ . open_device ( path, Some ( & header_path) , NAME , passphrase)
265+ . unwrap ( ) ;
266+
267+ luks2_formatter. close_device ( NAME ) . unwrap ( ) ;
268+ }
269+
270+ #[ test]
271+ #[ serial]
272+ fn encrypt_with_existing_header_file ( ) {
273+ let mut bin_file = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
274+ bin_file
275+ . as_file_mut ( )
276+ . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
277+ . unwrap ( ) ;
278+ let path = bin_file. path ( ) ;
279+ let header_path = prepare_luks_header_file ( None , path) . unwrap ( ) ;
280+ let _guard = RemoveHeaderOnDrop ( header_path. clone ( ) ) ;
281+
282+ let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
283+ let luks2_formatter = Luks2Formatter { integrity : false } ;
284+ let result = luks2_formatter. encrypt_device ( path, Some ( & header_path) , passphrase) ;
285+ assert ! ( result. is_ok( ) ) ;
286+ }
287+
288+ #[ test]
289+ #[ serial]
290+ fn open_device_missing_header_file_fails ( ) {
291+ let mut bin_file = tempfile:: NamedTempFile :: new ( ) . unwrap ( ) ;
292+ bin_file
293+ . as_file_mut ( )
294+ . write_all ( & vec ! [ 0 ; 20 * 1024 * 1024 ] )
295+ . unwrap ( ) ;
296+ let path = bin_file. path ( ) ;
297+ let header_path = prepare_luks_header_file ( None , path) . unwrap ( ) ;
298+ let _guard = RemoveHeaderOnDrop ( header_path. clone ( ) ) ;
299+
300+ let passphrase = Zeroizing :: new ( TEST_PASSPHRASE . to_vec ( ) ) ;
301+ let luks2_formatter = Luks2Formatter { integrity : false } ;
302+ luks2_formatter
303+ . encrypt_device ( path, Some ( & header_path) , passphrase. clone ( ) )
304+ . unwrap ( ) ;
305+
306+ std:: fs:: remove_file ( & header_path) . unwrap ( ) ;
307+
308+ let result = luks2_formatter. open_device ( path, Some ( & header_path) , NAME , passphrase) ;
309+ assert ! ( result. is_err( ) ) ;
310+ }
311+
189312 /// This test can be used to clean useless devices under /dev/mapper/
190313 #[ ignore]
191314 #[ test]
0 commit comments