use crate::{Error, LockboxOptions, LockboxProtection, OwnerSigningKeyPair, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ZstdLevel(u8);
impl ZstdLevel {
pub fn new(level: u8) -> Result<Self> {
if (1..=22).contains(&level) {
Ok(Self(level))
} else {
Err(Error::InvalidInput(
"Zstd level must be between 1 and 22".into(),
))
}
}
pub const fn get(self) -> u8 {
self.0
}
}
impl Default for ZstdLevel {
fn default() -> Self {
Self(3)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Compression {
None,
Zstd {
level: ZstdLevel,
},
}
impl Default for Compression {
fn default() -> Self {
Self::Zstd {
level: ZstdLevel::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EncryptionMode {
None,
ChaCha20Poly1305,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SigningMode {
None,
Owner,
}
pub enum Encryption<'a> {
None,
Encrypted(LockboxProtection<'a>),
}
#[derive(Clone, Copy)]
pub enum Signing<'a> {
None,
Owner(&'a OwnerSigningKeyPair),
}
impl<'a> From<&'a OwnerSigningKeyPair> for Signing<'a> {
fn from(key: &'a OwnerSigningKeyPair) -> Self {
Self::Owner(key)
}
}
pub struct LockboxCreateOptions<'a> {
pub encryption: Encryption<'a>,
pub signing: Signing<'a>,
pub compression: Compression,
pub runtime: LockboxOptions,
}
impl<'a> LockboxCreateOptions<'a> {
pub fn new(encryption: Encryption<'a>, signing: Signing<'a>) -> Self {
Self {
encryption,
signing,
compression: Compression::default(),
runtime: LockboxOptions::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LockboxFormatOptions {
pub encryption: EncryptionMode,
pub signing: SigningMode,
pub compression: Compression,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub(crate) struct FormatMode(pub(crate) u16);
impl FormatMode {
pub(crate) fn new(options: LockboxFormatOptions) -> Self {
let bits = u16::from(options.encryption == EncryptionMode::None)
| (u16::from(options.signing == SigningMode::None) << 1)
| match options.compression {
Compression::None => 4,
Compression::Zstd { level } => u16::from(level.get()) << 3,
};
Self(bits)
}
pub(crate) fn parse(bits: u16) -> Result<Self> {
if bits != 0
&& (bits & !0xff != 0
|| if bits & 4 != 0 {
bits >> 3 != 0
} else {
!(1..=22).contains(&(bits >> 3))
})
{
return Err(Error::CorruptHeader);
}
Ok(Self(bits))
}
pub(crate) fn plaintext(self) -> bool {
self.0 & 1 != 0
}
pub(crate) fn signed(self) -> bool {
self.0 & 2 == 0
}
pub(crate) fn options(self) -> LockboxFormatOptions {
LockboxFormatOptions {
encryption: if self.plaintext() {
EncryptionMode::None
} else {
EncryptionMode::ChaCha20Poly1305
},
signing: if self.signed() {
SigningMode::Owner
} else {
SigningMode::None
},
compression: if self.0 & 4 != 0 {
Compression::None
} else {
Compression::Zstd {
level: ZstdLevel(if self.0 == 0 { 1 } else { (self.0 >> 3) as u8 }),
}
},
}
}
}