// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright by contributors to this project. // SPDX-License-Identifier: (Apache-2.0 OR MIT) /// Padding used when sending an encrypted group message. #[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::ffi_type)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[repr(u8)] pub enum PaddingMode { /// Step function based on the size of the message being sent. /// The amount of padding used will increase with the size of the original /// message. #[default] StepFunction, /// No padding. None, } impl PaddingMode { pub(super) fn padded_size(&self, content_size: usize) -> usize { match self { PaddingMode::StepFunction => { // The padding hides all but 2 most significant bits of `length`. The hidden bits are replaced // by zeros and then the next number is taken to make sure the message fits. let blind = 1 << ((content_size + 1) .next_power_of_two() .max(256) .trailing_zeros() - 3); (content_size | (blind - 1)) + 1 } PaddingMode::None => content_size, } } } #[cfg(test)] mod tests { use super::PaddingMode; use alloc::vec; use alloc::vec::Vec; #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::wasm_bindgen_test as test; #[derive(serde::Deserialize, serde::Serialize)] struct TestCase { input: usize, output: usize, } #[cfg_attr(coverage_nightly, coverage(off))] fn generate_message_padding_test_vector() -> Vec { let mut test_cases = vec![]; for x in 1..1024 { test_cases.push(TestCase { input: x, output: PaddingMode::StepFunction.padded_size(x), }); } test_cases } fn load_test_cases() -> Vec { load_test_case_json!( message_padding_test_vector, generate_message_padding_test_vector() ) } #[test] fn test_no_padding() { for i in [0, 100, 1000, 10000] { assert_eq!(PaddingMode::None.padded_size(i), i) } } #[test] fn test_padding_length() { assert_eq!(PaddingMode::StepFunction.padded_size(0), 32); // Short assert_eq!(PaddingMode::StepFunction.padded_size(63), 64); assert_eq!(PaddingMode::StepFunction.padded_size(64), 96); assert_eq!(PaddingMode::StepFunction.padded_size(65), 96); // Almost long and almost short assert_eq!(PaddingMode::StepFunction.padded_size(127), 128); assert_eq!(PaddingMode::StepFunction.padded_size(128), 160); assert_eq!(PaddingMode::StepFunction.padded_size(129), 160); // One length from each of the 4 buckets between 256 and 512 assert_eq!(PaddingMode::StepFunction.padded_size(260), 320); assert_eq!(PaddingMode::StepFunction.padded_size(330), 384); assert_eq!(PaddingMode::StepFunction.padded_size(390), 448); assert_eq!(PaddingMode::StepFunction.padded_size(490), 512); // All test cases let test_cases: Vec = load_test_cases(); for test_case in test_cases { assert_eq!( test_case.output, PaddingMode::StepFunction.padded_size(test_case.input) ); } } }