use std::fmt;
use std::fmt::Debug;
use std::panic::{RefUnwindSafe, UnwindSafe};
use std::sync::OnceLock;
use std::time::Instant;
use subtle::ConstantTimeEq;
use crate::crypto::dtls::*;
use crate::crypto::error::CryptoError;
#[derive(Debug, Clone)]
pub struct CryptoProvider {
pub srtp_provider: &'static dyn SrtpProvider,
pub sha1_hmac_provider: &'static dyn Sha1HmacProvider,
pub sha256_provider: &'static dyn Sha256Provider,
pub dtls_provider: &'static dyn DtlsProvider,
}
impl UnwindSafe for CryptoProvider {}
impl RefUnwindSafe for CryptoProvider {}
static DEFAULT: OnceLock<CryptoProvider> = OnceLock::new();
impl CryptoProvider {
pub fn install_process_default(self) {
let _ = DEFAULT.set(self);
}
pub fn install_default(provider: CryptoProvider) {
DEFAULT
.set(provider)
.expect("CryptoProvider::install_default() called more than once");
}
pub fn get_default() -> Option<&'static CryptoProvider> {
DEFAULT.get()
}
}
impl fmt::Display for CryptoProvider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "CryptoProvider")
}
}
pub use crate::{CryptoSafe, Sha1HmacProvider};
pub trait SrtpProvider: CryptoSafe {
fn aes_128_cm_sha1_80(&self) -> &'static dyn SupportedAes128CmSha1_80;
fn aead_aes_128_gcm(&self) -> &'static dyn SupportedAeadAes128Gcm;
fn aead_aes_256_gcm(&self) -> &'static dyn SupportedAeadAes256Gcm;
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 trait Sha256Provider: CryptoSafe {
fn sha256(&self, data: &[u8]) -> [u8; 32];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum DtlsVersion {
#[default]
Dtls12,
Dtls13,
Auto,
}
impl fmt::Display for DtlsVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DtlsVersion::Dtls12 => write!(f, "DTLS 1.2"),
DtlsVersion::Dtls13 => write!(f, "DTLS 1.3"),
DtlsVersion::Auto => write!(f, "DTLS Auto-detect"),
}
}
}
pub trait DtlsProvider: CryptoSafe {
fn generate_certificate(&self) -> Option<DtlsCert>;
fn new_dtls(
&self,
cert: &DtlsCert,
now: Instant,
dtls_version: DtlsVersion,
) -> Result<Box<dyn DtlsInstance>, CryptoError>;
fn is_test(&self) -> bool {
cfg!(feature = "_internal_test_exports")
}
}
pub trait DtlsInstance: CryptoSafe {
fn set_active(&mut self, active: bool);
fn handle_packet(&mut self, packet: &[u8]) -> Result<(), DtlsImplError>;
fn poll_output<'a>(&mut self, buf: &'a mut [u8]) -> DtlsOutput<'a>;
fn handle_timeout(&mut self, now: Instant) -> Result<(), DtlsImplError>;
fn send_application_data(&mut self, data: &[u8]) -> Result<(), DtlsImplError>;
fn is_active(&self) -> bool;
}
pub trait SupportedAes128CmSha1_80: CryptoSafe {
fn create_cipher(&self, key: [u8; 16], encrypt: bool) -> Box<dyn Aes128CmSha1_80Cipher>;
}
pub trait SupportedAeadAes128Gcm: CryptoSafe {
fn create_cipher(&self, key: [u8; 16], encrypt: bool) -> Box<dyn AeadAes128GcmCipher>;
}
pub trait SupportedAeadAes256Gcm: CryptoSafe {
fn create_cipher(&self, key: [u8; 32], encrypt: bool) -> Box<dyn AeadAes256GcmCipher>;
}
pub trait Aes128CmSha1_80Cipher: CryptoSafe {
fn encrypt(
&mut self,
iv: &[u8; 16],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &[u8; 16],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
}
pub trait AeadAes128GcmCipher: CryptoSafe {
fn encrypt(
&mut self,
iv: &[u8; 12],
aad: &[u8],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &[u8; 12],
aads: &[&[u8]],
input: &[u8],
output: &mut [u8],
) -> Result<usize, CryptoError>;
}
pub trait AeadAes256GcmCipher: CryptoSafe {
fn encrypt(
&mut self,
iv: &[u8; 12],
aad: &[u8],
input: &[u8],
output: &mut [u8],
) -> Result<(), CryptoError>;
fn decrypt(
&mut self,
iv: &[u8; 12],
aads: &[&[u8]],
input: &[u8],
output: &mut [u8],
) -> Result<usize, CryptoError>;
}
#[derive(Debug, Clone, Copy)]
pub struct Aes128CmSha1_80;
impl Aes128CmSha1_80 {
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 fn rtp_hmac(
sha1_hmac: impl Fn(&[u8], &[&[u8]]) -> [u8; 20],
key: &[u8],
buf: &mut [u8],
srtp_index: u64,
hmac_start: usize,
) {
let roc = (srtp_index >> 16) as u32;
let tag = sha1_hmac(key, &[&buf[..hmac_start], &roc.to_be_bytes()]);
buf[hmac_start..(hmac_start + Self::HMAC_TAG_LEN)]
.copy_from_slice(&tag[0..Self::HMAC_TAG_LEN]);
}
pub fn rtp_verify(
sha1_hmac: impl Fn(&[u8], &[&[u8]]) -> [u8; 20],
key: &[u8],
buf: &[u8],
srtp_index: u64,
cmp: &[u8],
) -> bool {
let roc = (srtp_index >> 16) as u32;
let tag = sha1_hmac(key, &[buf, &roc.to_be_bytes()]);
tag[0..Self::HMAC_TAG_LEN].ct_eq(cmp).into()
}
pub fn rtp_iv(salt: [u8; 14], ssrc: u32, srtp_index: u64) -> [u8; 16] {
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(
sha1_hmac: impl Fn(&[u8], &[&[u8]]) -> [u8; 20],
key: &[u8],
buf: &mut [u8],
hmac_index: usize,
) {
let tag = sha1_hmac(key, &[&buf[0..hmac_index]]);
buf[hmac_index..(hmac_index + Self::HMAC_TAG_LEN)]
.copy_from_slice(&tag[0..Self::HMAC_TAG_LEN]);
}
pub fn rtcp_verify(
sha1_hmac: impl Fn(&[u8], &[&[u8]]) -> [u8; 20],
key: &[u8],
buf: &[u8],
cmp: &[u8],
) -> bool {
let tag = sha1_hmac(key, &[buf]);
tag[0..Self::HMAC_TAG_LEN].ct_eq(cmp).into()
}
}
#[derive(Debug, Clone, Copy)]
pub struct AeadAes128Gcm;
impl AeadAes128Gcm {
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 fn rtp_iv(salt: [u8; 12], ssrc: u32, roc: u32, seq: u16) -> [u8; 12] {
let mut iv = [0; 12];
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..12 {
iv[i] ^= salt[i];
}
iv
}
pub fn rtcp_iv(salt: [u8; 12], ssrc: u32, srtp_index: u32) -> [u8; 12] {
let mut iv = [0; 12];
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..12 {
iv[i] ^= salt[i];
}
iv
}
}
#[derive(Debug, Clone, Copy)]
pub struct AeadAes256Gcm;
impl AeadAes256Gcm {
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 fn rtp_iv(salt: [u8; 12], ssrc: u32, roc: u32, seq: u16) -> [u8; 12] {
let mut iv = [0; 12];
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..12 {
iv[i] ^= salt[i];
}
iv
}
pub fn rtcp_iv(salt: [u8; 12], ssrc: u32, srtp_index: u32) -> [u8; 12] {
let mut iv = [0; 12];
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..12 {
iv[i] ^= salt[i];
}
iv
}
}