#[cfg(feature = "alloc")]
use alloc::vec;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SideChannelProtection {
pub timing_protection: bool,
pub power_analysis_protection: bool,
pub cache_attack_protection: bool,
pub fault_injection_protection: bool,
}
impl Default for SideChannelProtection {
fn default() -> Self {
Self {
timing_protection: true,
power_analysis_protection: true,
cache_attack_protection: true,
fault_injection_protection: true,
}
}
}
impl SideChannelProtection {
pub fn new() -> Self {
Self::default()
}
pub fn strict() -> Self {
Self {
timing_protection: true,
power_analysis_protection: true,
cache_attack_protection: true,
fault_injection_protection: true,
}
}
pub fn permissive() -> Self {
Self {
timing_protection: false,
power_analysis_protection: false,
cache_attack_protection: false,
fault_injection_protection: false,
}
}
pub fn secure_key_compare(&self, a: &[u8], b: &[u8]) -> bool {
if !self.timing_protection {
return a == b;
}
crate::security::constant_time::constant_time_eq(a, b)
}
#[cfg(feature = "alloc")]
pub fn secure_key_select(&self, choice: u8, a: &[u8], b: &[u8]) -> Vec<u8> {
if !self.timing_protection {
return if choice == 1 { a.to_vec() } else { b.to_vec() };
}
let mut result = vec![0u8; a.len()];
for (i, (&a_byte, &b_byte)) in a.iter().zip(b.iter()).enumerate() {
result[i] =
crate::security::constant_time::constant_time_select(choice == 1, a_byte, b_byte);
}
result
}
#[cfg(not(feature = "alloc"))]
pub fn secure_key_select(&self, choice: u8, a: &[u8], b: &[u8], result: &mut [u8]) {
if !self.timing_protection {
if choice == 1 {
result.copy_from_slice(a);
} else {
result.copy_from_slice(b);
}
return;
}
for (i, (&a_byte, &b_byte)) in a.iter().zip(b.iter()).enumerate() {
result[i] =
crate::security::constant_time::constant_time_select(choice == 1, a_byte, b_byte);
}
}
pub fn secure_memory_access<'a, T>(&self, data: &'a [T], index: usize) -> Option<&'a T> {
if !self.cache_attack_protection {
return data.get(index);
}
let _ = data.len();
for (i, _) in data.iter().enumerate() {
if i == index {
return Some(&data[i]);
}
}
None
}
pub fn secure_memory_access_mut<'a, T>(
&self,
data: &'a mut [T],
index: usize,
) -> Option<&'a mut T> {
if !self.cache_attack_protection {
return data.get_mut(index);
}
let _ = data.len();
for (i, _) in data.iter().enumerate() {
if i == index {
return Some(&mut data[i]);
}
}
None
}
pub fn secure_conditional_execute<F>(&self, condition: bool, func: F) -> bool
where
F: FnOnce() -> bool,
{
if !self.timing_protection {
return if condition { func() } else { false };
}
let true_result = func();
let false_result = false;
crate::security::constant_time::constant_time_select_bool(
condition,
true_result,
false_result,
)
}
pub fn secure_conditional_execute_no_return<F>(&self, condition: bool, func: F)
where
F: FnOnce(),
{
if !self.timing_protection {
if condition {
func();
}
return;
}
func();
}
pub fn secure_loop<F>(&self, iterations: usize, mut func: F)
where
F: FnMut(usize) -> bool,
{
if !self.timing_protection {
for i in 0..iterations {
if !func(i) {
break;
}
}
return;
}
for i in 0..iterations {
func(i);
}
}
pub fn secure_array_access<'a, T>(&self, array: &'a [T], index: usize) -> Option<&'a T> {
if !self.timing_protection {
return array.get(index);
}
let in_bounds = index < array.len();
if in_bounds { Some(&array[index]) } else { None }
}
pub fn secure_array_access_mut<'a, T>(
&self,
array: &'a mut [T],
index: usize,
) -> Option<&'a mut T> {
if !self.timing_protection {
return array.get_mut(index);
}
let in_bounds = index < array.len();
if in_bounds {
Some(&mut array[index])
} else {
None
}
}
pub fn secure_string_compare(&self, a: &str, b: &str) -> bool {
if !self.timing_protection {
return a == b;
}
crate::security::constant_time::constant_time_eq(a.as_bytes(), b.as_bytes())
}
pub fn secure_integer_compare(&self, a: u64, b: u64) -> bool {
if !self.timing_protection {
return a == b;
}
let a_bytes = a.to_le_bytes();
let b_bytes = b.to_le_bytes();
crate::security::constant_time::constant_time_eq(&a_bytes, &b_bytes)
}
pub fn secure_integer_add(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a.wrapping_add(b);
}
a.wrapping_add(b)
}
pub fn secure_integer_sub(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a.wrapping_sub(b);
}
a.wrapping_sub(b)
}
pub fn secure_integer_mul(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a.wrapping_mul(b);
}
a.wrapping_mul(b)
}
pub fn secure_integer_div(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a.checked_div(b).unwrap_or(0);
}
let is_zero = b == 0;
let result = a.checked_div(b).unwrap_or(0);
crate::security::constant_time::constant_time_select(is_zero, 0, result)
}
pub fn secure_integer_mod(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a.checked_rem(b).unwrap_or(0);
}
let is_zero = b == 0;
let result = a.checked_rem(b).unwrap_or(0);
crate::security::constant_time::constant_time_select(is_zero, 0, result)
}
pub fn secure_bitwise_and(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a & b;
}
a & b
}
pub fn secure_bitwise_or(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a | b;
}
a | b
}
pub fn secure_bitwise_xor(&self, a: u64, b: u64) -> u64 {
if !self.timing_protection {
return a ^ b;
}
a ^ b
}
pub fn secure_bitwise_not(&self, a: u64) -> u64 {
if !self.timing_protection {
return !a;
}
!a
}
pub fn secure_left_shift(&self, a: u64, amount: u32) -> u64 {
if !self.timing_protection {
return a << amount;
}
a << amount
}
pub fn secure_right_shift(&self, a: u64, amount: u32) -> u64 {
if !self.timing_protection {
return a >> amount;
}
a >> amount
}
pub fn secure_rotate_left(&self, a: u64, amount: u32) -> u64 {
if !self.timing_protection {
return a.rotate_left(amount);
}
a.rotate_left(amount)
}
pub fn secure_rotate_right(&self, a: u64, amount: u32) -> u64 {
if !self.timing_protection {
return a.rotate_right(amount);
}
a.rotate_right(amount)
}
pub fn secure_conditional_assign<T: subtle::ConditionallySelectable>(
&self,
condition: bool,
value: &mut T,
new_value: T,
) {
if !self.timing_protection {
if condition {
*value = new_value;
}
return;
}
*value = crate::security::constant_time::constant_time_select(condition, new_value, *value);
}
pub fn secure_conditional_increment(&self, condition: bool, value: &mut u64) {
if !self.timing_protection {
if condition {
*value = value.wrapping_add(1);
}
return;
}
let increment = crate::security::constant_time::constant_time_select(condition, 1, 0);
*value = value.wrapping_add(increment);
}
pub fn secure_conditional_decrement(&self, condition: bool, value: &mut u64) {
if !self.timing_protection {
if condition {
*value = value.wrapping_sub(1);
}
return;
}
let decrement = crate::security::constant_time::constant_time_select(condition, 1, 0);
*value = value.wrapping_sub(decrement);
}
pub fn secure_conditional_add(&self, condition: bool, value: &mut u64, addend: u64) {
if !self.timing_protection {
if condition {
*value = value.wrapping_add(addend);
}
return;
}
let masked_addend =
crate::security::constant_time::constant_time_select(condition, addend, 0);
*value = value.wrapping_add(masked_addend);
}
pub fn secure_conditional_subtract(&self, condition: bool, value: &mut u64, subtrahend: u64) {
if !self.timing_protection {
if condition {
*value = value.wrapping_sub(subtrahend);
}
return;
}
let masked_subtrahend =
crate::security::constant_time::constant_time_select(condition, subtrahend, 0);
*value = value.wrapping_sub(masked_subtrahend);
}
pub fn secure_conditional_multiply(&self, condition: bool, value: &mut u64, multiplier: u64) {
if !self.timing_protection {
if condition {
*value = value.wrapping_mul(multiplier);
}
return;
}
let masked_multiplier =
crate::security::constant_time::constant_time_select(condition, multiplier, 1);
*value = value.wrapping_mul(masked_multiplier);
}
pub fn secure_conditional_divide(&self, condition: bool, value: &mut u64, divisor: u64) {
if !self.timing_protection {
if condition && divisor != 0 {
*value /= divisor;
}
return;
}
let is_zero = divisor == 0;
let masked_divisor =
crate::security::constant_time::constant_time_select(condition && !is_zero, divisor, 1);
*value /= masked_divisor;
}
pub fn secure_conditional_modulo(&self, condition: bool, value: &mut u64, divisor: u64) {
if !self.timing_protection {
if condition && divisor != 0 {
*value %= divisor;
}
return;
}
let is_zero = divisor == 0;
let masked_divisor = crate::security::constant_time::constant_time_select(
condition && !is_zero,
divisor,
u64::MAX,
);
*value %= masked_divisor;
}
pub fn secure_conditional_bitwise_and(&self, condition: bool, value: &mut u64, mask: u64) {
if !self.timing_protection {
if condition {
*value &= mask;
}
return;
}
let masked_mask = crate::security::constant_time::constant_time_select(condition, mask, !0);
*value &= masked_mask;
}
pub fn secure_conditional_bitwise_or(&self, condition: bool, value: &mut u64, mask: u64) {
if !self.timing_protection {
if condition {
*value |= mask;
}
return;
}
let masked_mask = crate::security::constant_time::constant_time_select(condition, mask, 0);
*value |= masked_mask;
}
pub fn secure_conditional_bitwise_xor(&self, condition: bool, value: &mut u64, mask: u64) {
if !self.timing_protection {
if condition {
*value ^= mask;
}
return;
}
let masked_mask = crate::security::constant_time::constant_time_select(condition, mask, 0);
*value ^= masked_mask;
}
pub fn secure_conditional_bitwise_not(&self, condition: bool, value: &mut u64) {
if !self.timing_protection {
if condition {
*value = !*value;
}
return;
}
let original = *value;
*value = !*value;
*value = crate::security::constant_time::constant_time_select(condition, *value, original);
}
pub fn secure_conditional_left_shift(&self, condition: bool, value: &mut u64, amount: u32) {
if !self.timing_protection {
if condition {
*value <<= amount;
}
return;
}
let shifted = *value << amount;
*value = crate::security::constant_time::constant_time_select(condition, shifted, *value);
}
pub fn secure_conditional_right_shift(&self, condition: bool, value: &mut u64, amount: u32) {
if !self.timing_protection {
if condition {
*value >>= amount;
}
return;
}
let shifted = *value >> amount;
*value = crate::security::constant_time::constant_time_select(condition, shifted, *value);
}
pub fn secure_conditional_rotate_left(&self, condition: bool, value: &mut u64, amount: u32) {
if !self.timing_protection {
if condition {
*value = value.rotate_left(amount);
}
return;
}
let rotated = value.rotate_left(amount);
*value = crate::security::constant_time::constant_time_select(condition, rotated, *value);
}
pub fn secure_conditional_rotate_right(&self, condition: bool, value: &mut u64, amount: u32) {
if !self.timing_protection {
if condition {
*value = value.rotate_right(amount);
}
return;
}
let rotated = value.rotate_right(amount);
*value = crate::security::constant_time::constant_time_select(condition, rotated, *value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_side_channel_protection_defaults() {
let protection = SideChannelProtection::default();
assert!(protection.timing_protection);
assert!(protection.power_analysis_protection);
assert!(protection.cache_attack_protection);
assert!(protection.fault_injection_protection);
}
#[test]
fn test_side_channel_protection_strict() {
let protection = SideChannelProtection::strict();
assert!(protection.timing_protection);
assert!(protection.power_analysis_protection);
assert!(protection.cache_attack_protection);
assert!(protection.fault_injection_protection);
}
#[test]
fn test_side_channel_protection_permissive() {
let protection = SideChannelProtection::permissive();
assert!(!protection.timing_protection);
assert!(!protection.power_analysis_protection);
assert!(!protection.cache_attack_protection);
assert!(!protection.fault_injection_protection);
}
#[test]
fn test_secure_key_compare() {
let protection = SideChannelProtection::new();
let a = [1, 2, 3, 4];
let b = [1, 2, 3, 4];
let c = [1, 2, 3, 5];
assert!(protection.secure_key_compare(&a, &b));
assert!(!protection.secure_key_compare(&a, &c));
}
#[test]
fn test_secure_key_select() {
let protection = SideChannelProtection::new();
let a = [1, 2, 3, 4];
let b = [5, 6, 7, 8];
#[cfg(feature = "alloc")]
{
let result1 = protection.secure_key_select(1, &a, &b);
assert_eq!(result1, a);
let result0 = protection.secure_key_select(0, &a, &b);
assert_eq!(result0, b);
}
#[cfg(not(feature = "alloc"))]
{
let mut result = [0; 4];
protection.secure_key_select(1, &a, &b, &mut result);
assert_eq!(result, a);
protection.secure_key_select(0, &a, &b, &mut result);
assert_eq!(result, b);
}
}
#[test]
fn test_secure_memory_access() {
let protection = SideChannelProtection::new();
let data = [1, 2, 3, 4, 5];
assert_eq!(protection.secure_memory_access(&data, 2), Some(&3));
assert_eq!(protection.secure_memory_access(&data, 10), None);
}
#[test]
fn test_secure_conditional_execute() {
let protection = SideChannelProtection::new();
let mut executed = false;
let result = protection.secure_conditional_execute(true, || {
executed = true;
true
});
assert!(result);
assert!(executed);
}
#[test]
fn test_secure_conditional_execute_no_return() {
let protection = SideChannelProtection::new();
let mut executed = false;
protection.secure_conditional_execute_no_return(true, || {
executed = true;
});
assert!(executed);
}
#[test]
fn test_secure_loop() {
let protection = SideChannelProtection::new();
let mut count = 0;
protection.secure_loop(5, |_| {
count += 1;
true
});
assert_eq!(count, 5);
}
#[test]
fn test_secure_array_access() {
let protection = SideChannelProtection::new();
let array = [1, 2, 3, 4, 5];
assert_eq!(protection.secure_array_access(&array, 2), Some(&3));
assert_eq!(protection.secure_array_access(&array, 10), None);
}
#[test]
fn test_secure_string_compare() {
let protection = SideChannelProtection::new();
assert!(protection.secure_string_compare("hello", "hello"));
assert!(!protection.secure_string_compare("hello", "world"));
}
#[test]
fn test_secure_integer_compare() {
let protection = SideChannelProtection::new();
assert!(protection.secure_integer_compare(42, 42));
assert!(!protection.secure_integer_compare(42, 24));
}
#[test]
fn test_secure_integer_operations() {
let protection = SideChannelProtection::new();
assert_eq!(protection.secure_integer_add(10, 5), 15);
assert_eq!(protection.secure_integer_sub(10, 5), 5);
assert_eq!(protection.secure_integer_mul(10, 5), 50);
assert_eq!(protection.secure_integer_div(10, 5), 2);
assert_eq!(protection.secure_integer_mod(10, 5), 0);
}
#[test]
fn test_secure_bitwise_operations() {
let protection = SideChannelProtection::new();
assert_eq!(protection.secure_bitwise_and(0b1010, 0b1100), 0b1000);
assert_eq!(protection.secure_bitwise_or(0b1010, 0b1100), 0b1110);
assert_eq!(protection.secure_bitwise_xor(0b1010, 0b1100), 0b0110);
assert_eq!(protection.secure_bitwise_not(0b1010), !0b1010);
}
#[test]
fn test_secure_shift_operations() {
let protection = SideChannelProtection::new();
assert_eq!(protection.secure_left_shift(0b1010u64, 2), 0b101000u64);
assert_eq!(protection.secure_right_shift(0b1010u64, 2), 0b10u64);
assert_eq!(protection.secure_rotate_left(0b1010u64, 2), 0b101000u64);
assert_eq!(
protection.secure_rotate_right(0b1010u64, 2),
0b1010u64.rotate_right(2)
);
}
#[test]
fn test_secure_conditional_operations() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_assign(true, &mut value, 24);
assert_eq!(value, 24);
protection.secure_conditional_assign(false, &mut value, 100);
assert_eq!(value, 24);
}
#[test]
fn test_secure_conditional_increment() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_increment(true, &mut value);
assert_eq!(value, 43);
protection.secure_conditional_increment(false, &mut value);
assert_eq!(value, 43);
}
#[test]
fn test_secure_conditional_decrement() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_decrement(true, &mut value);
assert_eq!(value, 41);
protection.secure_conditional_decrement(false, &mut value);
assert_eq!(value, 41);
}
#[test]
fn test_secure_conditional_add() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_add(true, &mut value, 10);
assert_eq!(value, 52);
protection.secure_conditional_add(false, &mut value, 5);
assert_eq!(value, 52);
}
#[test]
fn test_secure_conditional_subtract() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_subtract(true, &mut value, 10);
assert_eq!(value, 32);
protection.secure_conditional_subtract(false, &mut value, 5);
assert_eq!(value, 32);
}
#[test]
fn test_secure_conditional_multiply() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_multiply(true, &mut value, 2);
assert_eq!(value, 84);
protection.secure_conditional_multiply(false, &mut value, 3);
assert_eq!(value, 84);
}
#[test]
fn test_secure_conditional_divide() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_divide(true, &mut value, 2);
assert_eq!(value, 21);
protection.secure_conditional_divide(false, &mut value, 3);
assert_eq!(value, 21);
}
#[test]
fn test_secure_conditional_modulo() {
let protection = SideChannelProtection::new();
let mut value = 42u64;
protection.secure_conditional_modulo(true, &mut value, 10);
assert_eq!(value, 2);
protection.secure_conditional_modulo(false, &mut value, 5);
assert_eq!(value, 2);
}
#[test]
fn test_secure_conditional_bitwise_operations() {
let protection = SideChannelProtection::new();
let mut value = 0b1010u64;
protection.secure_conditional_bitwise_and(true, &mut value, 0b1100);
assert_eq!(value, 0b1000);
protection.secure_conditional_bitwise_or(true, &mut value, 0b0010);
assert_eq!(value, 0b1010);
protection.secure_conditional_bitwise_xor(true, &mut value, 0b1111);
assert_eq!(value, 0b0101);
protection.secure_conditional_bitwise_not(true, &mut value);
assert_eq!(value, !0b0101);
}
#[test]
fn test_secure_conditional_shift_operations() {
let protection = SideChannelProtection::new();
let mut value = 0b1010u64;
protection.secure_conditional_left_shift(true, &mut value, 2);
assert_eq!(value, 0b101000);
protection.secure_conditional_right_shift(true, &mut value, 2);
assert_eq!(value, 0b1010);
protection.secure_conditional_rotate_left(true, &mut value, 2);
assert_eq!(value, 0b101000);
protection.secure_conditional_rotate_right(true, &mut value, 2);
assert_eq!(value, 0b1010);
}
}