use super::{SrtpAuthenticationAlgorithm, SrtpCryptoSuite, SrtpEncryptionAlgorithm};
use crate::error::Error;
use crate::packet::RtpPacket;
use crate::Result;
use aes::{
cipher::{generic_array::GenericArray, KeyIvInit, StreamCipher},
Aes128, Aes256,
};
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use bytes::{BufMut, Bytes, BytesMut};
use ctr::Ctr64BE;
use hmac::{Hmac, Mac};
use sha1::Sha1;
type Aes128Ctr64BE = Ctr64BE<Aes128>;
type Aes256Ctr64BE = Ctr64BE<Aes256>;
type HmacSha1 = Hmac<Sha1>;
#[derive(Debug, Clone)]
pub struct SrtpCryptoKey {
key: Vec<u8>,
salt: Vec<u8>,
}
impl SrtpCryptoKey {
pub fn new(key: Vec<u8>, salt: Vec<u8>) -> Self {
Self { key, salt }
}
pub fn key(&self) -> &[u8] {
&self.key
}
pub fn salt(&self) -> &[u8] {
&self.salt
}
pub fn from_base64(data: &str) -> Result<Self> {
let decoded = BASE64
.decode(data)
.map_err(|e| Error::SrtpError(format!("Failed to decode base64 key: {}", e)))?;
if decoded.len() < 16 {
return Err(Error::SrtpError("Key material too short".to_string()));
}
let key = decoded[0..16].to_vec();
let salt = if decoded.len() > 16 {
decoded[16..].to_vec()
} else {
Vec::new()
};
Ok(Self { key, salt })
}
}
pub struct SrtpCrypto {
suite: SrtpCryptoSuite,
master_key: SrtpCryptoKey,
session_keys: Option<SrtpSessionKeys>,
}
#[derive(Debug, Clone)]
struct SrtpSessionKeys {
rtp_enc_key: Vec<u8>,
rtp_auth_key: Vec<u8>,
rtp_salt: Vec<u8>,
rtcp_enc_key: Vec<u8>,
rtcp_auth_key: Vec<u8>,
rtcp_salt: Vec<u8>,
}
impl SrtpCrypto {
pub fn new(suite: SrtpCryptoSuite, master_key: SrtpCryptoKey) -> Result<Self> {
if master_key.key().len() != suite.key_length {
return Err(Error::SrtpError(format!(
"Key length mismatch: expected {} but got {}",
suite.key_length,
master_key.key().len()
)));
}
let mut crypto = Self {
suite,
master_key,
session_keys: None,
};
crypto.derive_keys()?;
Ok(crypto)
}
fn derive_keys(&mut self) -> Result<()> {
let rtp_enc_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtpEncryption,
key_derivation_rate: 0,
index: 0,
};
let rtp_enc_key =
super::srtp_kdf(&self.master_key, &rtp_enc_params, self.suite.key_length)?;
let rtp_auth_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtpAuthentication,
key_derivation_rate: 0,
index: 0,
};
let rtp_auth_key = super::srtp_kdf(&self.master_key, &rtp_auth_params, 20)?;
let rtp_salt_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtpSalt,
key_derivation_rate: 0,
index: 0,
};
let rtp_salt = super::srtp_kdf(&self.master_key, &rtp_salt_params, 14)?;
let rtcp_enc_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtcpEncryption,
key_derivation_rate: 0,
index: 0,
};
let rtcp_enc_key =
super::srtp_kdf(&self.master_key, &rtcp_enc_params, self.suite.key_length)?;
let rtcp_auth_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtcpAuthentication,
key_derivation_rate: 0,
index: 0,
};
let rtcp_auth_key = super::srtp_kdf(&self.master_key, &rtcp_auth_params, 20)?;
let rtcp_salt_params = super::SrtpKeyDerivationParams {
label: super::KeyDerivationLabel::RtcpSalt,
key_derivation_rate: 0,
index: 0,
};
let rtcp_salt = super::srtp_kdf(&self.master_key, &rtcp_salt_params, 14)?;
let session_keys = SrtpSessionKeys {
rtp_enc_key,
rtp_auth_key,
rtp_salt,
rtcp_enc_key,
rtcp_auth_key,
rtcp_salt,
};
self.session_keys = Some(session_keys);
Ok(())
}
pub fn encrypt_rtp(&self, packet: &RtpPacket) -> Result<(RtpPacket, Option<Vec<u8>>)> {
if self.suite.encryption == SrtpEncryptionAlgorithm::Null {
return if self.suite.authentication == SrtpAuthenticationAlgorithm::Null {
Ok((packet.clone(), None))
} else {
let serialized = packet.serialize()?;
let auth_tag = self.calculate_auth_tag(&serialized, 0)?;
Ok((packet.clone(), Some(auth_tag)))
};
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
let header = packet.header.clone();
let payload = packet.payload.clone();
let ssrc = packet.header.ssrc;
let sequence = packet.header.sequence_number as u64;
let roc: u32 = 0; let packet_index = (roc as u64) << 16 | sequence;
let iv = match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
super::create_srtp_iv(&session_keys.rtp_salt, ssrc, packet_index)?
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
};
let mut encrypted_payload = BytesMut::from(&payload[..]);
match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
aes_cm_encrypt(&mut encrypted_payload, &session_keys.rtp_enc_key, &iv)?;
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
}
let encrypted_packet = RtpPacket::new(header, encrypted_payload.freeze());
let auth_tag = if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
let encrypted_serialized = encrypted_packet.serialize()?;
let auth_tag = self.calculate_auth_tag(&encrypted_serialized, roc)?;
Some(auth_tag)
} else {
None
};
Ok((encrypted_packet, auth_tag))
}
fn calculate_auth_tag(&self, packet_data: &[u8], roc: u32) -> Result<Vec<u8>> {
if self.suite.authentication == SrtpAuthenticationAlgorithm::Null {
return Err(Error::SrtpError(
"Authentication is not enabled".to_string(),
));
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
let authenticator = super::auth::SrtpAuthenticator::new(
self.suite.authentication,
session_keys.rtp_auth_key.clone(),
self.suite.tag_length,
);
authenticator.calculate_auth_tag(packet_data, roc)
}
pub fn decrypt_rtp(&self, data: &[u8]) -> Result<RtpPacket> {
if self.suite.encryption == SrtpEncryptionAlgorithm::Null
&& self.suite.authentication == SrtpAuthenticationAlgorithm::Null
{
return RtpPacket::parse(data);
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
let auth_tag_size = if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
self.suite.tag_length
} else {
0
};
if auth_tag_size > 0 && data.len() < auth_tag_size {
return Err(Error::SrtpError(
"Packet too short to contain authentication tag".to_string(),
));
}
let (packet_data, auth_tag) = if auth_tag_size > 0 {
let tag_start = data.len() - auth_tag_size;
(&data[0..tag_start], &data[tag_start..])
} else {
(data, &[][..])
};
if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
let authenticator = super::auth::SrtpAuthenticator::new(
self.suite.authentication,
session_keys.rtp_auth_key.clone(),
self.suite.tag_length,
);
let roc: u32 = 0;
let is_valid = authenticator.verify_auth_tag(packet_data, auth_tag, roc)?;
if !is_valid {
return Err(Error::SrtpError("Authentication failed".to_string()));
}
}
let packet = RtpPacket::parse(packet_data)?;
if self.suite.encryption == SrtpEncryptionAlgorithm::Null {
return Ok(packet);
}
let ssrc = packet.header.ssrc;
let sequence = packet.header.sequence_number as u64;
let roc: u32 = 0; let packet_index = (roc as u64) << 16 | sequence;
let iv = match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
super::create_srtp_iv(&session_keys.rtp_salt, ssrc, packet_index)?
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
};
let mut decrypted_payload = BytesMut::from(&packet.payload[..]);
match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
aes_cm_decrypt(&mut decrypted_payload, &session_keys.rtp_enc_key, &iv)?;
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
}
let decrypted_packet = RtpPacket::new(packet.header, decrypted_payload.freeze());
Ok(decrypted_packet)
}
pub fn encrypt_rtcp(&self, data: &[u8]) -> Result<(Bytes, Option<Vec<u8>>)> {
if self.suite.encryption == SrtpEncryptionAlgorithm::Null {
return if self.suite.authentication == SrtpAuthenticationAlgorithm::Null {
Ok((Bytes::copy_from_slice(data), None))
} else {
let auth_tag = self.calculate_rtcp_auth_tag(data, 0)?;
Ok((Bytes::copy_from_slice(data), Some(auth_tag)))
};
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
if data.len() <= 8 {
return Err(Error::SrtpError("RTCP packet too short".to_string()));
}
let header = &data[0..8];
let payload = &data[8..];
let mut result = BytesMut::with_capacity(data.len() + 4);
result.extend_from_slice(header);
let mut encrypted_payload = BytesMut::from(payload);
let ssrc = 0u32; let index = 0u64;
let iv = match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
super::create_srtp_iv(&session_keys.rtcp_salt, ssrc, index)?
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
};
match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
aes_cm_encrypt(&mut encrypted_payload, &session_keys.rtcp_enc_key, &iv)?;
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
}
result.extend_from_slice(&encrypted_payload);
result.put_u32(0x80000000 | (index as u32));
let auth_tag = if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
let auth_tag = self.calculate_rtcp_auth_tag(&result, 0)?;
Some(auth_tag)
} else {
None
};
Ok((result.freeze(), auth_tag))
}
fn calculate_rtcp_auth_tag(&self, data: &[u8], _index: u32) -> Result<Vec<u8>> {
if self.suite.authentication == SrtpAuthenticationAlgorithm::Null {
return Err(Error::SrtpError(
"Authentication is not enabled".to_string(),
));
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
let tag = hmac_sha1(data, &session_keys.rtcp_auth_key, self.suite.tag_length)?;
Ok(tag)
}
pub fn decrypt_rtcp(&self, data: &[u8]) -> Result<Bytes> {
if self.suite.encryption == SrtpEncryptionAlgorithm::Null
&& self.suite.authentication == SrtpAuthenticationAlgorithm::Null
{
return Ok(Bytes::copy_from_slice(data));
}
let session_keys = self
.session_keys
.as_ref()
.ok_or_else(|| Error::SrtpError("Session keys not derived".to_string()))?;
let min_len = 8
+ 4
+ (if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
self.suite.tag_length
} else {
0
});
if data.len() < min_len {
return Err(Error::SrtpError(format!(
"SRTCP packet too short: {} bytes",
data.len()
)));
}
let auth_tag_pos = data.len() - self.suite.tag_length;
if self.suite.authentication != SrtpAuthenticationAlgorithm::Null {
let packet_data = &data[0..auth_tag_pos];
let auth_tag = &data[auth_tag_pos..];
let calculated_tag = self.calculate_rtcp_auth_tag(packet_data, 0)?;
let mut result = 0;
if calculated_tag.len() != auth_tag.len() {
return Err(Error::SrtpError(
"Authentication tag length mismatch".to_string(),
));
}
for (a, b) in calculated_tag.iter().zip(auth_tag.iter()) {
result |= a ^ b;
}
if result != 0 {
return Err(Error::SrtpError("SRTCP authentication failed".to_string()));
}
}
let index_pos = auth_tag_pos - 4;
let index_bytes = [
data[index_pos],
data[index_pos + 1],
data[index_pos + 2],
data[index_pos + 3],
];
let index_value = u32::from_be_bytes(index_bytes);
let e_flag = (index_value & 0x80000000) != 0;
let index = index_value & 0x7FFFFFFF;
if !e_flag {
let mut result = BytesMut::with_capacity(index_pos);
result.extend_from_slice(&data[0..index_pos]);
return Ok(result.freeze());
}
let header = &data[0..8];
let payload = &data[8..index_pos];
let mut result = BytesMut::with_capacity(index_pos);
result.extend_from_slice(header);
let mut decrypted_payload = BytesMut::from(payload);
let ssrc = 0u32;
let iv = match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
super::create_srtp_iv(&session_keys.rtcp_salt, ssrc, index as u64)?
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
};
match self.suite.encryption {
SrtpEncryptionAlgorithm::AesCm => {
aes_cm_decrypt(&mut decrypted_payload, &session_keys.rtcp_enc_key, &iv)?;
}
_ => {
return Err(Error::SrtpError(
"Unsupported encryption algorithm".to_string(),
))
}
}
result.extend_from_slice(&decrypted_payload);
Ok(result.freeze())
}
}
fn aes_cm_encrypt(data: &mut [u8], key: &[u8], iv: &[u8]) -> Result<()> {
if iv.len() < 16 {
return Err(Error::SrtpError(format!(
"AES-CM IV too short: expected 16 bytes, got {}",
iv.len()
)));
}
let iv = GenericArray::from_slice(&iv[0..16]);
match key.len() {
16 => {
let key = GenericArray::from_slice(key);
let mut cipher = Aes128Ctr64BE::new(key, iv);
cipher.apply_keystream(data);
}
32 => {
let key = GenericArray::from_slice(key);
let mut cipher = Aes256Ctr64BE::new(key, iv);
cipher.apply_keystream(data);
}
len => {
return Err(Error::SrtpError(format!(
"unsupported AES-CM key length: {} bytes",
len
)));
}
}
Ok(())
}
fn aes_cm_decrypt(data: &mut [u8], key: &[u8], iv: &[u8]) -> Result<()> {
aes_cm_encrypt(data, key, iv)
}
fn hmac_sha1(data: &[u8], key: &[u8], tag_length: usize) -> Result<Vec<u8>> {
let mut mac = HmacSha1::new_from_slice(key)
.map_err(|e| Error::SrtpError(format!("Failed to create HMAC: {}", e)))?;
mac.update(data);
let result = mac.finalize().into_bytes();
let tag = result.as_slice()[..tag_length].to_vec();
Ok(tag)
}
#[cfg(test)]
mod tests {
use super::*;
fn hex_bytes(hex: &str) -> Vec<u8> {
assert_eq!(hex.len() % 2, 0);
(0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap())
.collect()
}
#[test]
fn test_srtp_key_from_base64() {
let base64_key = "YUJjRGVGZ0hpSmtMbU5vUHFSc1R1Vndv";
let key = SrtpCryptoKey::from_base64(base64_key);
assert!(key.is_ok());
let key = key.unwrap();
assert_eq!(key.key().len(), 16);
let invalid_key = "invalid-base64!";
let key = SrtpCryptoKey::from_base64(invalid_key);
assert!(key.is_err());
}
#[test]
fn test_null_encryption() {
let key = SrtpCryptoKey::new(vec![0; 16], vec![0; 14]);
let null_suite = SrtpCryptoSuite {
encryption: SrtpEncryptionAlgorithm::Null,
authentication: SrtpAuthenticationAlgorithm::Null,
key_length: 16, tag_length: 0,
};
let crypto = SrtpCrypto::new(null_suite, key).unwrap();
let header = crate::packet::RtpHeader::new(96, 1000, 12345, 0xabcdef01);
let payload = Bytes::from_static(b"test payload");
let packet = RtpPacket::new(header, payload);
let encrypted_result = crypto.encrypt_rtp(&packet);
assert!(encrypted_result.is_ok());
let (encrypted, _auth_tag) = encrypted_result.unwrap();
assert_eq!(encrypted.header.payload_type, packet.header.payload_type);
assert_eq!(
encrypted.header.sequence_number,
packet.header.sequence_number
);
assert_eq!(encrypted.header.timestamp, packet.header.timestamp);
assert_eq!(encrypted.header.ssrc, packet.header.ssrc);
assert_eq!(encrypted.payload, packet.payload);
}
#[test]
fn test_aes_cm_encryption() {
let mut data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let key = vec![0; 16]; let iv = vec![0; 16];
let result = aes_cm_encrypt(&mut data, &key, &iv);
assert!(result.is_ok());
assert_ne!(data, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let _encrypted = data.clone();
let result = aes_cm_decrypt(&mut data, &key, &iv);
assert!(result.is_ok());
assert_eq!(data, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn test_rfc3711_appendix_b2_aes_cm_vector() {
let key = hex_bytes("2B7E151628AED2A6ABF7158809CF4F3C");
let iv = hex_bytes("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0000");
let mut data = vec![0u8; 16];
aes_cm_encrypt(&mut data, &key, &iv).unwrap();
assert_eq!(data, hex_bytes("E03EAD0935C95E80E166B16DD92B4EB4"));
}
#[test]
fn test_hmac_sha1() {
let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let key = vec![0; 20];
let tag = hmac_sha1(&data, &key, 10);
assert!(tag.is_ok());
let tag = tag.unwrap();
assert_eq!(tag.len(), 10);
let tag32 = hmac_sha1(&data, &key, 4);
assert!(tag32.is_ok());
let tag32 = tag32.unwrap();
assert_eq!(tag32.len(), 4);
assert_eq!(tag[0..4], tag32[0..4]);
}
#[test]
fn test_complete_srtp_process() {
let master_key = vec![
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10,
];
let master_salt = vec![
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
];
let srtp_key = SrtpCryptoKey::new(master_key, master_salt);
let suites = vec![
super::super::SRTP_AES128_CM_SHA1_80,
super::super::SRTP_AES128_CM_SHA1_32,
];
for suite in suites {
let crypto = SrtpCrypto::new(suite.clone(), srtp_key.clone()).unwrap();
let header = crate::packet::RtpHeader::new(96, 1000, 12345, 0xabcdef01);
let payload = Bytes::from_static(
b"Hello SRTP World! This is a test of SRTP encryption and decryption.",
);
let packet = RtpPacket::new(header, payload);
let encrypted_result = crypto.encrypt_rtp(&packet).unwrap();
let (encrypted_packet, auth_tag) = encrypted_result;
assert_ne!(encrypted_packet.payload, packet.payload);
assert_eq!(
encrypted_packet.header.payload_type,
packet.header.payload_type
);
assert_eq!(
encrypted_packet.header.sequence_number,
packet.header.sequence_number
);
assert_eq!(encrypted_packet.header.timestamp, packet.header.timestamp);
assert_eq!(encrypted_packet.header.ssrc, packet.header.ssrc);
let serialized = encrypted_packet.serialize().unwrap();
let mut protected_data = BytesMut::with_capacity(serialized.len() + 10);
protected_data.extend_from_slice(&serialized);
if let Some(tag) = auth_tag {
protected_data.extend_from_slice(&tag);
}
let decrypted = crypto.decrypt_rtp(&protected_data);
assert!(decrypted.is_ok());
let decrypted = decrypted.unwrap();
assert_eq!(decrypted.header.payload_type, packet.header.payload_type);
assert_eq!(
decrypted.header.sequence_number,
packet.header.sequence_number
);
assert_eq!(decrypted.header.timestamp, packet.header.timestamp);
assert_eq!(decrypted.header.ssrc, packet.header.ssrc);
assert_eq!(decrypted.payload, packet.payload);
}
}
#[test]
fn test_complete_srtp_process_aes256() {
let master_key: Vec<u8> = (1..=32).collect();
let master_salt = vec![
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,
];
let srtp_key = SrtpCryptoKey::new(master_key, master_salt);
let suites = vec![
super::super::SRTP_AES256_CM_SHA1_80,
super::super::SRTP_AES256_CM_SHA1_32,
];
for suite in suites {
let crypto = SrtpCrypto::new(suite.clone(), srtp_key.clone()).unwrap();
let header = crate::packet::RtpHeader::new(96, 1000, 12345, 0xabcdef01);
let payload = Bytes::from_static(b"Hello AES-256 SRTP World");
let packet = RtpPacket::new(header, payload);
let (encrypted_packet, auth_tag) = crypto.encrypt_rtp(&packet).unwrap();
assert_ne!(encrypted_packet.payload, packet.payload);
let serialized = encrypted_packet.serialize().unwrap();
let mut protected_data = BytesMut::with_capacity(serialized.len() + suite.tag_length);
protected_data.extend_from_slice(&serialized);
let tag = auth_tag.expect("AES-256 SRTP suites authenticate RTP");
assert_eq!(tag.len(), suite.tag_length);
protected_data.extend_from_slice(&tag);
let decrypted = crypto.decrypt_rtp(&protected_data).unwrap();
assert_eq!(decrypted.header.payload_type, packet.header.payload_type);
assert_eq!(
decrypted.header.sequence_number,
packet.header.sequence_number
);
assert_eq!(decrypted.header.timestamp, packet.header.timestamp);
assert_eq!(decrypted.header.ssrc, packet.header.ssrc);
assert_eq!(decrypted.payload, packet.payload);
}
}
#[test]
fn test_tamper_detection() {
let master_key = vec![
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10,
];
let master_salt = vec![
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
];
let srtp_key = SrtpCryptoKey::new(master_key, master_salt);
let crypto = SrtpCrypto::new(super::super::SRTP_AES128_CM_SHA1_80, srtp_key).unwrap();
let header = crate::packet::RtpHeader::new(96, 1000, 12345, 0xabcdef01);
let payload = Bytes::from_static(b"Protected data");
let packet = RtpPacket::new(header, payload);
let encrypted_result = crypto.encrypt_rtp(&packet).unwrap();
let (encrypted_packet, auth_tag) = encrypted_result;
assert!(auth_tag.is_some());
let auth_tag_clone = auth_tag.clone();
let serialized = encrypted_packet.serialize().unwrap();
let mut protected_data = BytesMut::with_capacity(serialized.len() + 10);
protected_data.extend_from_slice(&serialized);
if let Some(tag) = auth_tag {
protected_data.extend_from_slice(&tag);
}
let protected_data = protected_data.freeze();
let decrypted = crypto.decrypt_rtp(&protected_data);
assert!(decrypted.is_ok());
let _tampered_size = protected_data.len();
let mut tampered = protected_data.to_vec();
let middle = tampered.len() / 2;
tampered[middle] ^= 0xFF;
let decrypted = crypto.decrypt_rtp(&tampered);
assert!(decrypted.is_err());
let mut tampered = protected_data.to_vec();
if let Some(_tag) = auth_tag_clone {
let tag_idx = tampered.len() - 1;
let tag_value = tampered[tag_idx];
tampered[tag_idx] = tag_value ^ 0xFF;
let decrypted = crypto.decrypt_rtp(&tampered);
assert!(decrypted.is_err());
}
}
}