From df8ee0ffcad03c26db489c356e183a7e1190b04c Mon Sep 17 00:00:00 2001 From: Sebbl0508 <28149337+Sebbl0508@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:50:46 +0200 Subject: [PATCH] Driver: Replace `xsalsa20poly1305` with `crypto_secretbox` (#198) As of v0.9.1, `xsalsa20poly1305` has been deprecated. This is a mostly seamless replacement, as it appears to be the same crate authors / code / etc. --- Cargo.toml | 12 ++++++------ src/driver/connection/error.rs | 12 +++++++++++- src/driver/connection/mod.rs | 2 +- src/driver/crypto.rs | 21 +++++++++++++-------- src/driver/tasks/error.rs | 2 +- src/driver/tasks/message/mixer.rs | 2 +- src/driver/tasks/mixer.rs | 2 +- src/driver/tasks/udp_rx.rs | 2 +- src/events/context/data/disconnect.rs | 2 +- 9 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ea6f0720b..0817952a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,11 @@ version = "0.3.0-rc.0" optional = true version = "1" +[dependencies.crypto_secretbox] +optional = true +version = "0.1.1" +features = ["std"] + [dependencies.dashmap] optional = true version = "5" @@ -109,11 +114,6 @@ optional = true version = "0.8" features = ["v4"] -[dependencies.xsalsa20poly1305] -optional = true -version = "0.8" -features = ["std"] - [dev-dependencies] criterion = "0.3" utils = { path = "utils" } @@ -152,6 +152,7 @@ driver-core = [ "async-trait", "audiopus", "byteorder", + "crypto_secretbox", "discortp", "flume", "parking_lot", @@ -161,7 +162,6 @@ driver-core = [ "typemap_rev", "url", "uuid", - "xsalsa20poly1305", ] rustls = ["async-tungstenite/tokio-rustls-webpki-roots", "rustls-marker"] native = ["async-tungstenite/tokio-native-tls", "native-marker"] diff --git a/src/driver/connection/error.rs b/src/driver/connection/error.rs index 6dbf72970..a363aeca5 100644 --- a/src/driver/connection/error.rs +++ b/src/driver/connection/error.rs @@ -4,11 +4,11 @@ use crate::{ driver::tasks::{error::Recipient, message::*}, ws::Error as WsError, }; +use crypto_secretbox::{cipher::InvalidLength, Error as CryptoError}; use flume::SendError; use serde_json::Error as JsonError; use std::{error::Error as StdError, fmt, io::Error as IoError}; use tokio::time::error::Elapsed; -use xsalsa20poly1305::aead::Error as CryptoError; /// Errors encountered while connecting to a Discord voice server over the driver. #[derive(Debug)] @@ -19,6 +19,8 @@ pub enum Error { AttemptDiscarded, /// An error occurred during [en/de]cryption of voice packets or key generation. Crypto(CryptoError), + /// Invalid length error while generating crypto keys + InvalidLength(InvalidLength), /// Server did not return the expected crypto mode during negotiation. CryptoModeInvalid, /// Selected crypto mode was not offered by server. @@ -89,6 +91,12 @@ impl From for Error { } } +impl From for Error { + fn from(value: InvalidLength) -> Self { + Error::InvalidLength(value) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "failed to connect to Discord RTP server: ")?; @@ -96,6 +104,7 @@ impl fmt::Display for Error { match self { AttemptDiscarded => write!(f, "connection attempt was aborted/discarded"), Crypto(e) => e.fmt(f), + InvalidLength(e) => e.fmt(f), CryptoModeInvalid => write!(f, "server changed negotiated encryption mode"), CryptoModeUnavailable => write!(f, "server did not offer chosen encryption mode"), EndpointUrl => write!(f, "endpoint URL received from gateway was invalid"), @@ -115,6 +124,7 @@ impl StdError for Error { match self { Error::AttemptDiscarded => None, Error::Crypto(e) => e.source(), + Error::InvalidLength(v) => v.source(), Error::CryptoModeInvalid => None, Error::CryptoModeUnavailable => None, Error::EndpointUrl => None, diff --git a/src/driver/connection/mod.rs b/src/driver/connection/mod.rs index 1d0bedfdc..e1d8c9b5a 100644 --- a/src/driver/connection/mod.rs +++ b/src/driver/connection/mod.rs @@ -15,6 +15,7 @@ use crate::{ ws::{self, ReceiverExt, SenderExt, WsStream}, ConnectionInfo, }; +use crypto_secretbox::{KeyInit, XSalsa20Poly1305 as Cipher}; use discortp::discord::{IpDiscoveryPacket, IpDiscoveryType, MutableIpDiscoveryPacket}; use error::{Error, Result}; use flume::Sender; @@ -22,7 +23,6 @@ use std::{net::IpAddr, str::FromStr, sync::Arc}; use tokio::{net::UdpSocket, spawn, time::timeout}; use tracing::{debug, info, instrument}; use url::Url; -use xsalsa20poly1305::{aead::NewAead, XSalsa20Poly1305 as Cipher}; #[cfg(all(feature = "rustls-marker", not(feature = "native-marker")))] use ws::create_rustls_client; diff --git a/src/driver/crypto.rs b/src/driver/crypto.rs index 18e408bfc..c10f69bf7 100644 --- a/src/driver/crypto.rs +++ b/src/driver/crypto.rs @@ -1,16 +1,19 @@ //! Encryption schemes supported by Discord's secure RTP negotiation. use byteorder::{NetworkEndian, WriteBytesExt}; -use discortp::{rtp::RtpPacket, MutablePacket}; -use rand::Rng; -use std::num::Wrapping; -use xsalsa20poly1305::{ - aead::{AeadInPlace, Error as CryptoError}, +use crypto_secretbox::{ + AeadInPlace, + Error as CryptoError, Nonce, + SecretBox, Tag, XSalsa20Poly1305 as Cipher, - NONCE_SIZE, - TAG_SIZE, }; +use discortp::{rtp::RtpPacket, MutablePacket}; +use rand::Rng; +use std::num::Wrapping; + +pub const NONCE_SIZE: usize = SecretBox::<()>::NONCE_SIZE; +pub const TAG_SIZE: usize = SecretBox::<()>::TAG_SIZE; /// Variants of the XSalsa20Poly1305 encryption scheme. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -241,8 +244,10 @@ impl CryptoState { #[cfg(test)] mod test { use super::*; + use crypto_secretbox::{KeyInit, SecretBox}; use discortp::rtp::MutableRtpPacket; - use xsalsa20poly1305::{aead::NewAead, KEY_SIZE, TAG_SIZE}; + + pub const KEY_SIZE: usize = SecretBox::<()>::KEY_SIZE; #[test] fn small_packet_decrypts_error() { diff --git a/src/driver/tasks/error.rs b/src/driver/tasks/error.rs index c56319b8f..28abf8bb4 100644 --- a/src/driver/tasks/error.rs +++ b/src/driver/tasks/error.rs @@ -1,9 +1,9 @@ use super::message::*; use crate::ws::Error as WsError; use audiopus::Error as OpusError; +use crypto_secretbox::aead::Error as CryptoError; use flume::SendError; use std::io::Error as IoError; -use xsalsa20poly1305::aead::Error as CryptoError; #[derive(Debug)] pub enum Recipient { diff --git a/src/driver/tasks/message/mixer.rs b/src/driver/tasks/message/mixer.rs index 220c26d6c..e50605be8 100644 --- a/src/driver/tasks/message/mixer.rs +++ b/src/driver/tasks/message/mixer.rs @@ -6,8 +6,8 @@ use crate::{ driver::{Bitrate, Config, CryptoState}, tracks::Track, }; +use crypto_secretbox::XSalsa20Poly1305 as Cipher; use flume::Sender; -use xsalsa20poly1305::XSalsa20Poly1305 as Cipher; pub struct MixerConnection { pub cipher: Cipher, diff --git a/src/driver/tasks/mixer.rs b/src/driver/tasks/mixer.rs index 47653df59..39e3d9b32 100644 --- a/src/driver/tasks/mixer.rs +++ b/src/driver/tasks/mixer.rs @@ -1,4 +1,5 @@ use super::{disposal, error::Result, message::*}; +use crate::driver::crypto::TAG_SIZE; use crate::{ constants::*, tracks::{PlayMode, Track}, @@ -20,7 +21,6 @@ use rand::random; use std::{convert::TryInto, time::Instant}; use tokio::runtime::Handle; use tracing::{debug, error, instrument}; -use xsalsa20poly1305::TAG_SIZE; pub struct Mixer { pub async_handle: Handle, diff --git a/src/driver/tasks/udp_rx.rs b/src/driver/tasks/udp_rx.rs index 76f5aaad3..c0cdf2f42 100644 --- a/src/driver/tasks/udp_rx.rs +++ b/src/driver/tasks/udp_rx.rs @@ -14,6 +14,7 @@ use audiopus::{ packet::Packet as OpusPacket, Channels, }; +use crypto_secretbox::XSalsa20Poly1305 as Cipher; use discortp::{ demux::{self, DemuxedMut}, rtp::{RtpExtensionPacket, RtpPacket}, @@ -25,7 +26,6 @@ use flume::Receiver; use std::{collections::HashMap, convert::TryInto, sync::Arc}; use tokio::{net::UdpSocket, select}; use tracing::{error, instrument, trace, warn}; -use xsalsa20poly1305::XSalsa20Poly1305 as Cipher; #[derive(Debug)] struct SsrcState { diff --git a/src/events/context/data/disconnect.rs b/src/events/context/data/disconnect.rs index 759ae151e..adb201317 100644 --- a/src/events/context/data/disconnect.rs +++ b/src/events/context/data/disconnect.rs @@ -95,7 +95,7 @@ impl From<&ConnectionError> for DisconnectReason { | IllegalIp | Json(_) => Self::ProtocolViolation, Io(_) => Self::Io, - Crypto(_) | InterconnectFailure(_) => Self::Internal, + Crypto(_) | InterconnectFailure(_) | InvalidLength(_) => Self::Internal, Ws(ws) => ws.into(), TimedOut => Self::TimedOut, }