Skip to main content

webrtc_sys/
frame_cryptor.rs

1// Copyright 2025 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::sync::Arc;
16
17use crate::impl_thread_safety;
18
19#[cxx::bridge(namespace = "livekit_ffi")]
20pub mod ffi {
21
22    #[derive(Debug)]
23    pub struct KeyProviderOptions {
24        pub shared_key: bool,
25        pub ratchet_window_size: i32,
26        pub ratchet_salt: Vec<u8>,
27        pub failure_tolerance: i32,
28        pub key_ring_size: i32,
29        pub key_derivation_algorithm: KeyDerivationAlgorithm,
30    }
31
32    #[derive(Debug)]
33    #[repr(i32)]
34    pub enum KeyDerivationAlgorithm {
35        PBKDF2 = 0,
36        HKDF,
37    }
38
39    #[derive(Debug)]
40    #[repr(i32)]
41    pub enum Algorithm {
42        AesGcm = 0,
43        AesCbc,
44    }
45
46    #[derive(Debug)]
47    #[repr(i32)]
48    pub enum FrameCryptionState {
49        New = 0,
50        Ok,
51        EncryptionFailed,
52        DecryptionFailed,
53        MissingKey,
54        KeyRatcheted,
55        InternalError,
56    }
57
58    #[derive(Debug)]
59    pub struct EncryptedPacket {
60        pub data: Vec<u8>,
61        pub iv: Vec<u8>,
62        pub key_index: u32,
63    }
64
65    unsafe extern "C++" {
66        include!("livekit/frame_cryptor.h");
67
68        pub type KeyProvider;
69
70        pub fn new_key_provider(options: KeyProviderOptions) -> SharedPtr<KeyProvider>;
71
72        pub fn set_shared_key(self: &KeyProvider, key_index: i32, key: Vec<u8>) -> bool;
73
74        pub fn ratchet_shared_key(self: &KeyProvider, key_index: i32) -> Result<Vec<u8>>;
75
76        pub fn get_shared_key(self: &KeyProvider, key_index: i32) -> Result<Vec<u8>>;
77
78        pub fn set_sif_trailer(&self, trailer: Vec<u8>);
79
80        pub fn set_key(
81            self: &KeyProvider,
82            participant_id: String,
83            key_index: i32,
84            key: Vec<u8>,
85        ) -> bool;
86
87        pub fn ratchet_key(
88            self: &KeyProvider,
89            participant_id: String,
90            key_index: i32,
91        ) -> Result<Vec<u8>>;
92
93        pub fn get_key(
94            self: &KeyProvider,
95            participant_id: String,
96            key_index: i32,
97        ) -> Result<Vec<u8>>;
98    }
99
100    unsafe extern "C++" {
101        include!("livekit/frame_cryptor.h");
102        include!("livekit/rtp_sender.h");
103        include!("livekit/rtp_receiver.h");
104        include!("livekit/peer_connection_factory.h");
105        include!("livekit/packet_trailer.h");
106
107        type RtpSender = crate::rtp_sender::ffi::RtpSender;
108        type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
109        type PeerConnectionFactory = crate::peer_connection_factory::ffi::PeerConnectionFactory;
110        type PacketTrailerHandler = crate::packet_trailer::ffi::PacketTrailerHandler;
111
112        pub type FrameCryptor;
113
114        pub fn new_frame_cryptor_for_rtp_sender(
115            peer_factory: SharedPtr<PeerConnectionFactory>,
116            participant_id: String,
117            algorithm: Algorithm,
118            key_provider: SharedPtr<KeyProvider>,
119            sender: SharedPtr<RtpSender>,
120        ) -> SharedPtr<FrameCryptor>;
121
122        pub fn new_frame_cryptor_for_rtp_receiver(
123            peer_factory: SharedPtr<PeerConnectionFactory>,
124            participant_id: String,
125            algorithm: Algorithm,
126            key_provider: SharedPtr<KeyProvider>,
127            receiver: SharedPtr<RtpReceiver>,
128        ) -> SharedPtr<FrameCryptor>;
129
130        pub fn set_enabled(self: &FrameCryptor, enabled: bool);
131
132        pub fn enabled(self: &FrameCryptor) -> bool;
133
134        pub fn set_key_index(self: &FrameCryptor, index: i32);
135
136        pub fn key_index(self: &FrameCryptor) -> i32;
137
138        pub fn participant_id(self: &FrameCryptor) -> String;
139
140        pub fn register_observer(
141            self: &FrameCryptor,
142            observer: Box<RtcFrameCryptorObserverWrapper>,
143        );
144
145        pub fn unregister_observer(self: &FrameCryptor);
146
147        pub fn set_packet_trailer_handler(
148            self: &FrameCryptor,
149            handler: SharedPtr<PacketTrailerHandler>,
150        );
151    }
152
153    unsafe extern "C++" {
154        include!("livekit/frame_cryptor.h");
155
156        pub type DataPacketCryptor;
157
158        pub fn new_data_packet_cryptor(
159            algorithm: Algorithm,
160            key_provider: SharedPtr<KeyProvider>,
161        ) -> SharedPtr<DataPacketCryptor>;
162
163        pub fn encrypt_data_packet(
164            self: &DataPacketCryptor,
165            participant_id: String,
166            key_index: u32,
167            data: Vec<u8>,
168        ) -> Result<EncryptedPacket>;
169
170        pub fn decrypt_data_packet(
171            self: &DataPacketCryptor,
172            participant_id: String,
173            encrypted_packet: &EncryptedPacket,
174        ) -> Result<Vec<u8>>;
175    }
176
177    extern "Rust" {
178        type RtcFrameCryptorObserverWrapper;
179
180        fn on_frame_cryption_state_change(
181            self: &RtcFrameCryptorObserverWrapper,
182            participant_id: String,
183            state: FrameCryptionState,
184        );
185    }
186} // namespace livekit_ffi
187
188impl_thread_safety!(ffi::FrameCryptor, Send + Sync);
189impl_thread_safety!(ffi::KeyProvider, Send + Sync);
190impl_thread_safety!(ffi::DataPacketCryptor, Send + Sync);
191
192use ffi::FrameCryptionState;
193
194// Re-export the EncryptedPacket for convenience
195pub use ffi::EncryptedPacket;
196
197pub trait RtcFrameCryptorObserver: Send + Sync {
198    fn on_frame_cryption_state_change(&self, participant_id: String, state: FrameCryptionState);
199}
200
201pub struct RtcFrameCryptorObserverWrapper {
202    observer: Arc<dyn RtcFrameCryptorObserver>,
203}
204
205impl RtcFrameCryptorObserverWrapper {
206    pub fn new(observer: Arc<dyn RtcFrameCryptorObserver>) -> Self {
207        Self { observer }
208    }
209
210    fn on_frame_cryption_state_change(
211        self: &RtcFrameCryptorObserverWrapper,
212        participant_id: String,
213        state: FrameCryptionState,
214    ) {
215        self.observer.on_frame_cryption_state_change(participant_id, state);
216    }
217}
218
219/// High-level Rust wrapper for data packet cryptor functionality
220pub struct DataPacketCryptor {
221    inner: cxx::SharedPtr<ffi::DataPacketCryptor>,
222}
223
224impl DataPacketCryptor {
225    /// Create a new data packet cryptor with the specified algorithm and key provider
226    pub fn new(algorithm: ffi::Algorithm, key_provider: cxx::SharedPtr<ffi::KeyProvider>) -> Self {
227        Self { inner: ffi::new_data_packet_cryptor(algorithm, key_provider) }
228    }
229
230    /// Encrypt data for a specific participant
231    pub fn encrypt(
232        &self,
233        participant_id: &str,
234        key_index: u32,
235        data: &[u8],
236    ) -> Result<ffi::EncryptedPacket, Box<dyn std::error::Error>> {
237        let data_vec: Vec<u8> = data.to_vec();
238        match self.inner.encrypt_data_packet(participant_id.to_string(), key_index, data_vec) {
239            Ok(packet) => Ok(packet),
240            Err(e) => Err(format!("Encryption failed: {}", e).into()),
241        }
242    }
243
244    /// Decrypt an encrypted packet for a specific participant
245    pub fn decrypt(
246        &self,
247        participant_id: &str,
248        encrypted_packet: &ffi::EncryptedPacket,
249    ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
250        match self.inner.decrypt_data_packet(participant_id.to_string(), encrypted_packet) {
251            Ok(data) => Ok(data.into_iter().collect()),
252            Err(e) => Err(format!("Decryption failed: {}", e).into()),
253        }
254    }
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260
261    #[test]
262    fn test_data_packet_cryptor_creation() {
263        let options = ffi::KeyProviderOptions {
264            shared_key: true,
265            ratchet_window_size: 16,
266            ratchet_salt: vec![],
267            failure_tolerance: -1,
268            key_ring_size: 16,
269            key_derivation_algorithm: ffi::KeyDerivationAlgorithm::HKDF,
270        };
271
272        let key_provider = ffi::new_key_provider(options);
273        let _cryptor = DataPacketCryptor::new(ffi::Algorithm::AesGcm, key_provider);
274    }
275}