Skip to content

Commit d151315

Browse files
NeloBlivionPaillat-dev
authored andcommitted
fix: support new voice encryption modes (Pycord-Development#2651)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ice Wolfy <[email protected]> Co-authored-by: Paillat <[email protected]> (cherry picked from commit 8e2185c)
1 parent 9e23f4b commit d151315

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

discord/sinks/core.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,25 @@ def __init__(self, data, client):
107107
self.data = bytearray(data)
108108
self.client = client
109109

110-
self.header = data[:12]
111-
self.data = self.data[12:]
112-
113110
unpacker = struct.Struct(">xxHII")
114-
self.sequence, self.timestamp, self.ssrc = unpacker.unpack_from(self.header)
115-
self.decrypted_data = getattr(self.client, f"_decrypt_{self.client.mode}")(self.header, self.data)
111+
self.sequence, self.timestamp, self.ssrc = unpacker.unpack_from(self.data[:12])
112+
113+
# RFC3550 5.1: RTP Fixed Header Fields
114+
if self.client.mode.endswith("_rtpsize"):
115+
# If It Has CSRC Chunks
116+
cutoff = 12 + (data[0] & 0b00_0_0_1111) * 4
117+
# If It Has A Extension
118+
if data[0] & 0b00_0_1_0000:
119+
cutoff += 4
120+
else:
121+
cutoff = 12
122+
123+
self.header = data[:cutoff]
124+
self.data = self.data[cutoff:]
125+
126+
self.decrypted_data = getattr(self.client, f"_decrypt_{self.client.mode}")(
127+
self.header, self.data
128+
)
116129
self.decoded_data = None
117130

118131
self.user_id = None

discord/types/voice.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@
3232
from .member import MemberWithUser
3333
from .snowflake import Snowflake
3434

35-
SupportedModes = Literal["xsalsa20_poly1305_lite", "xsalsa20_poly1305_suffix", "xsalsa20_poly1305"]
35+
SupportedModes = Literal[
36+
"xsalsa20_poly1305_lite",
37+
"xsalsa20_poly1305_suffix",
38+
"xsalsa20_poly1305",
39+
"aead_xchacha20_poly1305_rtpsize",
40+
]
3641

3742

3843
class _VoiceState(TypedDict):

discord/voice_client.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ def __init__(self, client: Client, channel: abc.Connectable):
271271
"xsalsa20_poly1305_lite",
272272
"xsalsa20_poly1305_suffix",
273273
"xsalsa20_poly1305",
274+
"aead_xchacha20_poly1305_rtpsize",
274275
)
275276

276277
@property
@@ -564,19 +565,22 @@ def _get_voice_packet(self, data):
564565
return encrypt_packet(header, data)
565566

566567
def _encrypt_xsalsa20_poly1305(self, header: bytes, data) -> bytes:
568+
# Deprecated, remove in 2.7
567569
box = nacl.secret.SecretBox(bytes(self.secret_key))
568570
nonce = bytearray(24)
569571
nonce[:12] = header
570572

571573
return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext
572574

573575
def _encrypt_xsalsa20_poly1305_suffix(self, header: bytes, data) -> bytes:
576+
# Deprecated, remove in 2.7
574577
box = nacl.secret.SecretBox(bytes(self.secret_key))
575578
nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE)
576579

577580
return header + box.encrypt(bytes(data), nonce).ciphertext + nonce
578581

579582
def _encrypt_xsalsa20_poly1305_lite(self, header: bytes, data) -> bytes:
583+
# Deprecated, remove in 2.7
580584
box = nacl.secret.SecretBox(bytes(self.secret_key))
581585
nonce = bytearray(24)
582586

@@ -585,7 +589,22 @@ def _encrypt_xsalsa20_poly1305_lite(self, header: bytes, data) -> bytes:
585589

586590
return header + box.encrypt(bytes(data), bytes(nonce)).ciphertext + nonce[:4]
587591

592+
def _encrypt_aead_xchacha20_poly1305_rtpsize(self, header: bytes, data) -> bytes:
593+
# Required as of Nov 18 2024
594+
box = nacl.secret.Aead(bytes(self.secret_key))
595+
nonce = bytearray(24)
596+
597+
nonce[:4] = struct.pack(">I", self._lite_nonce)
598+
self.checked_add("_lite_nonce", 1, 4294967295)
599+
600+
return (
601+
header
602+
+ box.encrypt(bytes(data), bytes(header), bytes(nonce)).ciphertext
603+
+ nonce[:4]
604+
)
605+
588606
def _decrypt_xsalsa20_poly1305(self, header, data):
607+
# Deprecated, remove in 2.7
589608
box = nacl.secret.SecretBox(bytes(self.secret_key))
590609

591610
nonce = bytearray(24)
@@ -594,6 +613,7 @@ def _decrypt_xsalsa20_poly1305(self, header, data):
594613
return self.strip_header_ext(box.decrypt(bytes(data), bytes(nonce)))
595614

596615
def _decrypt_xsalsa20_poly1305_suffix(self, header, data):
616+
# Deprecated, remove in 2.7
597617
box = nacl.secret.SecretBox(bytes(self.secret_key))
598618

599619
nonce_size = nacl.secret.SecretBox.NONCE_SIZE
@@ -602,6 +622,7 @@ def _decrypt_xsalsa20_poly1305_suffix(self, header, data):
602622
return self.strip_header_ext(box.decrypt(bytes(data[:-nonce_size]), nonce))
603623

604624
def _decrypt_xsalsa20_poly1305_lite(self, header, data):
625+
# Deprecated, remove in 2.7
605626
box = nacl.secret.SecretBox(bytes(self.secret_key))
606627

607628
nonce = bytearray(24)
@@ -610,6 +631,18 @@ def _decrypt_xsalsa20_poly1305_lite(self, header, data):
610631

611632
return self.strip_header_ext(box.decrypt(bytes(data), bytes(nonce)))
612633

634+
def _decrypt_aead_xchacha20_poly1305_rtpsize(self, header, data):
635+
# Required as of Nov 18 2024
636+
box = nacl.secret.Aead(bytes(self.secret_key))
637+
638+
nonce = bytearray(24)
639+
nonce[:4] = data[-4:]
640+
data = data[:-4]
641+
642+
return self.strip_header_ext(
643+
box.decrypt(bytes(data), bytes(header), bytes(nonce))
644+
)
645+
613646
@staticmethod
614647
def strip_header_ext(data):
615648
if len(data) > 4 and data[0] == 0xBE and data[1] == 0xDE:
@@ -724,11 +757,12 @@ def unpack_audio(self, data):
724757
data: :class:`bytes`
725758
Bytes received by Discord via the UDP connection used for sending and receiving voice data.
726759
"""
727-
if 200 <= data[1] <= 204:
728-
# RTCP received.
729-
# RTCP provides information about the connection
730-
# as opposed to actual audio data, so it's not
731-
# important at the moment.
760+
if data[1] != 0x78:
761+
# We Should Ignore Any Payload Types We Do Not Understand
762+
# Ref RFC 3550 5.1 payload type
763+
# At Some Point We Noted That We Should Ignore Only Types 200 - 204 inclusive.
764+
# They Were Marked As RTCP: Provides Information About The Connection
765+
# This Was Too Broad Of A Whitelist, It Is Unclear If This Is Too Narrow Of A Whitelist
732766
return
733767
if self.paused:
734768
return

0 commit comments

Comments
 (0)