Skip to content

Commit

Permalink
feat(radio): add new encryption methods and remove the deprecated
Browse files Browse the repository at this point in the history
  • Loading branch information
vittee committed Nov 19, 2024
1 parent 6774c53 commit 29ad94c
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 51 deletions.
64 changes: 22 additions & 42 deletions packages/radio/src/discord/voice/network/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class VoiceConnection extends TypedEmitter<VoiceConnectionEvents> {
sequence: randomNBit(16),
timestamp: randomNBit(32),
nonce: 0,
nonceBuffer: Buffer.alloc(24),
nonceBuffer: Buffer.alloc(encryptionMode === 'aead_aes256_gcm_rtpsize' ? 12 : 24),
speaking: false,
packetsPlayed: 0,
},
Expand Down Expand Up @@ -445,54 +445,34 @@ function chooseEncryptionMode(serverModes: EncryptionMode[]) {
function packVoiceData(opusPacket: Buffer, header: Buffer, connectionData: ConnectionData, nonce: Buffer) {
const { secretKey, encryptionMode } = connectionData;

const secretKeyBuffer = Buffer.from(secretKey);

if (encryptionMode === 'aead_xchacha20_poly1305_rtpsize') {
connectionData.nonce++;

if (connectionData.nonce > 2 ** 32 - 1) {
connectionData.nonce = 0;
}
connectionData.nonce++;

connectionData.nonceBuffer.writeUInt32BE(connectionData.nonce, 0);

return [
header,
secretbox.aeadClose(opusPacket, header, connectionData.nonceBuffer, secretKeyBuffer),
connectionData.nonceBuffer.subarray(0, 4),
];
if (connectionData.nonce > 2 ** 32 - 1) {
connectionData.nonce = 0;
}

if (encryptionMode === 'xsalsa20_poly1305_lite') {
connectionData.nonce++;

if (connectionData.nonce > 2 ** 32 - 1) {
connectionData.nonce = 0;
}
connectionData.nonceBuffer.writeUInt32BE(connectionData.nonce, 0);

connectionData.nonceBuffer.writeUInt32BE(connectionData.nonce, 0);
const noncePadding = connectionData.nonceBuffer.subarray(0, 4);

return [
header,
secretbox.close(opusPacket, connectionData.nonceBuffer, secretKeyBuffer),
connectionData.nonceBuffer.subarray(0, 4),
];
}
const secretKeyBuffer = Buffer.from(secretKey);

if (encryptionMode === 'xsalsa20_poly1305_suffix') {
const random = secretbox.random(24, connectionData.nonceBuffer);
return [
header,
secretbox.close(opusPacket, random, secretKeyBuffer),
random
];
}
switch (encryptionMode) {
case 'aead_xchacha20_poly1305_rtpsize': {
return [
header,
secretbox.aeadClose(opusPacket, header, connectionData.nonceBuffer, secretKeyBuffer),
noncePadding
];
}

if (encryptionMode === 'xsalsa20_poly1305') {
return [
header,
secretbox.close(opusPacket, nonce, secretKeyBuffer)
];
case 'aead_aes256_gcm_rtpsize': {
return [
header,
secretbox.gcmClose(opusPacket, header, connectionData.nonceBuffer, secretKeyBuffer),
noncePadding
]
}
}

return [];
Expand Down
18 changes: 9 additions & 9 deletions packages/radio/src/discord/voice/network/payload.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import crypto from 'node:crypto';
import { GatewayOpcodes, GatewayVoiceStateUpdateData } from "discord-api-types/v10";
import { VoiceOpcodes } from "discord-api-types/voice/v4";

Expand All @@ -16,18 +17,17 @@ export interface GatewayVoiceStateUpdatePayload extends GatewayVoicePayload<Gate

}

export type EncryptionMode = 'aead_aes256_gcm_rtpsize' | 'aead_xchacha20_poly1305_rtpsize';

export const ENCRYPTION_MODES = [
// Required by voice v8
'aead_xchacha20_poly1305_rtpsize',

// Deprecated
// TODO: Remove this before Nov 18th 2024
'xsalsa20_poly1305_lite',
'xsalsa20_poly1305_suffix',
'xsalsa20_poly1305'
] as const;
'aead_xchacha20_poly1305_rtpsize'
] as EncryptionMode[];

export type EncryptionMode = typeof ENCRYPTION_MODES[number];
// optional, if supported by the system
if (crypto.getCiphers().includes('aes-256-gcm')) {
ENCRYPTION_MODES.push('aead_aes256_gcm_rtpsize');
}

export interface VoicePayload<D = unknown> extends Payload<VoiceOpcodes, D> {
seq?: number;
Expand Down
8 changes: 8 additions & 0 deletions packages/radio/src/discord/voice/secretbox.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import crypto from 'node:crypto';

import {
crypto_aead_xchacha20poly1305_ietf_encrypt,
crypto_aead_xchacha20poly1305_ietf_ABYTES,
Expand Down Expand Up @@ -25,6 +27,12 @@ export function aeadClose(opusPacket: Buffer, header: Buffer, nonce: Buffer, sec
return output;
}

export function gcmClose(opusPacket: Buffer, header: Buffer, nonce: Buffer, secretKey: Buffer) {
const cipher = crypto.createCipheriv('aes-256-gcm', secretKey, nonce);
cipher.setAAD(header);
return Buffer.concat([cipher.update(opusPacket), cipher.final(), cipher.getAuthTag()]);
}

export function close(opusPacket: Buffer, nonce: Buffer, secretKey: Buffer) {
const output = Buffer.allocUnsafe(opusPacket.length + crypto_box_MACBYTES);
crypto_secretbox_easy(output, opusPacket, nonce, secretKey);
Expand Down

0 comments on commit 29ad94c

Please sign in to comment.