use rvoip_rtp_core::{
api::common::frame::{MediaFrame, MediaFrameType},
packet::{RtpHeader, RtpPacket},
srtp::{SrtpContext, SrtpCryptoKey, SRTP_AES128_CM_SHA1_80},
};
use bytes::Bytes;
use std::time::Duration;
use tracing::{error, info};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();
info!("🔐 Simplified SRTP Security Example");
info!("===================================");
info!("Demonstrating SRTP encryption/decryption without transport complexity");
info!("");
info!("Step 1: Setting up SRTP security context...");
let key_data = vec![
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10,
];
let salt_data = vec![
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
];
let crypto_key = SrtpCryptoKey::new(key_data.clone(), salt_data.clone());
let mut combined = Vec::with_capacity(key_data.len() + salt_data.len());
combined.extend_from_slice(&key_data);
combined.extend_from_slice(&salt_data);
let base64_key = base64::encode(&combined);
info!("✅ SRTP crypto suite: AES_CM_128_HMAC_SHA1_80");
info!("✅ SRTP key+salt (base64): {}", base64_key);
info!(
"✅ SDP crypto line: 1 AES_CM_128_HMAC_SHA1_80 inline:{}",
base64_key
);
info!("");
info!("Step 2: Creating SRTP encryption contexts...");
let mut sender_context = SrtpContext::new(SRTP_AES128_CM_SHA1_80, crypto_key.clone())
.map_err(|e| format!("Failed to create sender SRTP context: {}", e))?;
let mut receiver_context = SrtpContext::new(SRTP_AES128_CM_SHA1_80, crypto_key.clone())
.map_err(|e| format!("Failed to create receiver SRTP context: {}", e))?;
info!("✅ Sender SRTP context created");
info!("✅ Receiver SRTP context created");
info!("");
info!("Step 3: Testing SRTP encryption and decryption...");
info!("");
for i in 0..3 {
let test_message = format!("🎵 Secure audio frame #{}", i);
let rtp_header = RtpHeader::new(
0, i as u16, i * 160, 0x1234ABCD, );
let payload = Bytes::from(test_message.clone().into_bytes());
let rtp_packet = RtpPacket::new(rtp_header, payload);
info!("🔤 Original message {}: '{}'", i, test_message);
info!(
"📦 RTP packet size: {} bytes",
rtp_packet.serialize()?.len()
);
let protected_packet = sender_context
.protect(&rtp_packet)
.map_err(|e| format!("Failed to encrypt RTP packet: {}", e))?;
let protected_bytes = protected_packet
.serialize()
.map_err(|e| format!("Failed to serialize protected packet: {}", e))?;
info!("🔒 Encrypted packet size: {} bytes", protected_bytes.len());
let preview: String = protected_bytes
.iter()
.take(16)
.map(|b| format!("{:02x}", b))
.collect::<Vec<String>>()
.join(" ");
info!("🔐 Encrypted preview: {} ...", preview);
let decrypted_packet = receiver_context
.unprotect(&protected_bytes)
.map_err(|e| format!("Failed to decrypt SRTP packet: {}", e))?;
let decrypted_message = String::from_utf8_lossy(&decrypted_packet.payload);
info!("🔓 Decrypted message: '{}'", decrypted_message);
if decrypted_message == test_message {
info!("✅ Encryption/Decryption SUCCESS - Messages match!");
} else {
error!("❌ Encryption/Decryption FAILED - Messages don't match!");
return Err("SRTP test failed".into());
}
info!("");
tokio::time::sleep(Duration::from_millis(100)).await;
}
info!("Step 4: Testing MediaFrame-level security...");
info!("");
let media_frame = MediaFrame {
frame_type: MediaFrameType::Audio,
data: "🎤 Secure voice data".as_bytes().to_vec().into(),
timestamp: 3200, sequence: 3,
marker: true,
payload_type: 0, ssrc: 0x1234ABCD,
csrcs: Vec::new(),
};
info!("📢 Original MediaFrame: {} bytes", media_frame.data.len());
info!(
"🔤 Frame data: '{}'",
String::from_utf8_lossy(&media_frame.data)
);
let frame_header = RtpHeader::new(
media_frame.payload_type,
media_frame.sequence,
media_frame.timestamp,
media_frame.ssrc,
);
let frame_payload = Bytes::from(media_frame.data.clone());
let frame_packet = RtpPacket::new(frame_header, frame_payload);
let protected_frame = sender_context
.protect(&frame_packet)
.map_err(|e| format!("Failed to encrypt MediaFrame: {}", e))?;
let protected_frame_bytes = protected_frame
.serialize()
.map_err(|e| format!("Failed to serialize protected MediaFrame: {}", e))?;
info!(
"🔒 Encrypted MediaFrame: {} bytes",
protected_frame_bytes.len()
);
let decrypted_frame_packet = receiver_context
.unprotect(&protected_frame_bytes)
.map_err(|e| format!("Failed to decrypt MediaFrame: {}", e))?;
let decrypted_frame_message = String::from_utf8_lossy(&decrypted_frame_packet.payload);
info!("🔓 Decrypted MediaFrame: '{}'", decrypted_frame_message);
if decrypted_frame_packet.payload.to_vec() == media_frame.data {
info!("✅ MediaFrame encryption/decryption SUCCESS!");
} else {
error!("❌ MediaFrame encryption/decryption FAILED!");
return Err("MediaFrame SRTP test failed".into());
}
info!("");
info!("🎉 SRTP Security Example Completed Successfully!");
info!("============================================");
info!("✅ SRTP contexts created and initialized");
info!("✅ RTP packet encryption/decryption working");
info!("✅ MediaFrame security integration working");
info!("✅ AES-128 encryption with HMAC-SHA1 authentication");
info!("✅ Ready for SIP/SDP integration with crypto lines");
info!("");
info!("🔧 Next steps:");
info!(" • Integrate with SDP crypto attribute parsing");
info!(" • Add key exchange protocols (SDES, MIKEY, ZRTP)");
info!(" • Enable full transport layer with DTLS-SRTP");
Ok(())
}