use crate::cipher::provider::SymmetricCipher;
use crate::error::CryptoError;
use crate::i18n::translate_with_args;
use crate::side_channel::{
protect_critical_operation, RotatingSboxMasking, SideChannelConfig, SideChannelContext,
};
use crate::types::Algorithm;
use log::warn;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
pub struct BaseCipherProvider {
pub side_channel_context: Option<Arc<Mutex<SideChannelContext>>>,
pub rotating_sbox: Option<Arc<Mutex<RotatingSboxMasking>>>,
}
impl BaseCipherProvider {
pub fn new() -> Result<Self, CryptoError> {
let side_channel_context = Arc::new(Mutex::new(SideChannelContext::new(
SideChannelConfig::default(),
)));
let rotating_sbox = RotatingSboxMasking::new(4)
.map_err(|e| {
CryptoError::SideChannelError(format!(
"Failed to initialize side-channel protection (RotatingSboxMasking): {}",
e
))
})
.map(|sbox| Some(Arc::new(Mutex::new(sbox))))?;
warn!(
"{}",
translate_with_args("log.side_channel_init_masking", &[("mask_size", "4")])
);
Ok(Self {
side_channel_context: Some(side_channel_context),
rotating_sbox,
})
}
pub fn with_side_channel_config(config: SideChannelConfig) -> Result<Self, CryptoError> {
let rotating_sbox = if config.power_analysis_protection {
let sbox = RotatingSboxMasking::new(4).map_err(|e| {
CryptoError::SideChannelError(format!(
"Failed to initialize power analysis protection: {}",
e
))
})?;
warn!(
"{}",
translate_with_args("log.power_analysis_enabled", &[("mask_size", "4")])
);
Some(Arc::new(Mutex::new(sbox)))
} else {
warn!(
"{}",
translate_with_args("log.power_analysis_disabled", &[])
);
None
};
Ok(Self {
side_channel_context: Some(Arc::new(Mutex::new(SideChannelContext::new(config)))),
rotating_sbox,
})
}
pub fn protect_operation<F, R>(&self, operation: F) -> crate::error::Result<R>
where
F: FnOnce() -> crate::error::Result<R>,
{
if let Some(ref ctx) = self.side_channel_context {
let mut context_guard = ctx.lock().unwrap();
protect_critical_operation(&mut context_guard, operation)
} else {
operation()
}
}
#[allow(dead_code)]
pub fn side_channel_context(&self) -> &Option<Arc<Mutex<SideChannelContext>>> {
&self.side_channel_context
}
#[allow(dead_code)]
pub fn rotating_sbox(&self) -> &Option<Arc<Mutex<RotatingSboxMasking>>> {
&self.rotating_sbox
}
#[allow(dead_code)]
pub fn get_side_channel_stats(&self) -> Option<crate::side_channel::SideChannelStats> {
self.side_channel_context
.as_ref()
.and_then(|ctx| ctx.lock().ok().map(|guard| guard.get_stats()))
}
#[allow(dead_code)]
pub fn is_side_channel_protected(&self) -> bool {
self.side_channel_context.is_some() && self.rotating_sbox.is_some()
}
#[allow(dead_code)]
pub fn expand_key_protected(&self, key_bytes: &[u8]) -> crate::error::Result<Vec<u8>> {
if key_bytes.is_empty() {
return Err(crate::error::CryptoError::InvalidParameter(
"Key bytes cannot be empty".to_string(),
));
}
if key_bytes.len() < 16 || key_bytes.len() > 64 {
return Err(crate::error::CryptoError::InvalidKeySize {
expected: 32,
actual: key_bytes.len(),
});
}
if let Some(ref sbox_masking) = self.rotating_sbox {
let mut expanded_key = Vec::with_capacity(240);
expanded_key.extend_from_slice(key_bytes);
for i in 0..(expanded_key.len() / 4) {
if i > 7 && i % 4 == 0 {
let byte_idx = i * 4;
for j in 0..4 {
if byte_idx + j < expanded_key.len() {
let input = expanded_key[byte_idx + j];
let mut sbox = sbox_masking.lock().map_err(|_| {
crate::error::CryptoError::SideChannelError(
"S-box lock poisoned".into(),
)
})?;
expanded_key[byte_idx + j] = sbox.lookup(input);
}
}
}
}
Ok(expanded_key)
} else {
Ok(key_bytes.to_vec())
}
}
}
impl Default for BaseCipherProvider {
fn default() -> Self {
Self::new().unwrap_or_else(|e| {
log::error!(
"{}",
translate_with_args(
"metrics.create_provider_failed",
&[
("provider", "BaseCipherProvider"),
("error", &e.to_string())
]
)
);
panic!(
"{}",
translate_with_args(
"metrics.init_security_component_failed",
&[("error", &e.to_string())]
)
)
})
}
}
#[allow(dead_code)]
pub trait CipherProvider: SymmetricCipher + Send + Sync {
fn base_provider(&self) -> &BaseCipherProvider;
fn algorithm_type(&self) -> Algorithm;
}
#[macro_export]
macro_rules! impl_cipher_provider {
($provider:ty, $algorithm:expr) => {
impl $crate::cipher::base_provider::CipherProvider for $provider {
fn base_provider(&self) -> &$crate::cipher::base_provider::BaseCipherProvider {
&self.base
}
fn algorithm_type(&self) -> $crate::types::Algorithm {
$algorithm
}
}
};
}