diff --git a/rtc-srtp/src/cipher/cipher_aead_aes_gcm.rs b/rtc-srtp/src/cipher/cipher_aead_aes_gcm.rs index 8555b52..2935d40 100644 --- a/rtc-srtp/src/cipher/cipher_aead_aes_gcm.rs +++ b/rtc-srtp/src/cipher/cipher_aead_aes_gcm.rs @@ -7,6 +7,7 @@ use bytes::BytesMut; use super::Cipher; use crate::key_derivation::*; +use crate::protection_profile::ProtectionProfile; use shared::{ error::{Error, Result}, marshal::*, @@ -18,6 +19,7 @@ const RTCP_ENCRYPTION_FLAG: u8 = 0x80; /// AEAD Cipher based on AES. pub(crate) struct CipherAeadAesGcm { + profile: ProtectionProfile, srtp_cipher: aes_gcm::Aes128Gcm, srtcp_cipher: aes_gcm::Aes128Gcm, srtp_session_salt: Vec, @@ -25,8 +27,19 @@ pub(crate) struct CipherAeadAesGcm { } impl Cipher for CipherAeadAesGcm { - fn auth_tag_len(&self) -> usize { - CIPHER_AEAD_AES_GCM_AUTH_TAG_LEN + /// Get RTP authenticated tag length. + fn rtp_auth_tag_len(&self) -> usize { + self.profile.rtp_auth_tag_len() + } + + /// Get RTCP authenticated tag length. + fn rtcp_auth_tag_len(&self) -> usize { + self.profile.rtcp_auth_tag_len() + } + + /// Get AEAD auth key length of the cipher. + fn aead_auth_tag_len(&self) -> usize { + self.profile.aead_auth_tag_len() } fn encrypt_rtp( @@ -36,8 +49,9 @@ impl Cipher for CipherAeadAesGcm { roc: u32, ) -> Result { // Grow the given buffer to fit the output. - let mut writer = - BytesMut::with_capacity(header.marshal_size() + payload.len() + self.auth_tag_len()); + let mut writer = BytesMut::with_capacity( + header.marshal_size() + payload.len() + self.aead_auth_tag_len(), + ); let data = header.marshal()?; writer.extend(data); @@ -62,7 +76,7 @@ impl Cipher for CipherAeadAesGcm { header: &rtp::header::Header, roc: u32, ) -> Result { - if ciphertext.len() < self.auth_tag_len() { + if ciphertext.len() < self.aead_auth_tag_len() { return Err(Error::ErrFailedToVerifyAuthTag); } @@ -114,7 +128,7 @@ impl Cipher for CipherAeadAesGcm { srtcp_index: usize, ssrc: u32, ) -> Result { - if encrypted.len() < self.auth_tag_len() + SRTCP_INDEX_SIZE { + if encrypted.len() < self.aead_auth_tag_len() + SRTCP_INDEX_SIZE { return Err(Error::ErrFailedToVerifyAuthTag); } @@ -146,7 +160,11 @@ impl Cipher for CipherAeadAesGcm { impl CipherAeadAesGcm { /// Create a new AEAD instance. - pub(crate) fn new(master_key: &[u8], master_salt: &[u8]) -> Result { + pub(crate) fn new( + profile: ProtectionProfile, + master_key: &[u8], + master_salt: &[u8], + ) -> Result { let srtp_session_key = aes_cm_key_derivation( LABEL_SRTP_ENCRYPTION, master_key, @@ -188,6 +206,7 @@ impl CipherAeadAesGcm { )?; Ok(CipherAeadAesGcm { + profile, srtp_cipher, srtcp_cipher, srtp_session_salt, diff --git a/rtc-srtp/src/cipher/cipher_aes_cm_hmac_sha1.rs b/rtc-srtp/src/cipher/cipher_aes_cm_hmac_sha1.rs index 8e240db..5df6579 100644 --- a/rtc-srtp/src/cipher/cipher_aes_cm_hmac_sha1.rs +++ b/rtc-srtp/src/cipher/cipher_aes_cm_hmac_sha1.rs @@ -22,6 +22,7 @@ type Aes128Ctr = ctr::Ctr128BE; pub const CIPHER_AES_CM_HMAC_SHA1AUTH_TAG_LEN: usize = 10; pub(crate) struct CipherAesCmHmacSha1 { + profile: ProtectionProfile, srtp_session_key: Vec, srtp_session_salt: Vec, srtp_session_auth: HmacSha1, @@ -33,7 +34,7 @@ pub(crate) struct CipherAesCmHmacSha1 { } impl CipherAesCmHmacSha1 { - pub fn new(master_key: &[u8], master_salt: &[u8]) -> Result { + pub fn new(profile: ProtectionProfile, master_key: &[u8], master_salt: &[u8]) -> Result { let srtp_session_key = aes_cm_key_derivation( LABEL_SRTP_ENCRYPTION, master_key, @@ -87,6 +88,7 @@ impl CipherAesCmHmacSha1 { .map_err(|e| Error::Other(e.to_string()))?; Ok(CipherAesCmHmacSha1 { + profile, srtp_session_key, srtp_session_salt, srtp_session_auth, @@ -130,7 +132,7 @@ impl CipherAesCmHmacSha1 { let code_bytes = result.into_bytes(); // Truncate the hash to the first AUTH_TAG_SIZE bytes. - Ok(code_bytes[0..self.auth_tag_len()].to_vec()) + Ok(code_bytes[0..self.rtp_auth_tag_len()].to_vec()) } /// https://tools.ietf.org/html/rfc3711#section-4.2 @@ -153,17 +155,28 @@ impl CipherAesCmHmacSha1 { let code_bytes = result.into_bytes(); // Truncate the hash to the first AUTH_TAG_SIZE bytes. - code_bytes[0..self.auth_tag_len()].to_vec() + code_bytes[0..self.rtcp_auth_tag_len()].to_vec() } } impl Cipher for CipherAesCmHmacSha1 { - fn auth_tag_len(&self) -> usize { - CIPHER_AES_CM_HMAC_SHA1AUTH_TAG_LEN + /// Get RTP authenticated tag length. + fn rtp_auth_tag_len(&self) -> usize { + self.profile.rtp_auth_tag_len() + } + + /// Get RTCP authenticated tag length. + fn rtcp_auth_tag_len(&self) -> usize { + self.profile.rtcp_auth_tag_len() + } + + /// Get AEAD auth key length of the cipher. + fn aead_auth_tag_len(&self) -> usize { + self.profile.aead_auth_tag_len() } fn get_rtcp_index(&self, input: &[u8]) -> usize { - let tail_offset = input.len() - (self.auth_tag_len() + SRTCP_INDEX_SIZE); + let tail_offset = input.len() - (self.rtcp_auth_tag_len() + SRTCP_INDEX_SIZE); (BigEndian::read_u32(&input[tail_offset..tail_offset + SRTCP_INDEX_SIZE]) & !(1 << 31)) as usize } @@ -174,8 +187,9 @@ impl Cipher for CipherAesCmHmacSha1 { header: &rtp::header::Header, roc: u32, ) -> Result { - let mut writer = - BytesMut::with_capacity(header.marshal_size() + payload.len() + self.auth_tag_len()); + let mut writer = BytesMut::with_capacity( + header.marshal_size() + payload.len() + self.rtp_auth_tag_len(), + ); // Copy the header unencrypted. let data = header.marshal()?; @@ -210,15 +224,18 @@ impl Cipher for CipherAesCmHmacSha1 { header: &rtp::header::Header, roc: u32, ) -> Result { - if encrypted.len() < self.auth_tag_len() { - return Err(Error::SrtpTooSmall(encrypted.len(), self.auth_tag_len())); + if encrypted.len() < self.rtp_auth_tag_len() { + return Err(Error::SrtpTooSmall( + encrypted.len(), + self.rtp_auth_tag_len(), + )); } - let mut writer = BytesMut::with_capacity(encrypted.len() - self.auth_tag_len()); + let mut writer = BytesMut::with_capacity(encrypted.len() - self.rtp_auth_tag_len()); // Split the auth tag and the cipher text into two parts. - let actual_tag = &encrypted[encrypted.len() - self.auth_tag_len()..]; - let cipher_text = &encrypted[..encrypted.len() - self.auth_tag_len()]; + let actual_tag = &encrypted[encrypted.len() - self.rtp_auth_tag_len()..]; + let cipher_text = &encrypted[..encrypted.len() - self.rtp_auth_tag_len()]; // Generate the auth tag we expect to see from the ciphertext. let expected_tag = self.generate_srtp_auth_tag(cipher_text, roc)?; @@ -257,7 +274,7 @@ impl Cipher for CipherAesCmHmacSha1 { ssrc: u32, ) -> Result { let mut writer = - BytesMut::with_capacity(decrypted.len() + SRTCP_INDEX_SIZE + self.auth_tag_len()); + BytesMut::with_capacity(decrypted.len() + SRTCP_INDEX_SIZE + self.rtcp_auth_tag_len()); // Write the decrypted to the destination buffer. writer.extend_from_slice(decrypted); @@ -294,14 +311,14 @@ impl Cipher for CipherAesCmHmacSha1 { srtcp_index: usize, ssrc: u32, ) -> Result { - if encrypted.len() < self.auth_tag_len() + SRTCP_INDEX_SIZE { + if encrypted.len() < self.rtcp_auth_tag_len() + SRTCP_INDEX_SIZE { return Err(Error::SrtcpTooSmall( encrypted.len(), - self.auth_tag_len() + SRTCP_INDEX_SIZE, + self.rtcp_auth_tag_len() + SRTCP_INDEX_SIZE, )); } - let tail_offset = encrypted.len() - (self.auth_tag_len() + SRTCP_INDEX_SIZE); + let tail_offset = encrypted.len() - (self.rtcp_auth_tag_len() + SRTCP_INDEX_SIZE); let mut writer = BytesMut::with_capacity(tail_offset); @@ -313,8 +330,8 @@ impl Cipher for CipherAesCmHmacSha1 { } // Split the auth tag and the cipher text into two parts. - let actual_tag = &encrypted[encrypted.len() - self.auth_tag_len()..]; - let cipher_text = &encrypted[..encrypted.len() - self.auth_tag_len()]; + let actual_tag = &encrypted[encrypted.len() - self.rtcp_auth_tag_len()..]; + let cipher_text = &encrypted[..encrypted.len() - self.rtcp_auth_tag_len()]; // Generate the auth tag we expect to see from the ciphertext. let expected_tag = self.generate_srtcp_auth_tag(cipher_text); diff --git a/rtc-srtp/src/cipher/mod.rs b/rtc-srtp/src/cipher/mod.rs index 41cb4f3..46b1eaf 100644 --- a/rtc-srtp/src/cipher/mod.rs +++ b/rtc-srtp/src/cipher/mod.rs @@ -31,8 +31,14 @@ use shared::error::Result; /// Cipher represents a implementation of one /// of the SRTP Specific ciphers. pub(crate) trait Cipher { - /// Get authenticated tag length. - fn auth_tag_len(&self) -> usize; + /// Get RTP authenticated tag length. + fn rtp_auth_tag_len(&self) -> usize; + + /// Get RTCP authenticated tag length. + fn rtcp_auth_tag_len(&self) -> usize; + + /// Get AEAD auth key length of the cipher. + fn aead_auth_tag_len(&self) -> usize; /// Retrieved RTCP index. fn get_rtcp_index(&self, input: &[u8]) -> usize; diff --git a/rtc-srtp/src/context/mod.rs b/rtc-srtp/src/context/mod.rs index 8eb131a..43b9240 100644 --- a/rtc-srtp/src/context/mod.rs +++ b/rtc-srtp/src/context/mod.rs @@ -130,12 +130,12 @@ impl Context { } let cipher: Box = match profile { - ProtectionProfile::Aes128CmHmacSha1_80 => { - Box::new(CipherAesCmHmacSha1::new(master_key, master_salt)?) + ProtectionProfile::Aes128CmHmacSha1_32 | ProtectionProfile::Aes128CmHmacSha1_80 => { + Box::new(CipherAesCmHmacSha1::new(profile, master_key, master_salt)?) } - ProtectionProfile::AeadAes128Gcm => { - Box::new(CipherAeadAesGcm::new(master_key, master_salt)?) + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => { + Box::new(CipherAeadAesGcm::new(profile, master_key, master_salt)?) } }; diff --git a/rtc-srtp/src/context/srtcp_test.rs b/rtc-srtp/src/context/srtcp_test.rs index 5299de9..cec9050 100644 --- a/rtc-srtp/src/context/srtcp_test.rs +++ b/rtc-srtp/src/context/srtcp_test.rs @@ -130,7 +130,7 @@ fn test_rtcp_lifecycle() -> Result<()> { #[test] fn test_rtcp_invalid_auth_tag() -> Result<()> { - let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.auth_tag_len(); + let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.rtcp_auth_tag_len(); let mut decrypt_context = Context::new( &RTCP_TEST_MASTER_KEY, @@ -217,7 +217,7 @@ fn test_encrypt_rtcp_separation() -> Result<()> { None, )?; - let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.auth_tag_len(); + let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.rtcp_auth_tag_len(); let mut decrypt_context = Context::new( &RTCP_TEST_MASTER_KEY, diff --git a/rtc-srtp/src/context/srtp_test.rs b/rtc-srtp/src/context/srtp_test.rs index 239b35e..a9162bb 100644 --- a/rtc-srtp/src/context/srtp_test.rs +++ b/rtc-srtp/src/context/srtp_test.rs @@ -121,7 +121,7 @@ fn test_rtp_invalid_auth() -> Result<()> { fn test_rtp_lifecyle() -> Result<()> { let mut encrypt_context = build_test_context()?; let mut decrypt_context = build_test_context()?; - let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.auth_tag_len(); + let auth_tag_len = ProtectionProfile::Aes128CmHmacSha1_80.rtp_auth_tag_len(); for test_case in RTP_TEST_CASES.iter() { let decrypted_pkt = rtp::packet::Packet { diff --git a/rtc-srtp/src/protection_profile.rs b/rtc-srtp/src/protection_profile.rs index 0991ea7..c6cbdf4 100644 --- a/rtc-srtp/src/protection_profile.rs +++ b/rtc-srtp/src/protection_profile.rs @@ -4,34 +4,54 @@ pub enum ProtectionProfile { #[default] Aes128CmHmacSha1_80 = 0x0001, + Aes128CmHmacSha1_32 = 0x0002, AeadAes128Gcm = 0x0007, + AeadAes256Gcm = 0x0008, } impl ProtectionProfile { pub(crate) fn key_len(&self) -> usize { match *self { - ProtectionProfile::Aes128CmHmacSha1_80 | ProtectionProfile::AeadAes128Gcm => 16, + ProtectionProfile::Aes128CmHmacSha1_32 + | ProtectionProfile::Aes128CmHmacSha1_80 + | ProtectionProfile::AeadAes128Gcm => 16, + ProtectionProfile::AeadAes256Gcm => 32, } } pub(crate) fn salt_len(&self) -> usize { match *self { - ProtectionProfile::Aes128CmHmacSha1_80 => 14, - ProtectionProfile::AeadAes128Gcm => 12, + ProtectionProfile::Aes128CmHmacSha1_32 | ProtectionProfile::Aes128CmHmacSha1_80 => 14, + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => 12, } } - pub(crate) fn auth_tag_len(&self) -> usize { + pub(crate) fn rtp_auth_tag_len(&self) -> usize { match *self { - ProtectionProfile::Aes128CmHmacSha1_80 => 10, //CIPHER_AES_CM_HMAC_SHA1AUTH_TAG_LEN, - ProtectionProfile::AeadAes128Gcm => 16, //CIPHER_AEAD_AES_GCM_AUTH_TAG_LEN, + ProtectionProfile::Aes128CmHmacSha1_80 => 10, + ProtectionProfile::Aes128CmHmacSha1_32 => 4, + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => 0, + } + } + + pub(crate) fn rtcp_auth_tag_len(&self) -> usize { + match *self { + ProtectionProfile::Aes128CmHmacSha1_80 | ProtectionProfile::Aes128CmHmacSha1_32 => 10, + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => 0, + } + } + + pub(crate) fn aead_auth_tag_len(&self) -> usize { + match *self { + ProtectionProfile::Aes128CmHmacSha1_80 | ProtectionProfile::Aes128CmHmacSha1_32 => 0, + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => 16, } } pub(crate) fn auth_key_len(&self) -> usize { match *self { - ProtectionProfile::Aes128CmHmacSha1_80 => 20, - ProtectionProfile::AeadAes128Gcm => 0, + ProtectionProfile::Aes128CmHmacSha1_80 | ProtectionProfile::Aes128CmHmacSha1_32 => 20, + ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => 0, } } }