From 91dcd37e8e0fbe9f445b3aa698b41d6dc98e9a7a Mon Sep 17 00:00:00 2001 From: onestacked Date: Tue, 17 Feb 2026 00:19:18 +0100 Subject: [PATCH 1/2] Allow setting keyring-size from Rust --- libwebrtc/src/native/frame_cryptor.rs | 2 ++ livekit/src/room/e2ee/key_provider.rs | 5 +++++ webrtc-sys/src/frame_cryptor.cpp | 26 ++++++++++++++++---------- webrtc-sys/src/frame_cryptor.rs | 1 + 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/libwebrtc/src/native/frame_cryptor.rs b/libwebrtc/src/native/frame_cryptor.rs index f6fdf33bf..3def10657 100644 --- a/libwebrtc/src/native/frame_cryptor.rs +++ b/libwebrtc/src/native/frame_cryptor.rs @@ -31,6 +31,7 @@ pub struct KeyProviderOptions { pub ratchet_window_size: i32, pub ratchet_salt: Vec, pub failure_tolerance: i32, + pub key_ring_size: i32, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -272,6 +273,7 @@ impl From for sys_fc::ffi::KeyProviderOptions { ratchet_window_size: value.ratchet_window_size, ratchet_salt: value.ratchet_salt, failure_tolerance: value.failure_tolerance, + key_ring_size: value.key_ring_size, } } } diff --git a/livekit/src/room/e2ee/key_provider.rs b/livekit/src/room/e2ee/key_provider.rs index 5140a4168..a54a283cf 100644 --- a/livekit/src/room/e2ee/key_provider.rs +++ b/livekit/src/room/e2ee/key_provider.rs @@ -23,12 +23,14 @@ use crate::id::ParticipantIdentity; const DEFAULT_RATCHET_SALT: &str = "LKFrameEncryptionKey"; const DEFAULT_RATCHET_WINDOW_SIZE: i32 = 16; const DEFAULT_FAILURE_TOLERANCE: i32 = -1; // no tolerance by default +const DEFAULT_KEY_RING_SIZE: i32 = 16; #[derive(Clone)] pub struct KeyProviderOptions { pub ratchet_window_size: i32, pub ratchet_salt: Vec, pub failure_tolerance: i32, + pub key_ring_size: i32, } impl Default for KeyProviderOptions { @@ -37,6 +39,7 @@ impl Default for KeyProviderOptions { ratchet_window_size: DEFAULT_RATCHET_WINDOW_SIZE, ratchet_salt: DEFAULT_RATCHET_SALT.to_owned().into_bytes(), failure_tolerance: DEFAULT_FAILURE_TOLERANCE, + key_ring_size: DEFAULT_KEY_RING_SIZE, } } } @@ -56,6 +59,7 @@ impl KeyProvider { ratchet_window_size: options.ratchet_window_size, ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, + key_ring_size: options.key_ring_size, }), latest_key_index: Arc::new(AtomicI32::new(0)), } @@ -67,6 +71,7 @@ impl KeyProvider { ratchet_window_size: options.ratchet_window_size, ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, + key_ring_size: options.key_ring_size, }); handle.set_shared_key(0, shared_key); Self { handle, latest_key_index: Arc::new(AtomicI32::new(0)) } diff --git a/webrtc-sys/src/frame_cryptor.cpp b/webrtc-sys/src/frame_cryptor.cpp index cbbd10d0e..f094c8eb3 100644 --- a/webrtc-sys/src/frame_cryptor.cpp +++ b/webrtc-sys/src/frame_cryptor.cpp @@ -51,6 +51,7 @@ KeyProvider::KeyProvider(KeyProviderOptions options) { rtc_options.ratchet_salt = ratchet_salt; rtc_options.ratchet_window_size = options.ratchet_window_size; rtc_options.failure_tolerance = options.failure_tolerance; + rtc_options.key_ring_size = options.key_ring_size; impl_ = new rtc::RefCountedObject(rtc_options); @@ -154,10 +155,12 @@ int32_t FrameCryptor::key_index() const { return e2ee_transformer_->key_index(); } -DataPacketCryptor::DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm, - webrtc::scoped_refptr key_provider) +DataPacketCryptor::DataPacketCryptor( + webrtc::FrameCryptorTransformer::Algorithm algorithm, + webrtc::scoped_refptr key_provider) : data_packet_cryptor_( - webrtc::make_ref_counted(algorithm, key_provider)) {} + webrtc::make_ref_counted(algorithm, + key_provider)) {} EncryptedPacket DataPacketCryptor::encrypt_data_packet( const ::rust::String participant_id, @@ -167,12 +170,12 @@ EncryptedPacket DataPacketCryptor::encrypt_data_packet( std::copy(data.begin(), data.end(), std::back_inserter(data_vec)); auto result = data_packet_cryptor_->Encrypt( - std::string(participant_id.data(), participant_id.size()), - key_index, + std::string(participant_id.data(), participant_id.size()), key_index, data_vec); if (!result.ok()) { - throw std::runtime_error(std::string("Failed to encrypt data packet: ") + result.error().message()); + throw std::runtime_error(std::string("Failed to encrypt data packet: ") + + result.error().message()); } auto& packet = result.value(); @@ -202,20 +205,23 @@ rust::Vec<::std::uint8_t> DataPacketCryptor::decrypt_data_packet( std::copy(encrypted_packet.iv.begin(), encrypted_packet.iv.end(), std::back_inserter(iv_vec)); - auto native_encrypted_packet = webrtc::make_ref_counted( - std::move(data_vec), std::move(iv_vec), encrypted_packet.key_index); + auto native_encrypted_packet = + webrtc::make_ref_counted( + std::move(data_vec), std::move(iv_vec), encrypted_packet.key_index); auto result = data_packet_cryptor_->Decrypt( std::string(participant_id.data(), participant_id.size()), native_encrypted_packet); if (!result.ok()) { - throw std::runtime_error(std::string("Failed to decrypt data packet: ") + result.error().message()); + throw std::runtime_error(std::string("Failed to decrypt data packet: ") + + result.error().message()); } rust::Vec decrypted_data; auto& decrypted = result.value(); - std::copy(decrypted.begin(), decrypted.end(), std::back_inserter(decrypted_data)); + std::copy(decrypted.begin(), decrypted.end(), + std::back_inserter(decrypted_data)); return decrypted_data; } diff --git a/webrtc-sys/src/frame_cryptor.rs b/webrtc-sys/src/frame_cryptor.rs index 84095bfff..c805ce0e1 100644 --- a/webrtc-sys/src/frame_cryptor.rs +++ b/webrtc-sys/src/frame_cryptor.rs @@ -25,6 +25,7 @@ pub mod ffi { pub ratchet_window_size: i32, pub ratchet_salt: Vec, pub failure_tolerance: i32, + pub key_ring_size: i32, } #[derive(Debug)] From 379961fc8a307ca16b486ab2419a2d56d763fb66 Mon Sep 17 00:00:00 2001 From: onestacked Date: Thu, 5 Mar 2026 21:58:43 +0100 Subject: [PATCH 2/2] Implement using HKDF as the KDF. --- .cargo/config.toml | 6 +++++- libwebrtc/src/native/frame_cryptor.rs | 17 +++++++++++++++++ livekit-ffi/protocol/e2ee.proto | 7 +++++++ livekit-ffi/src/conversion/room.rs | 14 +++++++++++++- livekit/src/room/e2ee/key_provider.rs | 6 +++++- webrtc-sys/libwebrtc/.gclient | 2 +- webrtc-sys/src/frame_cryptor.cpp | 17 ++++++++++++++++- webrtc-sys/src/frame_cryptor.rs | 10 ++++++++++ 8 files changed, 74 insertions(+), 5 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 2dc4a5047..ecf3467b1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -14,4 +14,8 @@ rustflags = ["-C", "link-args=-ObjC"] rustflags = ["-C", "link-args=-ObjC"] [target.aarch64-apple-ios-sim] -rustflags = ["-C", "link-args=-ObjC"] \ No newline at end of file +rustflags = ["-C", "link-args=-ObjC"] + +[env] +# DO not merge! WIP change to for custom webrtc-sys build +LK_CUSTOM_WEBRTC = { value = "webrtc-sys/libwebrtc/linux-x64-release", relative = true } diff --git a/libwebrtc/src/native/frame_cryptor.rs b/libwebrtc/src/native/frame_cryptor.rs index 3def10657..0a076bf9a 100644 --- a/libwebrtc/src/native/frame_cryptor.rs +++ b/libwebrtc/src/native/frame_cryptor.rs @@ -25,6 +25,21 @@ use crate::{ pub type OnStateChange = Box; +#[derive(Copy, Clone, Debug)] +#[non_exhaustive] +pub enum KeyDerivationAlgorithm { + PBKDF2, + HKDF, +} +impl Into for KeyDerivationAlgorithm { + fn into(self) -> sys_fc::ffi::KeyDerivationAlgorithm { + match self { + KeyDerivationAlgorithm::PBKDF2 => sys_fc::ffi::KeyDerivationAlgorithm::PBKDF2, + KeyDerivationAlgorithm::HKDF => sys_fc::ffi::KeyDerivationAlgorithm::HKDF, + } + } +} + #[derive(Debug, Clone)] pub struct KeyProviderOptions { pub shared_key: bool, @@ -32,6 +47,7 @@ pub struct KeyProviderOptions { pub ratchet_salt: Vec, pub failure_tolerance: i32, pub key_ring_size: i32, + pub key_derivation_algorithm: KeyDerivationAlgorithm, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -274,6 +290,7 @@ impl From for sys_fc::ffi::KeyProviderOptions { ratchet_salt: value.ratchet_salt, failure_tolerance: value.failure_tolerance, key_ring_size: value.key_ring_size, + key_derivation_algorithm: value.key_derivation_algorithm.into(), } } } diff --git a/livekit-ffi/protocol/e2ee.proto b/livekit-ffi/protocol/e2ee.proto index bb693341d..3b2192a07 100644 --- a/livekit-ffi/protocol/e2ee.proto +++ b/livekit-ffi/protocol/e2ee.proto @@ -38,6 +38,13 @@ message KeyProviderOptions { required int32 ratchet_window_size = 2; required bytes ratchet_salt = 3; required int32 failure_tolerance = 4; // -1 = no tolerance + required int32 key_ring_size = 5; + required KeyDerivationFunction key_derivation_function = 6; +} + +enum KeyDerivationFunction { + PBKDF2 = 0; + HKDF = 1; } message E2eeOptions { diff --git a/livekit-ffi/src/conversion/room.rs b/livekit-ffi/src/conversion/room.rs index 87ee00a14..0bcf6392f 100644 --- a/livekit-ffi/src/conversion/room.rs +++ b/livekit-ffi/src/conversion/room.rs @@ -21,7 +21,7 @@ use livekit::{ options::{AudioEncoding, TrackPublishOptions, VideoEncoding}, prelude::*, webrtc::{ - native::frame_cryptor::EncryptionState, + native::frame_cryptor::{EncryptionState, KeyDerivationAlgorithm}, prelude::{ContinualGatheringPolicy, IceServer, IceTransportsType, RtcConfiguration}, }, RoomInfo, @@ -108,10 +108,22 @@ impl From for proto::DisconnectReason { impl From for KeyProviderOptions { fn from(value: proto::KeyProviderOptions) -> Self { + let key_derivation_algorithm = value.key_derivation_function().into(); Self { ratchet_window_size: value.ratchet_window_size, ratchet_salt: value.ratchet_salt, failure_tolerance: value.failure_tolerance, + key_ring_size: value.key_ring_size, + key_derivation_algorithm, + } + } +} + +impl From for KeyDerivationAlgorithm { + fn from(value: proto::KeyDerivationFunction) -> Self { + match value { + proto::KeyDerivationFunction::Pbkdf2 => KeyDerivationAlgorithm::PBKDF2, + proto::KeyDerivationFunction::Hkdf => KeyDerivationAlgorithm::HKDF, } } } diff --git a/livekit/src/room/e2ee/key_provider.rs b/livekit/src/room/e2ee/key_provider.rs index a54a283cf..7902c76f3 100644 --- a/livekit/src/room/e2ee/key_provider.rs +++ b/livekit/src/room/e2ee/key_provider.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use libwebrtc::native::frame_cryptor as fc; +use libwebrtc::native::frame_cryptor::{self as fc, KeyDerivationAlgorithm}; use std::sync::{ atomic::{AtomicI32, Ordering}, Arc, @@ -31,6 +31,7 @@ pub struct KeyProviderOptions { pub ratchet_salt: Vec, pub failure_tolerance: i32, pub key_ring_size: i32, + pub key_derivation_algorithm: KeyDerivationAlgorithm, } impl Default for KeyProviderOptions { @@ -40,6 +41,7 @@ impl Default for KeyProviderOptions { ratchet_salt: DEFAULT_RATCHET_SALT.to_owned().into_bytes(), failure_tolerance: DEFAULT_FAILURE_TOLERANCE, key_ring_size: DEFAULT_KEY_RING_SIZE, + key_derivation_algorithm: KeyDerivationAlgorithm::PBKDF2, } } } @@ -60,6 +62,7 @@ impl KeyProvider { ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, key_ring_size: options.key_ring_size, + key_derivation_algorithm: options.key_derivation_algorithm, }), latest_key_index: Arc::new(AtomicI32::new(0)), } @@ -72,6 +75,7 @@ impl KeyProvider { ratchet_salt: options.ratchet_salt, failure_tolerance: options.failure_tolerance, key_ring_size: options.key_ring_size, + key_derivation_algorithm: options.key_derivation_algorithm, }); handle.set_shared_key(0, shared_key); Self { handle, latest_key_index: Arc::new(AtomicI32::new(0)) } diff --git a/webrtc-sys/libwebrtc/.gclient b/webrtc-sys/libwebrtc/.gclient index 2cdc191a5..15d8bfbeb 100644 --- a/webrtc-sys/libwebrtc/.gclient +++ b/webrtc-sys/libwebrtc/.gclient @@ -1,7 +1,7 @@ solutions = [ { "name": 'src', - "url": 'https://github.com/webrtc-sdk/webrtc.git@m137_release', + "url": 'https://github.com/webrtc-sdk/webrtc.git@duan/hkdf-sha256-key-derivation', "custom_deps": {}, "deps_file": "DEPS", "managed": False, diff --git a/webrtc-sys/src/frame_cryptor.cpp b/webrtc-sys/src/frame_cryptor.cpp index f094c8eb3..9ed50f38d 100644 --- a/webrtc-sys/src/frame_cryptor.cpp +++ b/webrtc-sys/src/frame_cryptor.cpp @@ -40,6 +40,19 @@ webrtc::FrameCryptorTransformer::Algorithm AlgorithmToFrameCryptorAlgorithm( } } +webrtc::KeyDerivationAlgorithm +KeyDerivationAlgorithmToFrameCryptorKeyDerivationAlgorithm( + KeyDerivationAlgorithm algorithm) { + switch (algorithm) { + case KeyDerivationAlgorithm::PBKDF2: + return webrtc::KeyDerivationAlgorithm::kPBKDF2; + case KeyDerivationAlgorithm::HKDF: + return webrtc::KeyDerivationAlgorithm::kHKDF; + default: + return webrtc::KeyDerivationAlgorithm::kPBKDF2; + } +} + KeyProvider::KeyProvider(KeyProviderOptions options) { webrtc::KeyProviderOptions rtc_options; rtc_options.shared_key = options.shared_key; @@ -52,7 +65,9 @@ KeyProvider::KeyProvider(KeyProviderOptions options) { rtc_options.ratchet_window_size = options.ratchet_window_size; rtc_options.failure_tolerance = options.failure_tolerance; rtc_options.key_ring_size = options.key_ring_size; - + rtc_options.key_derivation_algorithm = + KeyDerivationAlgorithmToFrameCryptorKeyDerivationAlgorithm( + options.key_derivation_algorithm); impl_ = new rtc::RefCountedObject(rtc_options); } diff --git a/webrtc-sys/src/frame_cryptor.rs b/webrtc-sys/src/frame_cryptor.rs index c805ce0e1..55774a0d2 100644 --- a/webrtc-sys/src/frame_cryptor.rs +++ b/webrtc-sys/src/frame_cryptor.rs @@ -26,6 +26,14 @@ pub mod ffi { pub ratchet_salt: Vec, pub failure_tolerance: i32, pub key_ring_size: i32, + pub key_derivation_algorithm: KeyDerivationAlgorithm, + } + + #[derive(Debug)] + #[repr(i32)] + pub enum KeyDerivationAlgorithm { + PBKDF2 = 0, + HKDF, } #[derive(Debug)] @@ -250,6 +258,8 @@ mod tests { ratchet_window_size: 16, ratchet_salt: vec![], failure_tolerance: -1, + key_ring_size: 16, + key_derivation_algorithm: ffi::KeyDerivationAlgorithm::HKDF, }; let key_provider = ffi::new_key_provider(options);