use std::{
os::raw::{c_char, c_int, c_void},
path::Path,
ptr,
};
use crate::{device::CryptDevice, err::LibcryptErr, format::EncryptionFormat, Bool};
use either::Either;
use uuid::Uuid;
pub struct CryptContext<'a> {
reference: &'a mut CryptDevice,
}
impl<'a> CryptContext<'a> {
pub(crate) fn new(reference: &'a mut CryptDevice) -> Self {
CryptContext { reference }
}
pub fn format<T>(
&mut self,
type_: EncryptionFormat,
cipher_and_mode: (&str, &str),
uuid: Option<Uuid>,
volume_key: Either<&[u8], usize>,
params: Option<&mut T>,
) -> Result<(), LibcryptErr> {
let uuid_ptr = uuid
.as_ref()
.map(|u| u.as_bytes().as_ptr())
.unwrap_or(ptr::null()) as *const c_char;
let (volume_key_ptr, volume_key_len) = match volume_key {
Either::Left(vk) => (to_byte_ptr!(vk), vk.len()),
Either::Right(len) => (ptr::null(), len),
};
let (cipher, cipher_mode) = cipher_and_mode;
let cipher_cstring = to_cstring!(cipher)?;
let cipher_mode_cstring = to_cstring!(cipher_mode)?;
errno!(unsafe {
libcryptsetup_rs_sys::crypt_format(
self.reference.as_ptr(),
type_.as_ptr(),
cipher_cstring.as_ptr(),
cipher_mode_cstring.as_ptr(),
uuid_ptr,
volume_key_ptr,
volume_key_len,
params
.map(|p| p as *mut _ as *mut c_void)
.unwrap_or(ptr::null_mut()),
)
})?;
Ok(())
}
pub fn convert<T>(
&mut self,
type_: EncryptionFormat,
params: &mut T,
) -> Result<(), LibcryptErr> {
errno!(unsafe {
libcryptsetup_rs_sys::crypt_convert(
self.reference.as_ptr(),
type_.as_ptr(),
params as *mut _ as *mut c_void,
)
})
}
pub fn set_uuid(&mut self, uuid: Option<Uuid>) -> Result<(), LibcryptErr> {
let uptr = match uuid {
Some(u) => u.as_bytes().as_ptr() as *const c_char,
None => std::ptr::null(),
};
errno!(unsafe { libcryptsetup_rs_sys::crypt_set_uuid(self.reference.as_ptr(), uptr) })
}
pub fn set_label(
&mut self,
label: Option<&str>,
subsystem_label: Option<&str>,
) -> Result<(), LibcryptErr> {
let (lcstring, slcstring) = match (label, subsystem_label) {
(Some(l), Some(sl)) => (Some(to_cstring!(l)?), Some(to_cstring!(sl)?)),
(Some(l), _) => (Some(to_cstring!(l)?), None),
(_, Some(sl)) => (None, Some(to_cstring!(sl)?)),
(_, _) => (None, None),
};
errno!(unsafe {
libcryptsetup_rs_sys::crypt_set_label(
self.reference.as_ptr(),
lcstring.map(|cs| cs.as_ptr()).unwrap_or(ptr::null()),
slcstring.map(|cs| cs.as_ptr()).unwrap_or(ptr::null()),
)
})
}
pub fn volume_key_keyring(&mut self, enable: Bool) -> Result<(), LibcryptErr> {
errno!(unsafe {
libcryptsetup_rs_sys::crypt_volume_key_keyring(self.reference.as_ptr(), enable as c_int)
})
}
pub fn load<T>(
&mut self,
type_: Option<EncryptionFormat>,
params: Option<&mut T>,
) -> Result<(), LibcryptErr> {
errno!(unsafe {
libcryptsetup_rs_sys::crypt_load(
self.reference.as_ptr(),
type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()),
params
.map(|p| p as *mut _ as *mut c_void)
.unwrap_or(ptr::null_mut()),
)
})?;
Ok(())
}
pub fn repair<T>(
&mut self,
type_: EncryptionFormat,
params: &mut T,
) -> Result<(), LibcryptErr> {
errno!(unsafe {
libcryptsetup_rs_sys::crypt_repair(
self.reference.as_ptr(),
type_.as_ptr(),
params as *mut _ as *mut c_void,
)
})
}
pub fn resize(&mut self, name: &str, new_size: u64) -> Result<(), LibcryptErr> {
let name_cstring = to_cstring!(name)?;
errno!(unsafe {
libcryptsetup_rs_sys::crypt_resize(
self.reference.as_ptr(),
name_cstring.as_ptr(),
new_size,
)
})
}
pub fn suspend(&mut self, name: &str) -> Result<(), LibcryptErr> {
let name_cstring = to_cstring!(name)?;
errno!(unsafe {
libcryptsetup_rs_sys::crypt_suspend(self.reference.as_ptr(), name_cstring.as_ptr())
})
}
pub fn resume_by_passphrase(
&mut self,
name: &str,
keyslot: c_int,
passphrase: &str,
) -> Result<c_int, LibcryptErr> {
let name_cstring = to_cstring!(name)?;
let passphrase_cstring = to_cstring!(passphrase)?;
errno_int_success!(unsafe {
libcryptsetup_rs_sys::crypt_resume_by_passphrase(
self.reference.as_ptr(),
name_cstring.as_ptr(),
keyslot,
passphrase_cstring.as_ptr(),
passphrase.len() as crate::size_t,
)
})
}
pub fn resume_by_keyfile_device_offset(
&mut self,
name: &str,
keyslot: c_int,
keyfile: &Path,
keyfile_size: crate::size_t,
keyfile_offset: u64,
) -> Result<c_int, LibcryptErr> {
let name_cstring = to_cstring!(name)?;
let keyfile_cstring = path_to_cstring!(keyfile)?;
errno_int_success!(unsafe {
libcryptsetup_rs_sys::crypt_resume_by_keyfile_device_offset(
self.reference.as_ptr(),
name_cstring.as_ptr(),
keyslot,
keyfile_cstring.as_ptr(),
keyfile_size,
keyfile_offset,
)
})
}
}