1use std::fmt;
5use std::fs::File;
6use std::path::{Path, PathBuf};
7use std::ptr;
8
9use either::Either;
10use either::Either::{Left, Right};
11use uuid;
12
13use blkid_rs::{LuksHeader, LuksVersionedHeader};
14use raw;
15pub use raw::{crypt_pbkdf_algo_type, crypt_status_info, crypt_token_info};
16
17pub use crate::device::{
18 Error, Keyslot, Luks2TokenHandler, Luks2TokenHandlerBox, Luks2TokenHandlerRaw, Luks2TokenId, Result,
19};
20use crate::device::{Luks2FormatPbkdf, RawDevice};
21pub use crate::global::enable_debug;
22use crate::luks1::Luks1Params;
23use crate::luks2::Luks2Params;
24pub use crate::luks2_meta::{Luks2Metadata, Luks2Token};
25
26pub type Luks1CryptDeviceHandle = CryptDeviceHandle<Luks1Params>;
27pub type Luks2CryptDeviceHandle = CryptDeviceHandle<Luks2Params>;
28
29pub fn open<P: AsRef<Path>>(path: P) -> Result<CryptDeviceOpenBuilder> {
41 let cd = crate::device::init(path.as_ref())?;
42 Ok(CryptDeviceOpenBuilder {
43 path: path.as_ref().to_owned(),
44 cd,
45 })
46}
47
48pub fn status(name: &str) -> crypt_status_info {
50 crate::device::status_only(name)
51}
52
53pub fn format<P: AsRef<Path>>(path: P) -> Result<CryptDeviceFormatBuilder> {
90 let cd = crate::device::init(path.as_ref())?;
91 Ok(CryptDeviceFormatBuilder {
92 path: path.as_ref().to_owned(),
93 cd,
94 })
95}
96
97pub fn luks_version<P: AsRef<Path>>(path: P) -> Result<u16> {
99 let device_file = File::open(path.as_ref())?;
100 let header = LuksHeader::read(device_file)?;
101 Ok(header.version())
102}
103
104pub fn luks_uuid<P: AsRef<Path>>(path: P) -> Result<uuid::Uuid> {
106 let device_file = File::open(path.as_ref())?;
107 let uuid = LuksHeader::read(device_file)?.uuid()?;
108 Ok(uuid)
109}
110
111#[deprecated]
115pub fn luks1_uuid<P: AsRef<Path>>(path: P) -> Result<uuid::Uuid> {
116 luks_uuid(path)
117}
118
119pub struct CryptDeviceOpenBuilder {
121 path: PathBuf,
122 cd: RawDevice,
123}
124
125impl CryptDeviceOpenBuilder {
126 pub fn luks1(self: CryptDeviceOpenBuilder) -> Result<CryptDeviceHandle<Luks1Params>> {
128 let _ = crate::device::load(&self.cd, raw::crypt_device_type::LUKS1);
129 let params = Luks1Params::from_path(&self.path)?;
130 Ok(CryptDeviceHandle {
131 cd: self.cd,
132 path: self.path,
133 params,
134 })
135 }
136
137 pub fn luks2(self: CryptDeviceOpenBuilder) -> Result<CryptDeviceHandle<Luks2Params>> {
139 let _ = crate::device::load(&self.cd, raw::crypt_device_type::LUKS2);
140 let params = Luks2Params::from_path(&self.path)?;
141 Ok(CryptDeviceHandle {
142 cd: self.cd,
143 path: self.path,
144 params,
145 })
146 }
147
148 pub fn luks(
149 self: CryptDeviceOpenBuilder,
150 ) -> Result<Either<CryptDeviceHandle<Luks1Params>, CryptDeviceHandle<Luks2Params>>> {
151 match luks_version(&self.path)? {
152 1 => self.luks1().map(|d| Left(d)),
153 2 => self.luks2().map(|d| Right(d)),
154 _ => Err(Error::InvalidLuksVersion),
155 }
156 }
157}
158
159pub struct CryptDeviceFormatBuilder {
161 path: PathBuf,
162 cd: RawDevice,
163}
164
165#[derive(Default)]
166struct Luks2FormatBuilderParams<'a> {
167 label: Option<&'a str>,
168 subsystem: Option<&'a str>,
169 data_device: Option<&'a Path>,
170 pbkdf: Option<Luks2FormatPbkdf<'a>>,
171}
172
173pub struct CryptDeviceLuks2FormatBuilder<'a> {
174 path: PathBuf,
175 cd: RawDevice,
176 cipher: &'a str,
178 cipher_mode: &'a str,
179 mk_bits: usize,
180 maybe_uuid: Option<&'a uuid::Uuid>,
181 data_alignment: usize,
183 sector_size: u32,
184 other: Luks2FormatBuilderParams<'a>,
185}
186
187impl<'a> CryptDeviceLuks2FormatBuilder<'a> {
188 pub fn label(mut self, label: &'a str) -> Self {
190 self.other.label = Some(label);
191 self
192 }
193
194 pub fn subsystem(mut self, subsystem: &'a str) -> Self {
196 self.other.subsystem = Some(subsystem);
197 self
198 }
199
200 pub fn data_device(mut self, p: &'a Path) -> Self {
202 self.other.data_device = Some(p);
203 self
204 }
205
206 pub fn pbkdf2(mut self, hash: &'a str, time_ms: u32, iterations: u32) -> Self {
208 self.other.pbkdf = Some(Luks2FormatPbkdf {
209 type_: crypt_pbkdf_algo_type::pbkdf2,
210 hash,
211 time_ms,
212 iterations,
213 max_memory_kb: 0,
214 parallel_threads: 0,
215 flags: 0,
216 });
217 self
218 }
219
220 pub fn argon2i(
222 mut self,
223 hash: &'a str,
224 time_ms: u32,
225 iterations: u32,
226 max_memory_kb: u32,
227 parallel_threads: u32,
228 ) -> Self {
229 self.other.pbkdf = Some(Luks2FormatPbkdf {
230 type_: crypt_pbkdf_algo_type::argon2i,
231 hash,
232 time_ms,
233 iterations,
234 max_memory_kb,
235 parallel_threads,
236 flags: 0,
237 });
238 self
239 }
240
241 pub fn argon2id(
243 mut self,
244 hash: &'a str,
245 time_ms: u32,
246 iterations: u32,
247 max_memory_kb: u32,
248 parallel_threads: u32,
249 ) -> Self {
250 self.other.pbkdf = Some(Luks2FormatPbkdf {
251 type_: crypt_pbkdf_algo_type::argon2id,
252 hash,
253 time_ms,
254 iterations,
255 max_memory_kb,
256 parallel_threads,
257 flags: 0,
258 });
259 self
260 }
261
262 pub fn start(mut self) -> Result<CryptDeviceHandle<Luks2Params>> {
264 let _ = crate::device::luks2_format(
265 &mut self.cd,
266 self.cipher,
267 self.cipher_mode,
268 self.mk_bits,
269 self.data_alignment,
270 self.sector_size,
271 self.other.label,
272 self.other.subsystem,
273 self.other.data_device,
274 self.maybe_uuid,
275 self.other.pbkdf.as_ref(),
276 None,
277 )?;
278 let params = Luks2Params::from_path(&self.path)?;
279 Ok(CryptDeviceHandle {
280 cd: self.cd,
281 path: self.path,
282 params,
283 })
284 }
285}
286
287impl CryptDeviceFormatBuilder {
288 pub fn iteration_time(mut self, iteration_time_ms: u64) -> Self {
290 #[allow(deprecated)]
291 crate::device::set_iteration_time(&mut self.cd, iteration_time_ms);
292 self
293 }
294
295 pub fn rng_type(mut self, rng_type: raw::crypt_rng_type) -> Self {
297 crate::device::set_rng_type(&mut self.cd, rng_type);
298 self
299 }
300
301 pub fn luks1(
303 mut self: CryptDeviceFormatBuilder,
304 cipher: &str,
305 cipher_mode: &str,
306 hash: &str,
307 mk_bits: usize,
308 maybe_uuid: Option<&uuid::Uuid>,
309 ) -> Result<CryptDeviceHandle<Luks1Params>> {
310 let _ = crate::device::luks1_format(&mut self.cd, cipher, cipher_mode, hash, mk_bits, maybe_uuid)?;
311 let params = Luks1Params::from_path(&self.path)?;
312 Ok(CryptDeviceHandle {
313 cd: self.cd,
314 path: self.path,
315 params,
316 })
317 }
318
319 pub fn luks2<'a>(
321 self: CryptDeviceFormatBuilder,
322 cipher: &'a str,
323 cipher_mode: &'a str,
324 mk_bits: usize,
325 maybe_uuid: Option<&'a uuid::Uuid>,
326 maybe_data_alignment: Option<u32>,
327 maybe_sector_size: Option<u32>,
328 ) -> CryptDeviceLuks2FormatBuilder<'a> {
329 CryptDeviceLuks2FormatBuilder {
330 path: self.path,
331 cd: self.cd,
332 cipher,
333 cipher_mode,
334 mk_bits,
335 maybe_uuid,
336 data_alignment: maybe_data_alignment.unwrap_or(0) as usize,
337 sector_size: maybe_sector_size.unwrap_or(512),
338 other: Default::default(),
339 }
340 }
341}
342
343pub trait CryptDevice {
345 fn path(&self) -> &Path;
347
348 fn cipher(&self) -> &str;
350
351 fn cipher_mode(&self) -> &str;
353
354 fn device_name(&self) -> &str;
356
357 fn rng_type(&self) -> raw::crypt_rng_type;
359
360 fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type);
362
363 fn set_iteration_time(&mut self, iteration_time_ms: u64);
365
366 fn volume_key_size(&self) -> u8;
368}
369
370pub trait CryptDeviceType {
372 fn device_type(&self) -> raw::crypt_device_type;
374}
375
376pub trait LuksCryptDevice: CryptDevice + CryptDeviceType {
379 fn activate(&mut self, name: &str, key: &[u8]) -> Result<Keyslot>;
381
382 fn deactivate(self, name: &str) -> Result<()>;
384
385 fn destroy_keyslot(&mut self, slot: Keyslot) -> Result<()>;
387
388 fn keyslot_status(&self, keyslot: Keyslot) -> raw::crypt_keyslot_info;
390
391 fn dump(&self);
393
394 fn uuid(&self) -> uuid::Uuid;
396
397 fn add_keyslot(
399 &mut self,
400 key: &[u8],
401 maybe_prev_key: Option<&[u8]>,
402 maybe_keyslot: Option<Keyslot>,
403 ) -> Result<Keyslot>;
404
405 fn update_keyslot(&mut self, key: &[u8], prev_key: &[u8], maybe_keyslot: Option<Keyslot>) -> Result<Keyslot>;
407}
408
409pub trait Luks1CryptDevice: LuksCryptDevice {
411 fn hash_spec(&self) -> &str;
413
414 fn mk_bits(&self) -> u32;
416
417 fn mk_digest(&self) -> &[u8; 20];
419
420 fn mk_iterations(&self) -> u32;
422
423 fn mk_salt(&self) -> &[u8; 32];
425
426 fn payload_offset(&self) -> u32;
428}
429
430pub trait Luks2CryptDevice: LuksCryptDevice {
432 fn register_new_token_handler<Handler: Luks2TokenHandlerRaw>() -> Result<Luks2TokenHandlerBox<Handler>>;
434
435 fn register_token_handler<Handler: Luks2TokenHandlerRaw>(handler: &Luks2TokenHandlerBox<Handler>) -> Result<()>;
437
438 fn token_status(&mut self, token_id: Luks2TokenId) -> (crypt_token_info, Option<String>);
440
441 fn get_token(&mut self, token_id: Luks2TokenId) -> Result<Luks2Token>;
443
444 fn add_token_with_id(&mut self, token: &Luks2Token, token_id: Luks2TokenId) -> Result<()>;
446
447 fn add_token(&mut self, token: &Luks2Token) -> Result<Luks2TokenId>;
449
450 fn remove_token(&mut self, token_id: Luks2TokenId) -> Result<()>;
452
453 fn assign_token_to_keyslot(&mut self, token_id: Luks2TokenId, keyslot_opt: Option<Keyslot>) -> Result<()>;
455
456 fn unassign_token_keyslot(&mut self, token_id: Luks2TokenId, keyslot_opt: Option<Keyslot>) -> Result<()>;
458
459 fn token_keyslot_is_assigned(&mut self, token_id: Luks2TokenId, keyslot: Keyslot) -> Result<bool>;
461
462 fn activate_with_token(&mut self, name: &str, token_id: Luks2TokenId) -> Result<Keyslot>;
464
465 fn check_activation_with_token(&mut self, token_id: Luks2TokenId) -> Result<Keyslot>;
467
468 fn set_pbkdf_params(
470 &mut self,
471 type_: crypt_pbkdf_algo_type,
472 hash: &str,
473 time_ms: u32,
474 iterations: u32,
475 max_memory_kb: u32,
476 parallel_threads: u32,
477 ) -> Result<()>;
478}
479
480#[derive(PartialEq)]
482pub struct CryptDeviceHandle<P: fmt::Debug> {
483 pub(crate) cd: RawDevice,
485
486 pub(crate) path: PathBuf,
488
489 pub(crate) params: P,
491}
492
493impl<P: fmt::Debug> fmt::Debug for CryptDeviceHandle<P> {
494 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
495 write!(
496 f,
497 "CryptDeviceHandle(path={}, raw={:p}, params={:?})",
498 self.path.display(),
499 self.cd,
500 self.params
501 )
502 }
503}
504
505impl<P: fmt::Debug> Drop for CryptDeviceHandle<P> {
506 fn drop(&mut self) {
507 crate::device::free(&mut self.cd);
508 self.cd = ptr::null_mut();
509 }
510}
511
512impl<P: fmt::Debug> CryptDevice for CryptDeviceHandle<P> {
513 fn path(&self) -> &Path {
514 self.path.as_ref()
515 }
516
517 fn cipher(&self) -> &str {
518 crate::device::cipher(&self.cd).expect("Initialised device should have cipher")
519 }
520
521 fn cipher_mode(&self) -> &str {
522 crate::device::cipher_mode(&self.cd).expect("Initialised device should have cipher mode")
523 }
524
525 fn device_name(&self) -> &str {
526 crate::device::device_name(&self.cd).expect("Initialised device should have an underlying path")
527 }
528
529 fn rng_type(&self) -> raw::crypt_rng_type {
530 crate::device::rng_type(&self.cd)
531 }
532
533 fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type) {
534 crate::device::set_rng_type(&mut self.cd, rng_type)
535 }
536
537 fn set_iteration_time(&mut self, iteration_time_ms: u64) {
538 #[allow(deprecated)]
539 crate::device::set_iteration_time(&mut self.cd, iteration_time_ms)
540 }
541
542 fn volume_key_size(&self) -> u8 {
543 crate::device::volume_key_size(&self.cd)
544 }
545}