use crate::error::Error;
use crate::Result;
use crate::packet::RtpPacket;
use super::crypto::SrtpCryptoKey;
use aes::{Aes128, cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray}};
#[derive(Debug, Clone)]
pub struct SrtpKeyDerivationParams {
pub label: KeyDerivationLabel,
pub key_derivation_rate: u64,
pub index: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyDerivationLabel {
RtpEncryption = 0,
RtpAuthentication = 1,
RtpSalt = 2,
RtcpEncryption = 3,
RtcpAuthentication = 4,
RtcpSalt = 5,
}
pub fn srtp_kdf(
master_key: &SrtpCryptoKey,
params: &SrtpKeyDerivationParams,
output_len: usize,
) -> Result<Vec<u8>> {
let mut iv = Vec::with_capacity(16);
if master_key.salt().len() < 14 {
return Err(Error::SrtpError(format!(
"Salt too short: expected at least 14 bytes, got {}",
master_key.salt().len()
)));
}
iv.extend_from_slice(&master_key.salt()[0..14]);
iv.push(0x00);
iv.push(params.label as u8);
let num_blocks = (output_len + 15) / 16;
let mut key_material = Vec::with_capacity(num_blocks * 16);
let cipher = Aes128::new_from_slice(master_key.key())
.map_err(|e| Error::SrtpError(format!("Failed to create AES cipher: {}", e)))?;
for i in 0..num_blocks {
iv[14] = ((i >> 8) & 0xFF) as u8;
iv[15] = (i & 0xFF) as u8;
let mut block = GenericArray::clone_from_slice(&iv);
cipher.encrypt_block(&mut block);
key_material.extend_from_slice(&block);
}
key_material.truncate(output_len);
Ok(key_material)
}
pub fn create_srtp_iv(salt: &[u8], ssrc: u32, packet_index: u64) -> Result<Vec<u8>> {
if salt.len() < 14 {
return Err(Error::SrtpError(
format!("Salt too short: expected at least 14 bytes, got {}", salt.len())
));
}
let mut iv = Vec::with_capacity(16);
iv.extend_from_slice(&salt[0..14]);
iv.push(0);
iv.push(0);
iv[4] ^= ((ssrc >> 24) & 0xFF) as u8;
iv[5] ^= ((ssrc >> 16) & 0xFF) as u8;
iv[6] ^= ((ssrc >> 8) & 0xFF) as u8;
iv[7] ^= (ssrc & 0xFF) as u8;
iv[8] ^= ((packet_index >> 40) & 0xFF) as u8;
iv[9] ^= ((packet_index >> 32) & 0xFF) as u8;
iv[10] ^= ((packet_index >> 24) & 0xFF) as u8;
iv[11] ^= ((packet_index >> 16) & 0xFF) as u8;
iv[12] ^= ((packet_index >> 8) & 0xFF) as u8;
iv[13] ^= (packet_index & 0xFF) as u8;
Ok(iv)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyRotationFrequency {
None,
Power2(u8),
}
impl KeyRotationFrequency {
pub fn should_rotate(&self, packet_index: u64) -> bool {
match self {
Self::None => false,
Self::Power2(power) => {
let mask = (1u64 << power) - 1;
(packet_index & mask) == 0
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_rotation_frequency() {
let freq = KeyRotationFrequency::None;
assert!(!freq.should_rotate(0));
assert!(!freq.should_rotate(1000));
let freq = KeyRotationFrequency::Power2(8);
assert!(freq.should_rotate(0));
assert!(!freq.should_rotate(1));
assert!(!freq.should_rotate(255));
assert!(freq.should_rotate(256));
assert!(!freq.should_rotate(257));
assert!(freq.should_rotate(512));
}
#[test]
fn test_srtp_kdf() {
let master_key = SrtpCryptoKey::new(vec![0; 16], vec![0; 14]);
let params = SrtpKeyDerivationParams {
label: KeyDerivationLabel::RtpEncryption,
key_derivation_rate: 0,
index: 0,
};
let result = srtp_kdf(&master_key, ¶ms, 16);
assert!(result.is_ok());
let key = result.unwrap();
assert_eq!(key.len(), 16);
let params2 = SrtpKeyDerivationParams {
label: KeyDerivationLabel::RtpAuthentication,
key_derivation_rate: 0,
index: 0,
};
let key2 = srtp_kdf(&master_key, ¶ms2, 16).unwrap();
let different_key = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10];
assert_ne!(key, different_key);
}
#[test]
fn test_create_srtp_iv() {
let salt = vec![0; 14];
let result = create_srtp_iv(&salt, 0x12345678, 1000);
assert!(result.is_ok());
let iv = result.unwrap();
assert_eq!(iv.len(), 16);
assert_eq!(iv[4], 0x12); assert_eq!(iv[5], 0x34); assert_eq!(iv[6], 0x56); assert_eq!(iv[7], 0x78);
assert_eq!(iv[12], 0x03); assert_eq!(iv[13], 0xE8);
let short_salt = vec![0; 8];
let result = create_srtp_iv(&short_salt, 0x12345678, 1000);
assert!(result.is_err());
}
#[test]
fn test_kdf_with_different_output_sizes() {
let master_key = SrtpCryptoKey::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
vec![21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]);
let params = SrtpKeyDerivationParams {
label: KeyDerivationLabel::RtpEncryption,
key_derivation_rate: 0,
index: 0,
};
let key16 = srtp_kdf(&master_key, ¶ms, 16).unwrap();
assert_eq!(key16.len(), 16);
let key20 = srtp_kdf(&master_key, ¶ms, 20).unwrap();
assert_eq!(key20.len(), 20);
let key32 = srtp_kdf(&master_key, ¶ms, 32).unwrap();
assert_eq!(key32.len(), 32);
assert_eq!(key16, key20[0..16]);
assert_eq!(key16, key32[0..16]);
}
}