use std::fmt;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::ptr;
use either::Either;
use either::Either::{Left, Right};
use uuid;
use blkid_rs::{LuksHeader, LuksVersionedHeader};
use raw;
pub use raw::{crypt_pbkdf_algo_type, crypt_token_info};
pub use crate::device::{
Error, Keyslot, Luks2TokenHandler, Luks2TokenHandlerBox, Luks2TokenHandlerRaw, Luks2TokenId, Result,
};
use crate::device::{Luks2FormatPbkdf, RawDevice};
pub use crate::global::enable_debug;
use crate::luks1::Luks1Params;
use crate::luks2::Luks2Params;
pub use crate::luks2_meta::{Luks2Metadata, Luks2Token};
pub type Luks1CryptDeviceHandle = CryptDeviceHandle<Luks1Params>;
pub type Luks2CryptDeviceHandle = CryptDeviceHandle<Luks2Params>;
pub fn open<P: AsRef<Path>>(path: P) -> Result<CryptDeviceOpenBuilder> {
let cd = crate::device::init(path.as_ref())?;
Ok(CryptDeviceOpenBuilder {
path: path.as_ref().to_owned(),
cd,
})
}
pub fn format<P: AsRef<Path>>(path: P) -> Result<CryptDeviceFormatBuilder> {
let cd = crate::device::init(path.as_ref())?;
Ok(CryptDeviceFormatBuilder {
path: path.as_ref().to_owned(),
cd,
})
}
pub fn luks_version<P: AsRef<Path>>(path: P) -> Result<u16> {
let device_file = File::open(path.as_ref())?;
let header = LuksHeader::read(device_file)?;
Ok(header.version())
}
pub fn luks_uuid<P: AsRef<Path>>(path: P) -> Result<uuid::Uuid> {
let device_file = File::open(path.as_ref())?;
let uuid = LuksHeader::read(device_file)?.uuid()?;
Ok(uuid)
}
#[deprecated]
pub fn luks1_uuid<P: AsRef<Path>>(path: P) -> Result<uuid::Uuid> {
luks_uuid(path)
}
pub struct CryptDeviceOpenBuilder {
path: PathBuf,
cd: RawDevice,
}
impl CryptDeviceOpenBuilder {
pub fn luks1(self: CryptDeviceOpenBuilder) -> Result<CryptDeviceHandle<Luks1Params>> {
let _ = crate::device::load(&self.cd, raw::crypt_device_type::LUKS1);
let params = Luks1Params::from_path(&self.path)?;
Ok(CryptDeviceHandle {
cd: self.cd,
path: self.path,
params,
})
}
pub fn luks2(self: CryptDeviceOpenBuilder) -> Result<CryptDeviceHandle<Luks2Params>> {
let _ = crate::device::load(&self.cd, raw::crypt_device_type::LUKS2);
let params = Luks2Params::from_path(&self.path)?;
Ok(CryptDeviceHandle {
cd: self.cd,
path: self.path,
params,
})
}
pub fn luks(
self: CryptDeviceOpenBuilder,
) -> Result<Either<CryptDeviceHandle<Luks1Params>, CryptDeviceHandle<Luks2Params>>> {
match luks_version(&self.path)? {
1 => self.luks1().map(|d| Left(d)),
2 => self.luks2().map(|d| Right(d)),
_ => Err(Error::InvalidLuksVersion),
}
}
}
pub struct CryptDeviceFormatBuilder {
path: PathBuf,
cd: RawDevice,
}
#[derive(Default)]
struct Luks2FormatBuilderParams<'a> {
label: Option<&'a str>,
subsystem: Option<&'a str>,
data_device: Option<&'a Path>,
pbkdf: Option<Luks2FormatPbkdf<'a>>,
}
pub struct CryptDeviceLuks2FormatBuilder<'a> {
path: PathBuf,
cd: RawDevice,
cipher: &'a str,
cipher_mode: &'a str,
mk_bits: usize,
maybe_uuid: Option<&'a uuid::Uuid>,
data_alignment: usize,
sector_size: u32,
other: Luks2FormatBuilderParams<'a>,
}
impl<'a> CryptDeviceLuks2FormatBuilder<'a> {
pub fn label(mut self, label: &'a str) -> Self {
self.other.label = Some(label);
self
}
pub fn subsystem(mut self, subsystem: &'a str) -> Self {
self.other.subsystem = Some(subsystem);
self
}
pub fn data_device(mut self, p: &'a Path) -> Self {
self.other.data_device = Some(p);
self
}
pub fn pbkdf2(mut self, hash: &'a str, time_ms: u32, iterations: u32) -> Self {
self.other.pbkdf = Some(Luks2FormatPbkdf {
type_: crypt_pbkdf_algo_type::pbkdf2,
hash,
time_ms,
iterations,
max_memory_kb: 0,
parallel_threads: 0,
flags: 0,
});
self
}
pub fn argon2i(
mut self,
hash: &'a str,
time_ms: u32,
iterations: u32,
max_memory_kb: u32,
parallel_threads: u32,
) -> Self {
self.other.pbkdf = Some(Luks2FormatPbkdf {
type_: crypt_pbkdf_algo_type::argon2i,
hash,
time_ms,
iterations,
max_memory_kb,
parallel_threads,
flags: 0,
});
self
}
pub fn argon2id(
mut self,
hash: &'a str,
time_ms: u32,
iterations: u32,
max_memory_kb: u32,
parallel_threads: u32,
) -> Self {
self.other.pbkdf = Some(Luks2FormatPbkdf {
type_: crypt_pbkdf_algo_type::argon2id,
hash,
time_ms,
iterations,
max_memory_kb,
parallel_threads,
flags: 0,
});
self
}
pub fn start(mut self) -> Result<CryptDeviceHandle<Luks2Params>> {
let _ = crate::device::luks2_format(
&mut self.cd,
self.cipher,
self.cipher_mode,
self.mk_bits,
self.data_alignment,
self.sector_size,
self.other.label,
self.other.subsystem,
self.other.data_device,
self.maybe_uuid,
self.other.pbkdf.as_ref(),
None,
)?;
let params = Luks2Params::from_path(&self.path)?;
Ok(CryptDeviceHandle {
cd: self.cd,
path: self.path,
params,
})
}
}
impl CryptDeviceFormatBuilder {
pub fn iteration_time(mut self, iteration_time_ms: u64) -> Self {
#[allow(deprecated)]
crate::device::set_iteration_time(&mut self.cd, iteration_time_ms);
self
}
pub fn rng_type(mut self, rng_type: raw::crypt_rng_type) -> Self {
crate::device::set_rng_type(&mut self.cd, rng_type);
self
}
pub fn luks1(
mut self: CryptDeviceFormatBuilder,
cipher: &str,
cipher_mode: &str,
hash: &str,
mk_bits: usize,
maybe_uuid: Option<&uuid::Uuid>,
) -> Result<CryptDeviceHandle<Luks1Params>> {
let _ = crate::device::luks1_format(&mut self.cd, cipher, cipher_mode, hash, mk_bits, maybe_uuid)?;
let params = Luks1Params::from_path(&self.path)?;
Ok(CryptDeviceHandle {
cd: self.cd,
path: self.path,
params,
})
}
pub fn luks2<'a>(
self: CryptDeviceFormatBuilder,
cipher: &'a str,
cipher_mode: &'a str,
mk_bits: usize,
maybe_uuid: Option<&'a uuid::Uuid>,
maybe_data_alignment: Option<u32>,
maybe_sector_size: Option<u32>,
) -> CryptDeviceLuks2FormatBuilder<'a> {
CryptDeviceLuks2FormatBuilder {
path: self.path,
cd: self.cd,
cipher,
cipher_mode,
mk_bits,
maybe_uuid,
data_alignment: maybe_data_alignment.unwrap_or(0) as usize,
sector_size: maybe_sector_size.unwrap_or(512),
other: Default::default(),
}
}
}
pub trait CryptDevice {
fn path(&self) -> &Path;
fn cipher(&self) -> &str;
fn cipher_mode(&self) -> &str;
fn device_name(&self) -> &str;
fn rng_type(&self) -> raw::crypt_rng_type;
fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type);
fn set_iteration_time(&mut self, iteration_time_ms: u64);
fn volume_key_size(&self) -> u8;
}
pub trait CryptDeviceType {
fn device_type(&self) -> raw::crypt_device_type;
}
pub trait LuksCryptDevice: CryptDevice + CryptDeviceType {
fn activate(&mut self, name: &str, key: &[u8]) -> Result<Keyslot>;
fn deactivate(self, name: &str) -> Result<()>;
fn destroy_keyslot(&mut self, slot: Keyslot) -> Result<()>;
fn keyslot_status(&self, keyslot: Keyslot) -> raw::crypt_keyslot_info;
fn dump(&self);
fn uuid(&self) -> uuid::Uuid;
fn add_keyslot(
&mut self,
key: &[u8],
maybe_prev_key: Option<&[u8]>,
maybe_keyslot: Option<Keyslot>,
) -> Result<Keyslot>;
fn update_keyslot(&mut self, key: &[u8], prev_key: &[u8], maybe_keyslot: Option<Keyslot>) -> Result<Keyslot>;
}
pub trait Luks1CryptDevice: LuksCryptDevice {
fn hash_spec(&self) -> &str;
fn mk_bits(&self) -> u32;
fn mk_digest(&self) -> &[u8; 20];
fn mk_iterations(&self) -> u32;
fn mk_salt(&self) -> &[u8; 32];
fn payload_offset(&self) -> u32;
}
pub trait Luks2CryptDevice: LuksCryptDevice {
fn register_new_token_handler<Handler: Luks2TokenHandlerRaw>() -> Result<Luks2TokenHandlerBox<Handler>>;
fn register_token_handler<Handler: Luks2TokenHandlerRaw>(handler: &Luks2TokenHandlerBox<Handler>) -> Result<()>;
fn token_status(&mut self, token_id: Luks2TokenId) -> (crypt_token_info, Option<String>);
fn get_token(&mut self, token_id: Luks2TokenId) -> Result<Luks2Token>;
fn add_token_with_id(&mut self, token: &Luks2Token, token_id: Luks2TokenId) -> Result<()>;
fn add_token(&mut self, token: &Luks2Token) -> Result<Luks2TokenId>;
fn remove_token(&mut self, token_id: Luks2TokenId) -> Result<()>;
fn assign_token_to_keyslot(&mut self, token_id: Luks2TokenId, keyslot_opt: Option<Keyslot>) -> Result<()>;
fn unassign_token_keyslot(&mut self, token_id: Luks2TokenId, keyslot_opt: Option<Keyslot>) -> Result<()>;
fn token_keyslot_is_assigned(&mut self, token_id: Luks2TokenId, keyslot: Keyslot) -> Result<bool>;
fn activate_with_token(&mut self, name: &str, token_id: Luks2TokenId) -> Result<Keyslot>;
fn check_activation_with_token(&mut self, token_id: Luks2TokenId) -> Result<Keyslot>;
}
#[derive(PartialEq)]
pub struct CryptDeviceHandle<P: fmt::Debug> {
pub(crate) cd: RawDevice,
pub(crate) path: PathBuf,
pub(crate) params: P,
}
impl<P: fmt::Debug> fmt::Debug for CryptDeviceHandle<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CryptDeviceHandle(path={}, raw={:p}, params={:?})",
self.path.display(),
self.cd,
self.params
)
}
}
impl<P: fmt::Debug> Drop for CryptDeviceHandle<P> {
fn drop(&mut self) {
crate::device::free(&mut self.cd);
self.cd = ptr::null_mut();
}
}
impl<P: fmt::Debug> CryptDevice for CryptDeviceHandle<P> {
fn path(&self) -> &Path {
self.path.as_ref()
}
fn cipher(&self) -> &str {
crate::device::cipher(&self.cd).expect("Initialised device should have cipher")
}
fn cipher_mode(&self) -> &str {
crate::device::cipher_mode(&self.cd).expect("Initialised device should have cipher mode")
}
fn device_name(&self) -> &str {
crate::device::device_name(&self.cd).expect("Initialised device should have an underlying path")
}
fn rng_type(&self) -> raw::crypt_rng_type {
crate::device::rng_type(&self.cd)
}
fn set_rng_type(&mut self, rng_type: raw::crypt_rng_type) {
crate::device::set_rng_type(&mut self.cd, rng_type)
}
fn set_iteration_time(&mut self, iteration_time_ms: u64) {
#[allow(deprecated)]
crate::device::set_iteration_time(&mut self.cd, iteration_time_ms)
}
fn volume_key_size(&self) -> u8 {
crate::device::volume_key_size(&self.cd)
}
}