// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright by contributors to this project.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
use mls_rs_core::{crypto::CipherSuiteProvider, extension::ExtensionList, group::Capabilities};
use crate ::{
client::MlsError,
group::{GroupInfo, NewMemberInfo},
key_package::KeyPackage,
tree_kem::leaf_node::LeafNode,
};
impl LeafNode {
pub fn ungreased_capabilities(&self ) -> Capabilities {
let mut capabilitites = self .capabilities.clone();
grease_functions::ungrease(&mut capabilitites.cipher_suites);
grease_functions::ungrease(&mut capabilitites.extensions);
grease_functions::ungrease(&mut capabilitites.proposals);
grease_functions::ungrease(&mut capabilitites.credentials);
capabilitites
}
pub fn ungreased_extensions(&self ) -> ExtensionList {
let mut extensions = self .extensions.clone();
grease_functions::ungrease_extensions(&mut extensions);
extensions
}
pub fn grease<P: CipherSuiteProvider>(&mut self , cs: &P) -> Result<(), MlsError> {
grease_functions::grease(&mut self .capabilities.cipher_suites, cs)?;
grease_functions::grease(&mut self .capabilities.proposals, cs)?;
grease_functions::grease(&mut self .capabilities.credentials, cs)?;
let mut new_extensions = grease_functions::grease_extensions(&mut self .extensions, cs)?;
self .capabilities.extensions.append(&mut new_extensions);
Ok(())
}
}
impl KeyPackage {
pub fn grease<P: CipherSuiteProvider>(&mut self , cs: &P) -> Result<(), MlsError> {
grease_functions::grease_extensions(&mut self .extensions, cs).map(|_| ())
}
pub fn ungreased_extensions(&self ) -> ExtensionList {
let mut extensions = self .extensions.clone();
grease_functions::ungrease_extensions(&mut extensions);
extensions
}
}
impl GroupInfo {
pub fn grease<P: CipherSuiteProvider>(&mut self , cs: &P) -> Result<(), MlsError> {
grease_functions::grease_extensions(&mut self .extensions, cs).map(|_| ())
}
}
impl NewMemberInfo {
pub fn ungrease(&mut self ) {
grease_functions::ungrease_extensions(&mut self .group_info_extensions)
}
}
#[ cfg(feature = "grease" )]
mod grease_functions {
use core::ops::Deref;
use mls_rs_core::{
crypto::CipherSuiteProvider,
error::IntoAnyError,
extension::{Extension, ExtensionList, ExtensionType},
};
use super ::MlsError;
pub const GREASE_VALUES: &[u16] = &[
0 x0A0A, 0 x1A1A, 0 x2A2A, 0 x3A3A, 0 x4A4A, 0 x5A5A, 0 x6A6A, 0 x7A7A, 0 x8A8A, 0 x9A9A, 0 xAAAA,
0 xBABA, 0 xCACA, 0 xDADA, 0 xEAEA,
];
pub fn grease<T: From<u16>, P: CipherSuiteProvider>(
array: &mut Vec<T>,
cs: &P,
) -> Result<(), MlsError> {
array.push(random_grease_value(cs)?.into());
Ok(())
}
pub fn grease_extensions<P: CipherSuiteProvider>(
extensions: &mut ExtensionList,
cs: &P,
) -> Result<Vec<ExtensionType>, MlsError> {
let grease_value = random_grease_value(cs)?;
extensions.set(Extension::new(grease_value.into(), vec![]));
Ok(vec![grease_value.into()])
}
fn random_grease_value<P: CipherSuiteProvider>(cs: &P) -> Result<u16, MlsError> {
let index = cs
.random_bytes_vec(1 )
.map_err(|e| MlsError::CryptoProviderError(e.into_any_error()))?[0 ];
Ok(GREASE_VALUES[index as usize % GREASE_VALUES.len()])
}
pub fn ungrease<T: Deref<Target = u16>>(array: &mut Vec<T>) {
array.retain(|x| !GREASE_VALUES.contains(&**x));
}
pub fn ungrease_extensions(extensions: &mut ExtensionList) {
for e in GREASE_VALUES {
extensions.remove((*e).into())
}
}
}
#[ cfg(not(feature = "grease" ))]
mod grease_functions {
use core::ops::Deref;
use alloc::vec::Vec;
use mls_rs_core::{
crypto::CipherSuiteProvider,
extension::{ExtensionList, ExtensionType},
};
use super ::MlsError;
pub fn grease<T: From<u16>, P: CipherSuiteProvider>(
_array: &mut [T],
_cs: &P,
) -> Result<(), MlsError> {
Ok(())
}
pub fn grease_extensions<P: CipherSuiteProvider>(
_extensions: &mut ExtensionList,
_cs: &P,
) -> Result<Vec<ExtensionType>, MlsError> {
Ok(Vec::new())
}
pub fn ungrease<T: Deref<Target = u16>>(_array: &mut [T]) {}
pub fn ungrease_extensions(_extensions: &mut ExtensionList) {}
}
#[ cfg(all(test, feature = "grease" ))]
mod tests {
#[ cfg(target_arch = "wasm32" )]
use wasm_bindgen_test::wasm_bindgen_test as test;
use std::ops::Deref;
use mls_rs_core::extension::ExtensionList;
use crate ::{
client::test_utils::{test_client_with_key_pkg, TEST_CIPHER_SUITE, TEST_PROTOCOL_VERSION},
group::test_utils::test_group,
};
use super ::grease_functions::GREASE_VALUES;
#[ maybe_async::test(not(mls_build_async), async (mls_build_async, crate ::futures_test))]
async fn key_package_is_greased() {
let key_pkg = test_client_with_key_pkg(TEST_PROTOCOL_VERSION, TEST_CIPHER_SUITE, "alice" )
.await
.1
.into_key_package()
.unwrap();
assert!(is_ext_greased(&key_pkg.extensions));
assert!(is_ext_greased(&key_pkg.leaf_node.extensions));
assert!(is_greased(&key_pkg.leaf_node.capabilities.cipher_suites));
assert!(is_greased(&key_pkg.leaf_node.capabilities.extensions));
assert!(is_greased(&key_pkg.leaf_node.capabilities.proposals));
assert!(is_greased(&key_pkg.leaf_node.capabilities.credentials));
assert!(!is_greased(
&key_pkg.leaf_node.capabilities.protocol_versions
));
}
#[ maybe_async::test(not(mls_build_async), async (mls_build_async, crate ::futures_test))]
async fn group_info_is_greased() {
let group_info = test_group(TEST_PROTOCOL_VERSION, TEST_CIPHER_SUITE)
.await
.group
.group_info_message_allowing_ext_commit(false )
.await
.unwrap()
.into_group_info()
.unwrap();
assert!(is_ext_greased(&group_info.extensions));
}
#[ maybe_async::test(not(mls_build_async), async (mls_build_async, crate ::futures_test))]
async fn public_api_is_not_greased() {
let member = test_group(TEST_PROTOCOL_VERSION, TEST_CIPHER_SUITE)
.await
.group
.roster()
.member_with_index(0 )
.unwrap();
assert!(!is_ext_greased(member.extensions()));
assert!(!is_greased(member.capabilities().protocol_versions()));
assert!(!is_greased(member.capabilities().cipher_suites()));
assert!(!is_greased(member.capabilities().extensions()));
assert!(!is_greased(member.capabilities().proposals()));
assert!(!is_greased(member.capabilities().credentials()));
}
fn is_greased<T: Deref<Target = u16>>(list: &[T]) -> bool {
list.iter().any(|v| GREASE_VALUES.contains(v))
}
fn is_ext_greased(extensions: &ExtensionList) -> bool {
extensions
.iter()
.any(|ext| GREASE_VALUES.contains(&*ext.extension_type()))
}
}
Messung V0.5 in Prozent C=74 H=89 G=81
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland