use std::fmt;
use self::aes_128_cm_sha1_80::AesKey;
use super::CryptoProvider;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SrtpProfile {
#[cfg(feature = "_internal_test_exports")]
PassThrough,
Aes128CmSha1_80,
AeadAes128Gcm,
AeadAes256Gcm,
}
#[allow(dead_code)]
impl SrtpProfile {
pub(crate) const ALL: &'static [SrtpProfile] = &[
SrtpProfile::AeadAes256Gcm,
SrtpProfile::AeadAes128Gcm,
SrtpProfile::Aes128CmSha1_80,
];
#[rustfmt::skip]
pub(crate) fn keying_material_len(&self) -> usize {
match self {
#[cfg(feature = "_internal_test_exports")]
SrtpProfile::PassThrough => 0,
SrtpProfile::Aes128CmSha1_80 => 16 * 2 + 14 * 2,
SrtpProfile::AeadAes128Gcm => 16 * 2 + 12 * 2,
SrtpProfile::AeadAes256Gcm => 32 * 2 + 12 * 2,
}
}
}
pub enum SrtpCrypto {
#[cfg(any(feature = "openssl", feature = "openssl-dimpl"))]
OpenSsl(super::ossl::OsslSrtpCryptoImpl),
#[cfg(not(any(feature = "openssl", feature = "openssl-dimpl")))]
OpenSsl(DummySrtpCryptoImpl),
#[cfg(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows"))]
WinCrypto(super::wincrypto::WinCryptoSrtpCryptoImpl),
#[cfg(not(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows")))]
WinCrypto(DummySrtpCryptoImpl),
#[cfg(feature = "dimpl")]
AwsLc(super::aws_lc::AwsLcImpl),
#[cfg(not(feature = "dimpl"))]
AwsLc(DummySrtpCryptoImpl),
}
#[allow(clippy::unit_arg)]
impl SrtpCrypto {
#[cfg(any(feature = "openssl", feature = "openssl-dimpl"))]
pub fn new_openssl() -> SrtpCrypto {
Self::OpenSsl(super::ossl::OsslSrtpCryptoImpl)
}
#[cfg(not(any(feature = "openssl", feature = "openssl-dimpl")))]
pub fn new_openssl() -> SrtpCrypto {
Self::OpenSsl(DummySrtpCryptoImpl(CryptoProvider::OpenSsl))
}
#[cfg(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows"))]
pub fn new_wincrypto() -> SrtpCrypto {
Self::WinCrypto(super::wincrypto::WinCryptoSrtpCryptoImpl)
}
#[cfg(not(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows")))]
pub fn new_wincrypto() -> SrtpCrypto {
Self::WinCrypto(DummySrtpCryptoImpl(CryptoProvider::WinCrypto))
}
#[cfg(feature = "dimpl")]
pub fn new_rust_crypto() -> SrtpCrypto {
Self::AwsLc(super::aws_lc::AwsLcImpl)
}
#[cfg(not(feature = "dimpl"))]
pub fn new_rust_crypto() -> SrtpCrypto {
Self::AwsLc(DummySrtpCryptoImpl(CryptoProvider::Dimpl))
}
pub fn new_aes_128_cm_sha1_80(
&self,
key: AesKey,
encrypt: bool,
) -> Box<dyn aes_128_cm_sha1_80::CipherCtx> {
match self {
SrtpCrypto::OpenSsl(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
SrtpCrypto::WinCrypto(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
SrtpCrypto::AwsLc(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
}
}
pub fn new_aead_aes_128_gcm(
&self,
key: aead_aes_128_gcm::AeadKey,
encrypt: bool,
) -> Box<dyn aead_aes_128_gcm::CipherCtx> {
match self {
SrtpCrypto::OpenSsl(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
SrtpCrypto::WinCrypto(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
SrtpCrypto::AwsLc(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
}
}
pub fn new_aead_aes_256_gcm(
&self,
key: aead_aes_256_gcm::AeadKey,
encrypt: bool,
) -> Box<dyn aead_aes_256_gcm::CipherCtx> {
match self {
SrtpCrypto::OpenSsl(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
SrtpCrypto::WinCrypto(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
SrtpCrypto::AwsLc(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
}
}
pub fn srtp_aes_128_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]) {
match self {
SrtpCrypto::OpenSsl(v) => v.srtp_aes_128_ecb_round(key, input, output),
SrtpCrypto::WinCrypto(v) => v.srtp_aes_128_ecb_round(key, input, output),
SrtpCrypto::AwsLc(v) => v.srtp_aes_128_ecb_round(key, input, output),
}
}
pub fn srtp_aes_256_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]) {
match self {
SrtpCrypto::OpenSsl(v) => v.srtp_aes_256_ecb_round(key, input, output),
SrtpCrypto::WinCrypto(v) => v.srtp_aes_256_ecb_round(key, input, output),
SrtpCrypto::AwsLc(v) => v.srtp_aes_256_ecb_round(key, input, output),
}
}
}
pub trait SrtpCryptoImpl {
type Aes128CmSha1_80: aes_128_cm_sha1_80::CipherCtx;
type AeadAes128Gcm: aead_aes_128_gcm::CipherCtx;
type AeadAes256Gcm: aead_aes_256_gcm::CipherCtx;
fn new_aes_128_cm_sha1_80(&self, key: AesKey, encrypt: bool) -> Self::Aes128CmSha1_80 {
<Self::Aes128CmSha1_80 as aes_128_cm_sha1_80::CipherCtx>::new(key, encrypt)
}
fn new_aead_aes_128_gcm(
&self,
key: aead_aes_128_gcm::AeadKey,
encrypt: bool,
) -> Self::AeadAes128Gcm {
<Self::AeadAes128Gcm as aead_aes_128_gcm::CipherCtx>::new(key, encrypt)
}
fn new_aead_aes_256_gcm(
&self,
key: aead_aes_256_gcm::AeadKey,
encrypt: bool,
) -> Self::AeadAes256Gcm {
<Self::AeadAes256Gcm as aead_aes_256_gcm::CipherCtx>::new(key, encrypt)
}
fn srtp_aes_128_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]);
fn srtp_aes_256_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]);
}
pub mod aes_128_cm_sha1_80 {
use std::panic::UnwindSafe;
use subtle::ConstantTimeEq;
use crate::crypto::CryptoError;
pub const KEY_LEN: usize = 16;
pub const SALT_LEN: usize = 14;
pub const HMAC_KEY_LEN: usize = 20;
pub const HMAC_TAG_LEN: usize = 10;
pub type AesKey = [u8; 16];
pub type RtpSalt = [u8; 14];
pub type RtpIv = [u8; 16];
pub trait CipherCtx: UnwindSafe + Send + Sync {
fn new(key: AesKey, encrypt: bool) -> Self
where
Self: Sized;
fn encrypt(
&mut self,
iv: &RtpIv,
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &RtpIv,
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
}
pub fn rtp_hmac(key: &[u8], buf: &mut [u8], srtp_index: u64, hmac_start: usize) {
let roc = (srtp_index >> 16) as u32;
let tag = crate::crypto::sha1_hmac(key, &[&buf[..hmac_start], &roc.to_be_bytes()]);
buf[hmac_start..(hmac_start + HMAC_TAG_LEN)].copy_from_slice(&tag[0..HMAC_TAG_LEN]);
}
pub fn rtp_verify(key: &[u8], buf: &[u8], srtp_index: u64, cmp: &[u8]) -> bool {
let roc = (srtp_index >> 16) as u32;
let tag = crate::crypto::sha1_hmac(key, &[buf, &roc.to_be_bytes()]);
tag[0..HMAC_TAG_LEN].ct_eq(cmp).into()
}
pub fn rtp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u64) -> RtpIv {
let mut iv = [0; 16];
let ssrc_be = ssrc.to_be_bytes();
let srtp_be = srtp_index.to_be_bytes();
iv[4..8].copy_from_slice(&ssrc_be);
for i in 0..8 {
iv[i + 6] ^= srtp_be[i];
}
for i in 0..14 {
iv[i] ^= salt[i];
}
iv
}
pub fn rtcp_hmac(key: &[u8], buf: &mut [u8], hmac_index: usize) {
let tag = crate::crypto::sha1_hmac(key, &[&buf[0..hmac_index]]);
buf[hmac_index..(hmac_index + HMAC_TAG_LEN)].copy_from_slice(&tag[0..HMAC_TAG_LEN]);
}
pub fn rtcp_verify(key: &[u8], buf: &[u8], cmp: &[u8]) -> bool {
let tag = crate::crypto::sha1_hmac(key, &[buf]);
tag[0..HMAC_TAG_LEN].ct_eq(cmp).into()
}
}
pub mod aead_aes_128_gcm {
use std::panic::UnwindSafe;
use crate::crypto::CryptoError;
pub const KEY_LEN: usize = 16;
pub const SALT_LEN: usize = 12;
pub const RTCP_AAD_LEN: usize = 12;
pub const TAG_LEN: usize = 16;
pub const IV_LEN: usize = 12;
pub type AeadKey = [u8; KEY_LEN];
pub type RtpSalt = [u8; SALT_LEN];
pub type RtpIv = [u8; SALT_LEN];
pub trait CipherCtx: UnwindSafe + Send + Sync {
fn new(key: AeadKey, encrypt: bool) -> Self
where
Self: Sized;
fn encrypt(
&mut self,
iv: &[u8; IV_LEN],
aad: &[u8],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &[u8; IV_LEN],
aads: &[&[u8]],
input: &[u8],
output: &mut [u8],
) -> Result<usize, CryptoError>;
}
pub fn rtp_iv(salt: RtpSalt, ssrc: u32, roc: u32, seq: u16) -> RtpIv {
let mut iv = [0; SALT_LEN];
let ssrc_be = ssrc.to_be_bytes();
let roc_be = roc.to_be_bytes();
let seq_be = seq.to_be_bytes();
iv[2..6].copy_from_slice(&ssrc_be);
iv[6..10].copy_from_slice(&roc_be);
iv[10..12].copy_from_slice(&seq_be);
for i in 0..SALT_LEN {
iv[i] ^= salt[i];
}
iv
}
pub fn rtcp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u32) -> RtpIv {
let mut iv = [0; SALT_LEN];
let ssrc_be = ssrc.to_be_bytes();
let srtp_be = srtp_index.to_be_bytes();
iv[2..6].copy_from_slice(&ssrc_be);
iv[8..12].copy_from_slice(&srtp_be);
for i in 0..SALT_LEN {
iv[i] ^= salt[i];
}
iv
}
}
pub mod aead_aes_256_gcm {
use std::panic::UnwindSafe;
use crate::crypto::CryptoError;
pub const KEY_LEN: usize = 32;
pub const SALT_LEN: usize = 12;
pub const RTCP_AAD_LEN: usize = 12;
pub const TAG_LEN: usize = 16;
pub const IV_LEN: usize = 12;
pub type AeadKey = [u8; KEY_LEN];
pub type RtpSalt = [u8; SALT_LEN];
pub type RtpIv = [u8; SALT_LEN];
pub trait CipherCtx: UnwindSafe + Send + Sync {
fn new(key: AeadKey, encrypt: bool) -> Self
where
Self: Sized;
fn encrypt(
&mut self,
iv: &[u8; IV_LEN],
aad: &[u8],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &[u8; IV_LEN],
aads: &[&[u8]],
input: &[u8],
output: &mut [u8],
) -> Result<usize, CryptoError>;
}
pub fn rtp_iv(salt: RtpSalt, ssrc: u32, roc: u32, seq: u16) -> RtpIv {
let mut iv = [0; SALT_LEN];
let ssrc_be = ssrc.to_be_bytes();
let roc_be = roc.to_be_bytes();
let seq_be = seq.to_be_bytes();
iv[2..6].copy_from_slice(&ssrc_be);
iv[6..10].copy_from_slice(&roc_be);
iv[10..12].copy_from_slice(&seq_be);
for i in 0..SALT_LEN {
iv[i] ^= salt[i];
}
iv
}
pub fn rtcp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u32) -> RtpIv {
let mut iv = [0; SALT_LEN];
let ssrc_be = ssrc.to_be_bytes();
let srtp_be = srtp_index.to_be_bytes();
iv[2..6].copy_from_slice(&ssrc_be);
iv[8..12].copy_from_slice(&srtp_be);
for i in 0..SALT_LEN {
iv[i] ^= salt[i];
}
iv
}
}
impl fmt::Display for SrtpProfile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
#[cfg(feature = "_internal_test_exports")]
SrtpProfile::PassThrough => write!(f, "PassThrough"),
SrtpProfile::Aes128CmSha1_80 => write!(f, "SRTP_AES128_CM_SHA1_80"),
SrtpProfile::AeadAes128Gcm => write!(f, "SRTP_AEAD_AES_128_GCM"),
SrtpProfile::AeadAes256Gcm => write!(f, "SRTP_AEAD_AES_256_GCM"),
}
}
}
pub struct DummySrtpCryptoImpl(CryptoProvider);
impl SrtpCryptoImpl for DummySrtpCryptoImpl {
type Aes128CmSha1_80 = ();
type AeadAes128Gcm = ();
type AeadAes256Gcm = ();
fn new_aes_128_cm_sha1_80(&self, _: AesKey, _: bool) -> Self::Aes128CmSha1_80 {
panic!("Must enable feature: {}", self.0)
}
fn new_aead_aes_128_gcm(&self, _: aead_aes_128_gcm::AeadKey, _: bool) -> Self::AeadAes128Gcm {
panic!("Must enable feature: {}", self.0)
}
fn new_aead_aes_256_gcm(&self, _: aead_aes_256_gcm::AeadKey, _: bool) -> Self::AeadAes256Gcm {
panic!("Must enable feature: {}", self.0)
}
fn srtp_aes_128_ecb_round(&self, _: &[u8], _: &[u8], _: &mut [u8]) {
panic!("Must enable feature: {}", self.0)
}
fn srtp_aes_256_ecb_round(&self, _: &[u8], _: &[u8], _: &mut [u8]) {
panic!("Must enable feature: {}", self.0)
}
}
impl aes_128_cm_sha1_80::CipherCtx for () {
fn new(_: AesKey, _: bool) -> Self
where
Self: Sized,
{
unreachable!()
}
fn encrypt(
&mut self,
_: &aes_128_cm_sha1_80::RtpIv,
_: &[u8],
_: &mut [u8],
) -> Result<(), super::CryptoError> {
unreachable!()
}
fn decrypt(
&mut self,
_: &aes_128_cm_sha1_80::RtpIv,
_: &[u8],
_: &mut [u8],
) -> Result<(), super::CryptoError> {
unreachable!()
}
}
impl aead_aes_128_gcm::CipherCtx for () {
fn new(_: aead_aes_128_gcm::AeadKey, _: bool) -> Self
where
Self: Sized,
{
unreachable!()
}
fn encrypt(
&mut self,
_: &[u8; aead_aes_128_gcm::IV_LEN],
_: &[u8],
_: &[u8],
_: &mut [u8],
) -> Result<(), super::CryptoError> {
unreachable!()
}
fn decrypt(
&mut self,
_: &[u8; aead_aes_128_gcm::IV_LEN],
_: &[&[u8]],
_: &[u8],
_: &mut [u8],
) -> Result<usize, super::CryptoError> {
unreachable!()
}
}
impl aead_aes_256_gcm::CipherCtx for () {
fn new(_: aead_aes_256_gcm::AeadKey, _: bool) -> Self
where
Self: Sized,
{
unreachable!()
}
fn encrypt(
&mut self,
_: &[u8; aead_aes_256_gcm::IV_LEN],
_: &[u8],
_: &[u8],
_: &mut [u8],
) -> Result<(), super::CryptoError> {
unreachable!()
}
fn decrypt(
&mut self,
_: &[u8; aead_aes_256_gcm::IV_LEN],
_: &[&[u8]],
_: &[u8],
_: &mut [u8],
) -> Result<usize, super::CryptoError> {
unreachable!()
}
}