Skip to content

Commit

Permalink
add more ProtectionProfile
Browse files Browse the repository at this point in the history
  • Loading branch information
yngrtc committed Jun 29, 2024
1 parent 3190812 commit f5dd5fd
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 43 deletions.
33 changes: 26 additions & 7 deletions rtc-srtp/src/cipher/cipher_aead_aes_gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*,
Expand All @@ -18,15 +19,27 @@ 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<u8>,
srtcp_session_salt: Vec<u8>,
}

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(
Expand All @@ -36,8 +49,9 @@ impl Cipher for CipherAeadAesGcm {
roc: u32,
) -> Result<BytesMut> {
// 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);
Expand All @@ -62,7 +76,7 @@ impl Cipher for CipherAeadAesGcm {
header: &rtp::header::Header,
roc: u32,
) -> Result<BytesMut> {
if ciphertext.len() < self.auth_tag_len() {
if ciphertext.len() < self.aead_auth_tag_len() {
return Err(Error::ErrFailedToVerifyAuthTag);
}

Expand Down Expand Up @@ -114,7 +128,7 @@ impl Cipher for CipherAeadAesGcm {
srtcp_index: usize,
ssrc: u32,
) -> Result<BytesMut> {
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);
}

Expand Down Expand Up @@ -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<CipherAeadAesGcm> {
pub(crate) fn new(
profile: ProtectionProfile,
master_key: &[u8],
master_salt: &[u8],
) -> Result<CipherAeadAesGcm> {
let srtp_session_key = aes_cm_key_derivation(
LABEL_SRTP_ENCRYPTION,
master_key,
Expand Down Expand Up @@ -188,6 +206,7 @@ impl CipherAeadAesGcm {
)?;

Ok(CipherAeadAesGcm {
profile,
srtp_cipher,
srtcp_cipher,
srtp_session_salt,
Expand Down
55 changes: 36 additions & 19 deletions rtc-srtp/src/cipher/cipher_aes_cm_hmac_sha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Aes128Ctr = ctr::Ctr128BE<aes::Aes128>;
pub const CIPHER_AES_CM_HMAC_SHA1AUTH_TAG_LEN: usize = 10;

pub(crate) struct CipherAesCmHmacSha1 {
profile: ProtectionProfile,
srtp_session_key: Vec<u8>,
srtp_session_salt: Vec<u8>,
srtp_session_auth: HmacSha1,
Expand All @@ -33,7 +34,7 @@ pub(crate) struct CipherAesCmHmacSha1 {
}

impl CipherAesCmHmacSha1 {
pub fn new(master_key: &[u8], master_salt: &[u8]) -> Result<Self> {
pub fn new(profile: ProtectionProfile, master_key: &[u8], master_salt: &[u8]) -> Result<Self> {
let srtp_session_key = aes_cm_key_derivation(
LABEL_SRTP_ENCRYPTION,
master_key,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -174,8 +187,9 @@ impl Cipher for CipherAesCmHmacSha1 {
header: &rtp::header::Header,
roc: u32,
) -> Result<BytesMut> {
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()?;
Expand Down Expand Up @@ -210,15 +224,18 @@ impl Cipher for CipherAesCmHmacSha1 {
header: &rtp::header::Header,
roc: u32,
) -> Result<BytesMut> {
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)?;
Expand Down Expand Up @@ -257,7 +274,7 @@ impl Cipher for CipherAesCmHmacSha1 {
ssrc: u32,
) -> Result<BytesMut> {
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);
Expand Down Expand Up @@ -294,14 +311,14 @@ impl Cipher for CipherAesCmHmacSha1 {
srtcp_index: usize,
ssrc: u32,
) -> Result<BytesMut> {
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);

Expand All @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions rtc-srtp/src/cipher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions rtc-srtp/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ impl Context {
}

let cipher: Box<dyn Cipher> = 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)?)
}
};

Expand Down
4 changes: 2 additions & 2 deletions rtc-srtp/src/context/srtcp_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion rtc-srtp/src/context/srtp_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 28 additions & 8 deletions rtc-srtp/src/protection_profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}

0 comments on commit f5dd5fd

Please sign in to comment.