use std::sync::Arc;
use crate::impl_thread_safety;
#[cxx::bridge(namespace = "livekit_ffi")]
pub mod ffi {
#[derive(Debug)]
pub struct KeyProviderOptions {
pub shared_key: bool,
pub ratchet_window_size: i32,
pub ratchet_salt: Vec<u8>,
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)]
#[repr(i32)]
pub enum Algorithm {
AesGcm = 0,
AesCbc,
}
#[derive(Debug)]
#[repr(i32)]
pub enum FrameCryptionState {
New = 0,
Ok,
EncryptionFailed,
DecryptionFailed,
MissingKey,
KeyRatcheted,
InternalError,
}
#[derive(Debug)]
pub struct EncryptedPacket {
pub data: Vec<u8>,
pub iv: Vec<u8>,
pub key_index: u32,
}
unsafe extern "C++" {
include!("livekit/frame_cryptor.h");
pub type KeyProvider;
pub fn new_key_provider(options: KeyProviderOptions) -> SharedPtr<KeyProvider>;
pub fn set_shared_key(self: &KeyProvider, key_index: i32, key: Vec<u8>) -> bool;
pub fn ratchet_shared_key(self: &KeyProvider, key_index: i32) -> Result<Vec<u8>>;
pub fn get_shared_key(self: &KeyProvider, key_index: i32) -> Result<Vec<u8>>;
pub fn set_sif_trailer(&self, trailer: Vec<u8>);
pub fn set_key(
self: &KeyProvider,
participant_id: String,
key_index: i32,
key: Vec<u8>,
) -> bool;
pub fn ratchet_key(
self: &KeyProvider,
participant_id: String,
key_index: i32,
) -> Result<Vec<u8>>;
pub fn get_key(
self: &KeyProvider,
participant_id: String,
key_index: i32,
) -> Result<Vec<u8>>;
}
unsafe extern "C++" {
include!("livekit/frame_cryptor.h");
include!("livekit/rtp_sender.h");
include!("livekit/rtp_receiver.h");
include!("livekit/peer_connection_factory.h");
include!("livekit/packet_trailer.h");
type RtpSender = crate::rtp_sender::ffi::RtpSender;
type RtpReceiver = crate::rtp_receiver::ffi::RtpReceiver;
type PeerConnectionFactory = crate::peer_connection_factory::ffi::PeerConnectionFactory;
type PacketTrailerHandler = crate::packet_trailer::ffi::PacketTrailerHandler;
pub type FrameCryptor;
pub fn new_frame_cryptor_for_rtp_sender(
peer_factory: SharedPtr<PeerConnectionFactory>,
participant_id: String,
algorithm: Algorithm,
key_provider: SharedPtr<KeyProvider>,
sender: SharedPtr<RtpSender>,
) -> SharedPtr<FrameCryptor>;
pub fn new_frame_cryptor_for_rtp_receiver(
peer_factory: SharedPtr<PeerConnectionFactory>,
participant_id: String,
algorithm: Algorithm,
key_provider: SharedPtr<KeyProvider>,
receiver: SharedPtr<RtpReceiver>,
) -> SharedPtr<FrameCryptor>;
pub fn set_enabled(self: &FrameCryptor, enabled: bool);
pub fn enabled(self: &FrameCryptor) -> bool;
pub fn set_key_index(self: &FrameCryptor, index: i32);
pub fn key_index(self: &FrameCryptor) -> i32;
pub fn participant_id(self: &FrameCryptor) -> String;
pub fn register_observer(
self: &FrameCryptor,
observer: Box<RtcFrameCryptorObserverWrapper>,
);
pub fn unregister_observer(self: &FrameCryptor);
pub fn set_packet_trailer_handler(
self: &FrameCryptor,
handler: SharedPtr<PacketTrailerHandler>,
);
}
unsafe extern "C++" {
include!("livekit/frame_cryptor.h");
pub type DataPacketCryptor;
pub fn new_data_packet_cryptor(
algorithm: Algorithm,
key_provider: SharedPtr<KeyProvider>,
) -> SharedPtr<DataPacketCryptor>;
pub fn encrypt_data_packet(
self: &DataPacketCryptor,
participant_id: String,
key_index: u32,
data: Vec<u8>,
) -> Result<EncryptedPacket>;
pub fn decrypt_data_packet(
self: &DataPacketCryptor,
participant_id: String,
encrypted_packet: &EncryptedPacket,
) -> Result<Vec<u8>>;
}
extern "Rust" {
type RtcFrameCryptorObserverWrapper;
fn on_frame_cryption_state_change(
self: &RtcFrameCryptorObserverWrapper,
participant_id: String,
state: FrameCryptionState,
);
}
}
impl_thread_safety!(ffi::FrameCryptor, Send + Sync);
impl_thread_safety!(ffi::KeyProvider, Send + Sync);
impl_thread_safety!(ffi::DataPacketCryptor, Send + Sync);
use ffi::FrameCryptionState;
pub use ffi::EncryptedPacket;
pub trait RtcFrameCryptorObserver: Send + Sync {
fn on_frame_cryption_state_change(&self, participant_id: String, state: FrameCryptionState);
}
pub struct RtcFrameCryptorObserverWrapper {
observer: Arc<dyn RtcFrameCryptorObserver>,
}
impl RtcFrameCryptorObserverWrapper {
pub fn new(observer: Arc<dyn RtcFrameCryptorObserver>) -> Self {
Self { observer }
}
fn on_frame_cryption_state_change(
self: &RtcFrameCryptorObserverWrapper,
participant_id: String,
state: FrameCryptionState,
) {
self.observer.on_frame_cryption_state_change(participant_id, state);
}
}
pub struct DataPacketCryptor {
inner: cxx::SharedPtr<ffi::DataPacketCryptor>,
}
impl DataPacketCryptor {
pub fn new(algorithm: ffi::Algorithm, key_provider: cxx::SharedPtr<ffi::KeyProvider>) -> Self {
Self { inner: ffi::new_data_packet_cryptor(algorithm, key_provider) }
}
pub fn encrypt(
&self,
participant_id: &str,
key_index: u32,
data: &[u8],
) -> Result<ffi::EncryptedPacket, Box<dyn std::error::Error>> {
let data_vec: Vec<u8> = data.to_vec();
match self.inner.encrypt_data_packet(participant_id.to_string(), key_index, data_vec) {
Ok(packet) => Ok(packet),
Err(e) => Err(format!("Encryption failed: {}", e).into()),
}
}
pub fn decrypt(
&self,
participant_id: &str,
encrypted_packet: &ffi::EncryptedPacket,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
match self.inner.decrypt_data_packet(participant_id.to_string(), encrypted_packet) {
Ok(data) => Ok(data.into_iter().collect()),
Err(e) => Err(format!("Decryption failed: {}", e).into()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_data_packet_cryptor_creation() {
let options = ffi::KeyProviderOptions {
shared_key: true,
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);
let _cryptor = DataPacketCryptor::new(ffi::Algorithm::AesGcm, key_provider);
}
}