voice: support xsalsa20_poly1305_lite and xsalsa20_poly1305_suffix

This commit is contained in:
Amish Shah
2018-05-10 12:11:22 +01:00
parent 685814aa61
commit 43c92c13e2
4 changed files with 42 additions and 9 deletions

View File

@@ -8,6 +8,12 @@ const EventEmitter = require('events');
const { Error } = require('../../errors'); const { Error } = require('../../errors');
const PlayInterface = require('./util/PlayInterface'); const PlayInterface = require('./util/PlayInterface');
const SUPPORTED_MODES = [
'xsalsa20_poly1305_lite',
'xsalsa20_poly1305_suffix',
'xsalsa20_poly1305',
];
/** /**
* Represents a connection to a guild's voice server. * Represents a connection to a guild's voice server.
* ```js * ```js
@@ -382,9 +388,16 @@ class VoiceConnection extends EventEmitter {
* @param {Object} data The received data * @param {Object} data The received data
* @private * @private
*/ */
onReady({ port, ssrc, ip }) { onReady({ port, ssrc, ip, modes }) {
this.authentication.port = port; this.authentication.port = port;
this.authentication.ssrc = ssrc; this.authentication.ssrc = ssrc;
for (let mode of modes) {
if (SUPPORTED_MODES.includes(mode)) {
this.authentication.encryptionMode = mode;
this.emit('debug', `Selecting the ${mode} mode`);
break;
}
}
this.sockets.udp.createUDPSocket(ip); this.sockets.udp.createUDPSocket(ip);
} }

View File

@@ -7,8 +7,8 @@ const FRAME_LENGTH = 20;
const CHANNELS = 2; const CHANNELS = 2;
const TIMESTAMP_INC = (48000 / 100) * CHANNELS; const TIMESTAMP_INC = (48000 / 100) * CHANNELS;
const MAX_NONCE_SIZE = (2 ** 32) - 1;
const nonce = Buffer.alloc(24); const nonce = Buffer.alloc(24);
nonce.fill(0);
/** /**
* @external WritableStream * @external WritableStream
@@ -42,6 +42,9 @@ class StreamDispatcher extends Writable {
this.streamOptions = streamOptions; this.streamOptions = streamOptions;
this.streams = streams; this.streams = streams;
this._nonce = 0;
this._nonceBuffer = Buffer.alloc(24);
/** /**
* The time that the stream was paused at (null if not paused) * The time that the stream was paused at (null if not paused)
* @type {?number} * @type {?number}
@@ -217,9 +220,26 @@ class StreamDispatcher extends Writable {
this._sendPacket(this._createPacket(this._sdata.sequence, this._sdata.timestamp, chunk)); this._sendPacket(this._createPacket(this._sdata.sequence, this._sdata.timestamp, chunk));
} }
_encrypt(buffer) {
const { secretKey, encryptionMode } = this.player.voiceConnection.authentication;
if (encryptionMode === 'xsalsa20_poly1305_lite') {
this._nonce++;
if (this._nonce > MAX_NONCE_SIZE) this._nonce = 0;
this._nonceBuffer.writeUInt32BE(this._nonce, 0);
return [
secretbox.methods.close(buffer, this._nonceBuffer, secretKey),
this._nonceBuffer.slice(0, 4),
];
} else if (encryptionMode === 'xsalsa20_poly1305_suffix') {
const random = secretbox.methods.random(24);
return [secretbox.methods.close(buffer, random, secretKey), random];
} else {
return [secretbox.methods.close(buffer, nonce, secretKey)];
}
}
_createPacket(sequence, timestamp, buffer) { _createPacket(sequence, timestamp, buffer) {
const packetBuffer = Buffer.alloc(buffer.length + 28); const packetBuffer = Buffer.alloc(12);
packetBuffer.fill(0);
packetBuffer[0] = 0x80; packetBuffer[0] = 0x80;
packetBuffer[1] = 0x78; packetBuffer[1] = 0x78;
@@ -228,10 +248,7 @@ class StreamDispatcher extends Writable {
packetBuffer.writeUIntBE(this.player.voiceConnection.authentication.ssrc, 8, 4); packetBuffer.writeUIntBE(this.player.voiceConnection.authentication.ssrc, 8, 4);
packetBuffer.copy(nonce, 0, 0, 12); packetBuffer.copy(nonce, 0, 0, 12);
buffer = secretbox.methods.close(buffer, nonce, this.player.voiceConnection.authentication.secretKey); return Buffer.concat([packetBuffer, ...this._encrypt(buffer, sequence)]);
for (let i = 0; i < buffer.length; i++) packetBuffer[i + 12] = buffer[i];
return packetBuffer;
} }
_sendPacket(packet) { _sendPacket(packet) {

View File

@@ -104,7 +104,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
data: { data: {
address: packet.address, address: packet.address,
port: packet.port, port: packet.port,
mode: 'xsalsa20_poly1305', mode: this.voiceConnection.authentication.encryptionMode,
}, },
}, },
}); });

View File

@@ -2,14 +2,17 @@ const libs = {
sodium: sodium => ({ sodium: sodium => ({
open: sodium.api.crypto_secretbox_open_easy, open: sodium.api.crypto_secretbox_open_easy,
close: sodium.api.crypto_secretbox_easy, close: sodium.api.crypto_secretbox_easy,
random: n => sodium.randombytes_buf(n),
}), }),
'libsodium-wrappers': sodium => ({ 'libsodium-wrappers': sodium => ({
open: sodium.crypto_secretbox_open_easy, open: sodium.crypto_secretbox_open_easy,
close: sodium.crypto_secretbox_easy, close: sodium.crypto_secretbox_easy,
random: n => sodium.randombytes_buf(n),
}), }),
tweetnacl: tweetnacl => ({ tweetnacl: tweetnacl => ({
open: tweetnacl.secretbox.open, open: tweetnacl.secretbox.open,
close: tweetnacl.secretbox, close: tweetnacl.secretbox,
random: n => tweetnacl.randomBytes(n),
}), }),
}; };