diff --git a/Cargo.toml b/Cargo.toml index 6ea1339..08e43a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ sqlx = { version = "0.7.3", features = [ "any", ], optional = true } discortp = { version = "0.5.0", optional = true, features = ["rtp", "discord", "demux"] } -crypto_secretbox = {version = "0.1.1", optional = true} +crypto_secretbox = { version = "0.1.1", optional = true } rand = "0.8.5" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/src/errors.rs b/src/errors.rs index 56e3222..1e9087d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -144,6 +144,7 @@ custom_error! { NoData = "We have not set received the necessary data to perform this operation.", // Encryption errors + EncryptionModeNotImplemented{encryption_mode: String} = "Voice encryption mode {encryption_mode} is not yet implemented.", NoKey = "Tried to encrypt / decrypt rtp data, but no key has been received yet", FailedEncryption = "Tried to encrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new", FailedDecryption = "Tried to decrypt rtp data, but failed. Most likely this is an issue chorus' nonce generation. Please open an issue on the chorus github: https://github.com/polyphony-chat/chorus/issues/new", diff --git a/src/types/events/voice_gateway/mod.rs b/src/types/events/voice_gateway/mod.rs index 8cef9df..f8618e9 100644 --- a/src/types/events/voice_gateway/mod.rs +++ b/src/types/events/voice_gateway/mod.rs @@ -88,14 +88,40 @@ pub enum VoiceEncryptionMode { // Officially Undocumented /// Not implemented yet, we have no idea what the rtpsize nonces are. Xsalsa20Poly1305LiteRtpsize, - /// Not implemented yet + /// Not implemented yet, we have no idea what the nonce is. AeadAes256Gcm, - /// Not implemented yet + /// Not implemented yet, we have no idea what the rtpsize nonces are. AeadAes256GcmRtpsize, /// Not implemented yet, we have no idea what the rtpsize nonces are. AeadXchacha20Poly1305Rtpsize, } +impl VoiceEncryptionMode { + /// Returns whether this encryption mode uses Xsalsa20Poly1305 encryption. + pub fn is_xsalsa20_poly1305(&self) -> bool { + match *self { + VoiceEncryptionMode::Xsalsa20Poly1305 + | VoiceEncryptionMode::Xsalsa20Poly1305Lite + | VoiceEncryptionMode::Xsalsa20Poly1305Suffix + | VoiceEncryptionMode::Xsalsa20Poly1305LiteRtpsize => true, + _ => false, + } + } + + /// Returns whether this encryption mode uses AeadAes256Gcm encryption. + pub fn is_aead_aes256_gcm(&self) -> bool { + match *self { + VoiceEncryptionMode::AeadAes256Gcm | VoiceEncryptionMode::AeadAes256GcmRtpsize => true, + _ => false, + } + } + + /// Returns whether this encryption mode uses AeadXchacha20Poly1305 encryption. + pub fn is_aead_xchacha20_poly1305(&self) -> bool { + *self == VoiceEncryptionMode::AeadXchacha20Poly1305Rtpsize + } +} + /// The possible audio codecs to use #[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[serde(rename_all = "lowercase")] diff --git a/src/voice/udp/handle.rs b/src/voice/udp/handle.rs index 3c740f8..ecaf3ab 100644 --- a/src/voice/udp/handle.rs +++ b/src/voice/udp/handle.rs @@ -148,32 +148,61 @@ impl UdpHandle { .last_udp_encryption_nonce .unwrap_or_default() .wrapping_add(1); + data_lock.last_udp_encryption_nonce = Some(nonce); drop(data_lock); // TODO: Is le correct? This is not documented anywhere let mut bytes = nonce.to_le_bytes().to_vec(); - // This is 4 bytes, it has to be 24, so we need to append 20 + + // This is 4 bytes, it has to be a different size, appends 0s while bytes.len() < 24 { bytes.push(0); } bytes } _ => { - // TODO: Implement aead_aes256_gcm - todo!("This voice encryption mode is not yet implemented."); + error!( + "This voice encryption mode ({:?}) is not yet implemented.", + session_description.encryption_mode + ); + return Err(VoiceUdpError::EncryptionModeNotImplemented { + encryption_mode: format!("{:?}", session_description.encryption_mode), + }); } }; - let nonce = GenericArray::from_slice(&nonce_bytes); - let key = GenericArray::from_slice(&session_description.secret_key); - let encryptor = XSalsa20Poly1305::new(key); + let encryption_result; - let encryption_result = encryptor.encrypt(nonce, payload); + if session_description.encryption_mode.is_xsalsa20_poly1305() { + let nonce = GenericArray::from_slice(&nonce_bytes); + + let encryptor = XSalsa20Poly1305::new(key); + + encryption_result = encryptor.encrypt(nonce, payload); + } + // Note: currently unused because I have no idea what the AeadAes256Gcm nonce is + /*else if session_description.encryption_mode.is_aead_aes256_gcm() { + let nonce = GenericArray::from_slice(&nonce_bytes); + + let encryptor = Aes256Gcm::new(key); + + encryption_result = encryptor.encrypt(nonce, payload); + + }*/ + else { + error!( + "This voice encryption mode ({:?}) is not yet implemented.", + session_description.encryption_mode + ); + return Err(VoiceUdpError::EncryptionModeNotImplemented { + encryption_mode: format!("{:?}", session_description.encryption_mode), + }); + } if encryption_result.is_err() { - // Safety: If encryption errors here, it's chorus' fault, and it makes no sense to + // Safety: If encryption fails here, it's chorus' fault, and it makes no sense to // return the error to the user. // // This is not an error the user should account for, which is why we throw it here. diff --git a/src/voice/udp/handler.rs b/src/voice/udp/handler.rs index 53a4c3d..650111b 100644 --- a/src/voice/udp/handler.rs +++ b/src/voice/udp/handler.rs @@ -188,7 +188,8 @@ impl UdpHandler { return; } _ => { - unreachable!(); + error!("VUDP: Failed to decrypt voice data: {}", err); + return; } } } @@ -306,18 +307,45 @@ impl UdpHandler { get_xsalsa20_poly1305_lite_nonce(packet_bytes) } _ => { - // TODO: Implement aead_aes256_gcm - todo!("This voice encryption mode is not yet implemented."); + error!( + "This voice encryption mode ({:?}) is not yet implemented.", + session_description.encryption_mode + ); + return Err(VoiceUdpError::EncryptionModeNotImplemented { + encryption_mode: format!("{:?}", session_description.encryption_mode), + }); } }; - let nonce = GenericArray::from_slice(&nonce_bytes); - let key = GenericArray::from_slice(&session_description.secret_key); - let decryptor = XSalsa20Poly1305::new(key); + let decryption_result; - let decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref()); + if session_description.encryption_mode.is_xsalsa20_poly1305() { + let nonce = GenericArray::from_slice(&nonce_bytes); + + let decryptor = XSalsa20Poly1305::new(key); + + decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref()); + } + // Note: currently unused because I have no idea what the AeadAes256Gcm nonce is + /*else if session_description.encryption_mode.is_aead_aes256_gcm() { + let nonce = GenericArray::from_slice(&nonce_bytes); + + let decryptor = Aes256Gcm::new(key); + + decryption_result = decryptor.decrypt(nonce, ciphertext.as_ref()); + + }*/ + else { + error!( + "This voice encryption mode ({:?}) is not yet implemented.", + session_description.encryption_mode + ); + return Err(VoiceUdpError::EncryptionModeNotImplemented { + encryption_mode: format!("{:?}", session_description.encryption_mode), + }); + } // Note: this may seem like we are throwing away valuable error handling data, // but the decryption error provides no extra info.