Skip to content

Commit

Permalink
use the xsalsa20poly1305 crate for encryption in voice (serenity-rs…
Browse files Browse the repository at this point in the history
…#884)

This commit replaces the `sodiumoxide` crate, a wrapper for the
libsodium C library, with the pure Rust `xsalsa20poly1305` crate from
the RustCrypto project: 

https://github.com/RustCrypto/AEADs/tree/master/xsalsa20poly1305
  • Loading branch information
tarcieri authored Jun 12, 2020
1 parent f98e61e commit 3965e00
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 20 deletions.
12 changes: 5 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,6 @@ version = "0.7"
optional = true
version = "0.16"

[dependencies.sodiumoxide]
default-features = false
features = ["std"]
optional = true
version = "0.2"

[dependencies.threadpool]
optional = true
version = "1"
Expand All @@ -99,6 +93,10 @@ version = "0.21"
optional = true
version = "0.18"

[dependencies.xsalsa20poly1305]
optional = true
version = "0.4.2"

[dev-dependencies.http_crate]
version = "0.2"
package = "http"
Expand Down Expand Up @@ -154,7 +152,7 @@ native_tls_backend = ["reqwest/native-tls", "tungstenite/tls"]
model = ["builder", "http"]
standard_framework = ["framework", "uwl", "command_attr", "static_assertions"]
utils = ["base64"]
voice = ["byteorder", "gateway", "audiopus", "rand", "sodiumoxide"]
voice = ["byteorder", "gateway", "audiopus", "rand", "xsalsa20poly1305"]

[package.metadata.docs.rs]
all-features = true
35 changes: 22 additions & 13 deletions src/voice/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use audiopus::{
use parking_lot::Mutex;
use rand::random;
use serde::Deserialize;
use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
use std::{
collections::HashMap,
io::Write,
Expand All @@ -46,6 +45,10 @@ use std::{
},
time::Duration
};
use xsalsa20poly1305::{
aead::{Aead, NewAead},
Key, Nonce, XSalsa20Poly1305, KEY_SIZE,
};

use super::audio::{AudioReceiver, AudioType, HEADER_LEN, SAMPLE_RATE, DEFAULT_BITRATE, LockedAudio};
use super::connection_info::ConnectionInfo;
Expand Down Expand Up @@ -73,14 +76,14 @@ struct ThreadItems {

pub struct Connection {
audio_timer: Timer,
cipher: XSalsa20Poly1305,
client: Arc<Mutex<WsClient>>,
connection_info: ConnectionInfo,
decoder_map: HashMap<(u32, Channels), OpusDecoder>,
destination: SocketAddr,
encoder: OpusEncoder,
encoder_stereo: bool,
keepalive_timer: Timer,
key: Key,
last_heartbeat_nonce: Option<u64>,
sequence: u16,
silence_frames: u8,
Expand Down Expand Up @@ -180,7 +183,7 @@ impl Connection {
.send_json(&payload::build_select_protocol(addr, port))?;
}

let key = encryption_key(&mut client)?;
let cipher = init_cipher(&mut client)?;

unset_blocking(&mut client)?;
let mutexed_client = Arc::new(Mutex::new(client));
Expand All @@ -204,13 +207,13 @@ impl Connection {

Ok(Connection {
audio_timer: Timer::new(1000 * 60 * 4),
cipher,
client: mutexed_client,
connection_info: info,
decoder_map: HashMap::new(),
destination,
encoder,
encoder_stereo: false,
key,
keepalive_timer: Timer::new(temp_heartbeat),
last_heartbeat_nonce: None,
udp,
Expand Down Expand Up @@ -299,11 +302,10 @@ impl Connection {
let timestamp = handle.read_u32::<BigEndian>()?;
let ssrc = handle.read_u32::<BigEndian>()?;

nonce.0[..HEADER_LEN]
nonce[..HEADER_LEN]
.clone_from_slice(&packet[..HEADER_LEN]);

if let Ok(mut decrypted) =
secretbox::open(&packet[HEADER_LEN..], &nonce, &self.key) {
if let Ok(mut decrypted) = self.cipher.decrypt(&nonce, &packet[HEADER_LEN..]) {
let channels = opus_packet::nb_channels(&decrypted)?;

let entry =
Expand Down Expand Up @@ -477,7 +479,7 @@ impl Connection {
let mut buffer = [0i16; 960 * 2];
let mut mix_buffer = [0f32; 960 * 2];
let mut packet = vec![0u8; size as usize].into_boxed_slice();
let mut nonce = secretbox::Nonce([0; 24]);
let mut nonce = Nonce::default();

while let Ok(status) = self.thread_items.rx.try_recv() {
match status {
Expand Down Expand Up @@ -584,7 +586,7 @@ impl Connection {
cursor.write_u32::<BigEndian>(self.ssrc)?;
}

nonce.0[..HEADER_LEN]
nonce[..HEADER_LEN]
.clone_from_slice(&packet[..HEADER_LEN]);

let sl_index = packet.len() - 16;
Expand All @@ -602,7 +604,8 @@ impl Connection {

let crypted = {
let slice = &packet[HEADER_LEN..HEADER_LEN + len];
secretbox::seal(slice, &nonce, &self.key)
self.cipher.encrypt(&nonce, slice)
.expect("[Voice] Couldn't encrypt packet.")
};
let index = HEADER_LEN + crypted.len();
packet[HEADER_LEN..index].clone_from_slice(&crypted);
Expand Down Expand Up @@ -663,7 +666,7 @@ fn generate_url(endpoint: &mut String) -> Result<Url> {
}

#[inline]
fn encryption_key(client: &mut WsClient) -> Result<Key> {
fn init_cipher(client: &mut WsClient) -> Result<XSalsa20Poly1305> {
loop {
let value = match client.recv_json()? {
Some(value) => value,
Expand All @@ -676,8 +679,14 @@ fn encryption_key(client: &mut WsClient) -> Result<Key> {
return Err(Error::Voice(VoiceError::VoiceModeInvalid));
}

return Key::from_slice(&desc.secret_key)
.ok_or(Error::Voice(VoiceError::KeyGen));
// TODO: use `XSalsa20Poly1305::new_varkey`. See:
// <https://github.com/RustCrypto/traits/pull/191>
if desc.secret_key.len() == KEY_SIZE {
let key = Key::from_slice(&desc.secret_key);
return Ok(XSalsa20Poly1305::new(key));
} else {
return Err(Error::Voice(VoiceError::KeyGen));
}
},
VoiceEvent::Unknown(op, value) => {
debug!(
Expand Down

0 comments on commit 3965e00

Please sign in to comment.