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 PlayInterface = require('./util/PlayInterface');
const SUPPORTED_MODES = [
'xsalsa20_poly1305_lite',
'xsalsa20_poly1305_suffix',
'xsalsa20_poly1305',
];
/**
* Represents a connection to a guild's voice server.
* ```js
@@ -382,9 +388,16 @@ class VoiceConnection extends EventEmitter {
* @param {Object} data The received data
* @private
*/
onReady({ port, ssrc, ip }) {
onReady({ port, ssrc, ip, modes }) {
this.authentication.port = port;
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);
}

View File

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

View File

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

View File

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