use crate::error::{FluxError, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CipherSuite {
Aes128Gcm,
Aes256Gcm,
}
impl Default for CipherSuite {
fn default() -> Self {
Self::Aes256Gcm
}
}
#[derive(Debug, Clone)]
pub enum KeyDerivation {
Pbkdf2 {
iterations: u32,
salt_len: usize,
},
#[allow(dead_code)]
Argon2 {
memory_cost: u32,
time_cost: u32,
parallelism: u32,
},
}
impl Default for KeyDerivation {
fn default() -> Self {
Self::Pbkdf2 {
iterations: 100_000,
salt_len: 32,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RsaKeySize {
Rsa2048,
Rsa3072,
Rsa4096,
}
impl Default for RsaKeySize {
fn default() -> Self {
Self::Rsa4096
}
}
impl From<RsaKeySize> for usize {
fn from(size: RsaKeySize) -> Self {
match size {
RsaKeySize::Rsa2048 => 2048,
RsaKeySize::Rsa3072 => 3072,
RsaKeySize::Rsa4096 => 4096,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Compression {
None,
#[allow(dead_code)]
Zlib,
#[allow(dead_code)]
Lz4,
}
impl Default for Compression {
fn default() -> Self {
Self::None
}
}
#[derive(Debug, Clone)]
pub struct Config {
pub cipher_suite: CipherSuite,
pub key_derivation: KeyDerivation,
pub rsa_key_size: RsaKeySize,
pub compression: Compression,
pub memory_limit_mb: usize,
pub hardware_acceleration: bool,
pub stream_chunk_size: usize,
pub secure_memory: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
cipher_suite: CipherSuite::default(),
key_derivation: KeyDerivation::default(),
rsa_key_size: RsaKeySize::default(),
compression: Compression::default(),
memory_limit_mb: 256,
hardware_acceleration: true,
stream_chunk_size: 64 * 1024, secure_memory: true,
}
}
}
#[derive(Debug, Default)]
pub struct ConfigBuilder {
config: Config,
}
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigBuilder::default()
}
pub fn key_length(&self) -> usize {
match self.cipher_suite {
CipherSuite::Aes128Gcm => 16,
CipherSuite::Aes256Gcm => 32,
}
}
pub fn nonce_length(&self) -> usize {
match self.cipher_suite {
CipherSuite::Aes128Gcm | CipherSuite::Aes256Gcm => 12,
}
}
pub fn tag_length(&self) -> usize {
match self.cipher_suite {
CipherSuite::Aes128Gcm | CipherSuite::Aes256Gcm => 16,
}
}
pub fn validate(&self) -> Result<()> {
if self.memory_limit_mb == 0 {
return Err(FluxError::config("Memory limit cannot be zero"));
}
if self.stream_chunk_size == 0 {
return Err(FluxError::config("Stream chunk size cannot be zero"));
}
if self.stream_chunk_size > self.memory_limit_mb * 1024 * 1024 {
return Err(FluxError::config(
"Stream chunk size cannot exceed memory limit",
));
}
match &self.key_derivation {
KeyDerivation::Pbkdf2 {
iterations,
salt_len,
} => {
if *iterations < 1000 {
return Err(FluxError::config(
"PBKDF2 iterations should be at least 1000",
));
}
if *salt_len < 16 {
return Err(FluxError::config("Salt length should be at least 16 bytes"));
}
}
KeyDerivation::Argon2 { .. } => {
}
}
Ok(())
}
}
impl ConfigBuilder {
pub fn cipher_suite(mut self, cipher_suite: CipherSuite) -> Self {
self.config.cipher_suite = cipher_suite;
self
}
pub fn key_derivation(mut self, key_derivation: KeyDerivation) -> Self {
self.config.key_derivation = key_derivation;
self
}
pub fn rsa_key_size(mut self, rsa_key_size: RsaKeySize) -> Self {
self.config.rsa_key_size = rsa_key_size;
self
}
pub fn compression(mut self, compression: Compression) -> Self {
self.config.compression = compression;
self
}
pub fn memory_limit_mb(mut self, memory_limit_mb: usize) -> Self {
self.config.memory_limit_mb = memory_limit_mb;
self
}
pub fn hardware_acceleration(mut self, hardware_acceleration: bool) -> Self {
self.config.hardware_acceleration = hardware_acceleration;
self
}
pub fn stream_chunk_size(mut self, stream_chunk_size: usize) -> Self {
self.config.stream_chunk_size = stream_chunk_size;
self
}
pub fn secure_memory(mut self, secure_memory: bool) -> Self {
self.config.secure_memory = secure_memory;
self
}
pub fn build(self) -> Result<Config> {
self.config.validate()?;
Ok(self.config)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert!(config.validate().is_ok());
assert_eq!(config.cipher_suite, CipherSuite::Aes256Gcm);
assert_eq!(config.rsa_key_size, RsaKeySize::Rsa4096);
assert_eq!(config.memory_limit_mb, 256);
}
#[test]
fn test_config_builder() {
let config = Config::builder()
.cipher_suite(CipherSuite::Aes128Gcm)
.memory_limit_mb(512)
.hardware_acceleration(false)
.build()
.unwrap();
assert_eq!(config.cipher_suite, CipherSuite::Aes128Gcm);
assert_eq!(config.memory_limit_mb, 512);
assert!(!config.hardware_acceleration);
}
#[test]
fn test_invalid_config() {
let result = Config::builder().memory_limit_mb(0).build();
assert!(result.is_err());
}
}