feat: v8 encryption modes (#264)
This PR adds support for the new AEAD cryptosystems advertised by Discord, AES256-GCM and XChaCha20Poly1305. These schemes will shortly become mandatory, and provider stronger integrity/authentication guarantees over the cleartext portions of any voice packet by correctly specifying additional authenticated data. To provide smooth switchover, we've added basic negotiation over the `CryptoMode`. This ensures that any clients who are manually specifying one of the legacy modes will automatically migrate to `Aes256Gcm` when Discord cease to advertise their original preference. Closes #246. --------- Co-authored-by: Kyle Simpson <kyleandrew.simpson@gmail.com>
This commit is contained in:
@@ -5,14 +5,14 @@ mod ssrc_state;
|
||||
use self::{decode_sizes::*, playout_buffer::*, ssrc_state::*};
|
||||
|
||||
use super::message::*;
|
||||
use crate::driver::CryptoMode;
|
||||
use crate::{
|
||||
constants::*,
|
||||
driver::CryptoMode,
|
||||
driver::crypto::Cipher,
|
||||
events::{context_data::VoiceTick, internal_data::*, CoreContext},
|
||||
Config,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use crypto_secretbox::XSalsa20Poly1305 as Cipher;
|
||||
use discortp::{
|
||||
demux::{self, DemuxedMut},
|
||||
rtp::RtpPacket,
|
||||
@@ -33,6 +33,7 @@ type RtpSsrc = u32;
|
||||
|
||||
struct UdpRx {
|
||||
cipher: Cipher,
|
||||
crypto_mode: CryptoMode,
|
||||
decoder_map: HashMap<RtpSsrc, SsrcState>,
|
||||
config: Config,
|
||||
rx: Receiver<UdpRxMessage>,
|
||||
@@ -143,7 +144,7 @@ impl UdpRx {
|
||||
// For simplicity, if the event task fails then we nominate the mixing thread
|
||||
// to rebuild their context etc. (hence, the `let _ =` statements.), as it will
|
||||
// try to make contact every 20ms.
|
||||
let crypto_mode = self.config.crypto_mode;
|
||||
let crypto_mode = self.crypto_mode;
|
||||
|
||||
match demux::demux_mut(packet.as_mut()) {
|
||||
DemuxedMut::Rtp(mut rtp) => {
|
||||
@@ -153,11 +154,12 @@ impl UdpRx {
|
||||
}
|
||||
|
||||
let packet_data = if self.config.decode_mode.should_decrypt() {
|
||||
let out = crypto_mode
|
||||
.decrypt_in_place(&mut rtp, &self.cipher)
|
||||
let out = self
|
||||
.cipher
|
||||
.decrypt_rtp_in_place(&mut rtp)
|
||||
.map(|(s, t)| (s, t, true));
|
||||
|
||||
if let Err(e) = out {
|
||||
if let Err(ref e) = out {
|
||||
warn!("RTP decryption failed: {:?}", e);
|
||||
}
|
||||
|
||||
@@ -169,7 +171,7 @@ impl UdpRx {
|
||||
let rtp = rtp.to_immutable();
|
||||
let (rtp_body_start, rtp_body_tail, decrypted) = packet_data.unwrap_or_else(|| {
|
||||
(
|
||||
CryptoMode::payload_prefix_len(),
|
||||
crypto_mode.payload_prefix_len2(),
|
||||
crypto_mode.payload_suffix_len(),
|
||||
false,
|
||||
)
|
||||
@@ -178,7 +180,7 @@ impl UdpRx {
|
||||
let entry = self
|
||||
.decoder_map
|
||||
.entry(rtp.get_ssrc())
|
||||
.or_insert_with(|| SsrcState::new(&rtp, &self.config));
|
||||
.or_insert_with(|| SsrcState::new(&rtp, crypto_mode, &self.config));
|
||||
|
||||
// Only do this on RTP, rather than RTCP -- this pins decoder state liveness
|
||||
// to *speech* rather than just presence.
|
||||
@@ -201,9 +203,9 @@ impl UdpRx {
|
||||
},
|
||||
DemuxedMut::Rtcp(mut rtcp) => {
|
||||
let packet_data = if self.config.decode_mode.should_decrypt() {
|
||||
let out = crypto_mode.decrypt_in_place(&mut rtcp, &self.cipher);
|
||||
let out = self.cipher.decrypt_rtcp_in_place(&mut rtcp);
|
||||
|
||||
if let Err(e) = out {
|
||||
if let Err(ref e) = out {
|
||||
warn!("RTCP decryption failed: {:?}", e);
|
||||
}
|
||||
|
||||
@@ -214,7 +216,7 @@ impl UdpRx {
|
||||
|
||||
let (start, tail) = packet_data.unwrap_or_else(|| {
|
||||
(
|
||||
CryptoMode::payload_prefix_len(),
|
||||
crypto_mode.payload_prefix_len2(),
|
||||
crypto_mode.payload_suffix_len(),
|
||||
)
|
||||
});
|
||||
@@ -242,6 +244,7 @@ pub(crate) async fn runner(
|
||||
mut interconnect: Interconnect,
|
||||
rx: Receiver<UdpRxMessage>,
|
||||
cipher: Cipher,
|
||||
crypto_mode: CryptoMode,
|
||||
config: Config,
|
||||
udp_socket: UdpSocket,
|
||||
ssrc_signalling: Arc<SsrcTracker>,
|
||||
@@ -250,6 +253,7 @@ pub(crate) async fn runner(
|
||||
|
||||
let mut state = UdpRx {
|
||||
cipher,
|
||||
crypto_mode,
|
||||
decoder_map: HashMap::new(),
|
||||
config,
|
||||
rx,
|
||||
|
||||
Reference in New Issue
Block a user