livekit_datatrack/e2ee.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 bytes::Bytes;
16use core::fmt::Debug;
17use thiserror::Error;
18
19// TODO: If a core module for end-to-end encryption is created in the future
20// (livekit-e2ee), these traits should be moved to there.
21
22/// Twelve byte AES initialization vector (IV).
23pub type InitializationVector = [u8; 12];
24
25/// Encrypted payload and metadata required for decryption.
26#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
27pub struct EncryptedPayload {
28 pub payload: Bytes,
29 pub iv: InitializationVector,
30 pub key_index: u8,
31}
32
33/// An error indicating a payload could not be encrypted.
34#[derive(Debug, Error)]
35#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
36#[cfg_attr(feature = "uniffi", uniffi(flat_error))]
37pub enum EncryptionError {
38 #[error("Encryption failed")]
39 Failed,
40}
41
42/// An error indicating a payload could not be decrypted.
43#[derive(Debug, Error)]
44#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
45#[cfg_attr(feature = "uniffi", uniffi(flat_error))]
46pub enum DecryptionError {
47 #[error("Decryption failed")]
48 Failed,
49}
50
51/// Provider for encrypting payloads for E2EE.
52#[cfg_attr(feature = "uniffi", uniffi::export(with_foreign))]
53pub trait EncryptionProvider: Send + Sync + Debug {
54 /// Encrypts the given payload being sent by the local participant.
55 fn encrypt(&self, payload: Bytes) -> Result<EncryptedPayload, EncryptionError>;
56}
57
58/// Provider for decrypting payloads for E2EE.
59#[cfg_attr(feature = "uniffi", uniffi::export(with_foreign))]
60pub trait DecryptionProvider: Send + Sync + Debug {
61 /// Decrypts the given payload received from a remote participant.
62 ///
63 /// Sender identity is required in order for the proper key to be used
64 /// for decryption.
65 ///
66 fn decrypt(
67 &self,
68 payload: EncryptedPayload,
69 sender_identity: String,
70 ) -> Result<Bytes, DecryptionError>;
71
72 // TODO: the above method previously took &str for sender_identity but has
73 // been modified to accept String so it can be exported for UniFFI. However,
74 // this results in an unnecessary heap allocation when used in a Rust-only context.
75 // Find a better solution for this.
76}
77
78#[cfg(feature = "uniffi")]
79uniffi::custom_type!(Bytes, Vec<u8>, { remote });
80
81#[cfg(feature = "uniffi")]
82uniffi::custom_type!(InitializationVector, Vec<u8>, {
83 remote,
84 lower: |iv| iv.to_vec(),
85 try_lift: |v| v.try_into()
86 .map_err(|_| uniffi::deps::anyhow::anyhow!("IV must be exactly 12 bytes"))
87});