From 5a62808c30632b72da99282c7483af1b2d57729d 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 4dc485cbf7..8cc5bd6a1d 100644 --- a/discord/types/voice.py +++ b/discord/types/voice.py @@ -32,7 +32,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 b9d4766883..77e193ec9b 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -270,6 +270,7 @@ def __init__(self, client: Client, channel: abc.Connectable): "xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305", + "aead_xchacha20_poly1305_rtpsize", ) @property @@ -564,6 +565,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 @@ -571,12 +573,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) @@ -585,7 +589,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) @@ -594,6 +609,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 @@ -602,6 +618,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) @@ -610,6 +627,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 data[0] == 0xBE and data[1] == 0xDE and len(data) > 4: From 1ff9a196b7283da701fa1efd1731e4fafca1ff10 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 8cc5bd6a1d..899719185c 100644 --- a/discord/types/voice.py +++ b/discord/types/voice.py @@ -32,7 +32,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 77e193ec9b..341c7f6828 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -594,10 +594,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 @@ -635,7 +639,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 f53bf9095285bc1ea7943f164d625f8e8152def8 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 341c7f6828..3d97111ee2 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -638,6 +638,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)) @@ -761,11 +763,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 7f1871602dc280718147adf8e646c879c56cdf45 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 3d97111ee2..8802382288 100644 --- a/discord/voice_client.py +++ b/discord/voice_client.py @@ -638,8 +638,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))