From b91ef855d5dca4c5aef75f20c6f3bcc6c77df181 Mon Sep 17 00:00:00 2001 From: UK <41271523+NeloBlivion@users.noreply.github.com> Date: Sun, 17 Nov 2024 02:35:18 +0000 Subject: [PATCH 1/4] support aead_xchacha20_poly1305_rtpsize --- discord/types/voice.py | 2 +- discord/voice_client.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/discord/types/voice.py b/discord/types/voice.py index 732f9826d7..89901a83a1 100644 --- a/discord/types/voice.py +++ b/discord/types/voice.py @@ -33,7 +33,7 @@ from .snowflake import Snowflake SupportedModes = Literal[ - "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305" + "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305", "aead_xchacha20_poly1305_rtpsize" ] diff --git a/discord/voice_client.py b/discord/voice_client.py index 75902ecbe2..c04c336af1 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -271,6 +271,7 @@ def __init__(self, client: Client, channel: abc.Connectable): "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305", + "aead_xchacha20_poly1305_rtpsize", ) @property @@ -565,6 +566,7 @@ def _get_voice_packet(self, data): return encrypt_packet(header, data) def _encrypt_xsalsa20_poly1305(self, header: bytes, data) -> bytes: + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce = bytearray(24) nonce[:12] = header @@ -572,12 +574,14 @@ def _encrypt_xsalsa20_poly1305(self, header: bytes, data) -> bytes: return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext def _encrypt_xsalsa20_poly1305_suffix(self, header: bytes, data) -> bytes: + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) return header + box.encrypt(bytes(data), nonce).ciphertext + nonce def _encrypt_xsalsa20_poly1305_lite(self, header: bytes, data) -> bytes: + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce = bytearray(24) @@ -586,7 +590,18 @@ def _encrypt_xsalsa20_poly1305_lite(self, header: bytes, data) -> bytes: return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext + nonce[:4] + def _encrypt_aead_xchacha20_poly1305_rtpsize(self, header: bytes, data) -> bytes: + # Required as of Nov 18 2024 + box = nacl.secret.Aead(bytes(self.secret_key)) + nonce = bytearray(24) + + nonce[:4] = struct.pack('>I', self._lite_nonce) + self.checked_add('_lite_nonce', 1, 4294967295) + + return header + box.encrypt(bytes(data), bytes(header), bytes(nonce)).ciphertext + nonce[:4] + def _decrypt_xsalsa20_poly1305(self, header, data): + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce = bytearray(24) @@ -595,6 +610,7 @@ def _decrypt_xsalsa20_poly1305(self, header, data): return self.strip_header_ext(box.decrypt(bytes(data), bytes(nonce))) def _decrypt_xsalsa20_poly1305_suffix(self, header, data): + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce_size = nacl.secret.SecretBox.NONCE_SIZE @@ -603,6 +619,7 @@ def _decrypt_xsalsa20_poly1305_suffix(self, header, data): return self.strip_header_ext(box.decrypt(bytes(data[:-nonce_size]), nonce)) def _decrypt_xsalsa20_poly1305_lite(self, header, data): + # Deprecated, remove in 2.7 box = nacl.secret.SecretBox(bytes(self.secret_key)) nonce = bytearray(24) @@ -611,6 +628,16 @@ def _decrypt_xsalsa20_poly1305_lite(self, header, data): return self.strip_header_ext(box.decrypt(bytes(data), bytes(nonce))) + def _decrypt_aead_xchacha20_poly1305_rtpsize(self, header, data): + # Required as of Nov 18 2024 + box = nacl.secret.Aead(bytes(self.secret_key)) + + nonce = bytearray(24) + nonce[:4] = data[-4:] + data = data[:-4] + + return self.strip_header_ext(box.decrypt(bytes(data), bytes(header), bytes(nonce))) + @staticmethod def strip_header_ext(data): if len(data) > 4 and data[0] == 0xBE and data[1] == 0xDE: From 756de66d274c178a48702e226ccdc67a0d142980 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2024 02:38:16 +0000 Subject: [PATCH 2/4] style(pre-commit): auto fixes from pre-commit.com hooks --- discord/types/voice.py | 5 ++++- discord/voice_client.py | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/discord/types/voice.py b/discord/types/voice.py index 89901a83a1..68d99ccd48 100644 --- a/discord/types/voice.py +++ b/discord/types/voice.py @@ -33,7 +33,10 @@ from .snowflake import Snowflake SupportedModes = Literal[ - "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305", "aead_xchacha20_poly1305_rtpsize" + "xsalsa20_poly1305_lite", + "xsalsa20_poly1305_suffix", + "xsalsa20_poly1305", + "aead_xchacha20_poly1305_rtpsize", ] diff --git a/discord/voice_client.py b/discord/voice_client.py index c04c336af1..c69110f373 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -595,10 +595,14 @@ def _encrypt_aead_xchacha20_poly1305_rtpsize(self, header: bytes, data) -> bytes box = nacl.secret.Aead(bytes(self.secret_key)) nonce = bytearray(24) - nonce[:4] = struct.pack('>I', self._lite_nonce) - self.checked_add('_lite_nonce', 1, 4294967295) + nonce[:4] = struct.pack(">I", self._lite_nonce) + self.checked_add("_lite_nonce", 1, 4294967295) - return header + box.encrypt(bytes(data), bytes(header), bytes(nonce)).ciphertext + nonce[:4] + return ( + header + + box.encrypt(bytes(data), bytes(header), bytes(nonce)).ciphertext + + nonce[:4] + ) def _decrypt_xsalsa20_poly1305(self, header, data): # Deprecated, remove in 2.7 @@ -636,7 +640,9 @@ def _decrypt_aead_xchacha20_poly1305_rtpsize(self, header, data): nonce[:4] = data[-4:] data = data[:-4] - return self.strip_header_ext(box.decrypt(bytes(data), bytes(header), bytes(nonce))) + return self.strip_header_ext( + box.decrypt(bytes(data), bytes(header), bytes(nonce)) + ) @staticmethod def strip_header_ext(data): From 2b66debdb0ecaa2b5dc8f89770431cb26a2c0b92 Mon Sep 17 00:00:00 2001 From: Ice Wolfy Date: Sun, 19 Jan 2025 23:55:29 -0500 Subject: [PATCH 3/4] fix: Add Checks For Payload Type And Header Length --- discord/sinks/core.py | 19 +++++++++++++++---- discord/voice_client.py | 13 ++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/discord/sinks/core.py b/discord/sinks/core.py index c8ea31a82a..90fdbf7d19 100644 --- a/discord/sinks/core.py +++ b/discord/sinks/core.py @@ -107,11 +107,22 @@ def __init__(self, data, client): self.data = bytearray(data) self.client = client - self.header = data[:12] - self.data = self.data[12:] - unpacker = struct.Struct(">xxHII") - self.sequence, self.timestamp, self.ssrc = unpacker.unpack_from(self.header) + self.sequence, self.timestamp, self.ssrc = unpacker.unpack_from(self.data[:12]) + + # RFC3550 5.1: RTP Fixed Header Fields + if self.client.mode.endswith("_rtpsize"): + # If It Has CSRC Chunks + cutoff = 12 + (data[0] & 0b00_0_0_1111) * 4 + # If It Has A Extension + if data[0] & 0b00_0_1_0000: + cutoff += 4 + else: + cutoff = 12 + + self.header = data[:cutoff] + self.data = self.data[cutoff:] + self.decrypted_data = getattr(self.client, f"_decrypt_{self.client.mode}")( self.header, self.data ) diff --git a/discord/voice_client.py b/discord/voice_client.py index c69110f373..ccd184b6b8 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -639,6 +639,8 @@ def _decrypt_aead_xchacha20_poly1305_rtpsize(self, header, data): nonce = bytearray(24) nonce[:4] = data[-4:] data = data[:-4] + print(bytes(data)) + print(bytes(header)) return self.strip_header_ext( box.decrypt(bytes(data), bytes(header), bytes(nonce)) @@ -762,11 +764,12 @@ def unpack_audio(self, data): data: :class:`bytes` Bytes received by Discord via the UDP connection used for sending and receiving voice data. """ - if 200 <= data[1] <= 204: - # RTCP received. - # RTCP provides information about the connection - # as opposed to actual audio data, so it's not - # important at the moment. + if data[1] != 0x78: + # We Should Ignore Any Payload Types We Do Not Understand + # Ref RFC 3550 5.1 payload type + # At Some Point We Noted That We Should Ignore Only Types 200 - 204 inclusive. + # They Were Marked As RTCP: Provides Information About The Connection + # This Was Too Broad Of A Whitelist, It Is Unclear If This Is Too Narrow Of A Whitelist return if self.paused: return From dae61591a4c92d491b0a27b8798b1c4681e34f30 Mon Sep 17 00:00:00 2001 From: Ice Wolfy Date: Mon, 20 Jan 2025 00:30:46 -0500 Subject: [PATCH 4/4] chore: Remove Prints --- discord/voice_client.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/discord/voice_client.py b/discord/voice_client.py index ccd184b6b8..a590f0fd24 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -639,8 +639,6 @@ def _decrypt_aead_xchacha20_poly1305_rtpsize(self, header, data): nonce = bytearray(24) nonce[:4] = data[-4:] data = data[:-4] - print(bytes(data)) - print(bytes(header)) return self.strip_header_ext( box.decrypt(bytes(data), bytes(header), bytes(nonce))