Initial encryption support
This commit is contained in:
@@ -62,6 +62,9 @@
|
||||
<Content Include="lib\libopus.so">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="lib\libsodium.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="lib\opus.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
@@ -101,6 +104,9 @@
|
||||
<Compile Include="..\Discord.Net\Audio\OpusEncoder.cs">
|
||||
<Link>Audio\OpusEncoder.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\Audio\Sodium.cs">
|
||||
<Link>Audio\Sodium.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Discord.Net\Collections\AsyncCollection.cs">
|
||||
<Link>Collections\AsyncCollection.cs</Link>
|
||||
</Compile>
|
||||
|
||||
BIN
src/Discord.Net.Net45/lib/libsodium.dll
Normal file
BIN
src/Discord.Net.Net45/lib/libsodium.dll
Normal file
Binary file not shown.
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Discord.Audio
|
||||
{
|
||||
internal unsafe class Opus
|
||||
internal static unsafe class Opus
|
||||
{
|
||||
[DllImport("lib/opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr CreateEncoder(int Fs, int channels, int application, out Error error);
|
||||
|
||||
15
src/Discord.Net/Audio/Sodium.cs
Normal file
15
src/Discord.Net/Audio/Sodium.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Discord.Audio
|
||||
{
|
||||
internal static class Sodium
|
||||
{
|
||||
[DllImport("lib/libsodium", EntryPoint = "crypto_stream_xor", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern int StreamXOR(byte[] output, byte[] msg, long msgLength, byte[] nonce, byte[] secret);
|
||||
|
||||
public static int Encrypt(byte[] buffer, int inputLength, byte[] output, byte[] nonce, byte[] secret)
|
||||
{
|
||||
return StreamXOR(output, buffer, inputLength, nonce, secret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Discord
|
||||
{
|
||||
public class DiscordClientConfig
|
||||
{
|
||||
/// <summary> Specifies the minimum log level severity that will be sent to the LogMessage event. Warning: setting this to verbose will hinder performance but should help investigate any internal issues. </summary>
|
||||
/// <summary> Specifies the minimum log level severity that will be sent to the LogMessage event. Warning: setting this to debug will really hurt performance but should help investigate any internal issues. </summary>
|
||||
public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
|
||||
private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
|
||||
|
||||
@@ -36,8 +36,12 @@ namespace Discord
|
||||
/// <summary> (Experimental) Enables the voice websocket and UDP client. This option requires the opus .dll or .so be in the local lib/ folder. </summary>
|
||||
public bool EnableVoice { get { return _enableVoice; } set { SetValue(ref _enableVoice, value); } }
|
||||
private bool _enableVoice = false;
|
||||
/// <summary> (Experimental) Enables the voice websocket and UDP client. This option requires the libsodium .dll or .so be in the local lib/ folder. </summary>
|
||||
public bool EnableVoiceEncryption { get { return _enableVoiceEncryption; } set { SetValue(ref _enableVoiceEncryption, value); } }
|
||||
private bool _enableVoiceEncryption = false;
|
||||
#else
|
||||
internal bool EnableVoice => false;
|
||||
internal bool EnableVoiceEncryption => false;
|
||||
#endif
|
||||
/// <summary> (Experimental) Enables or disables the internal message queue. This will allow SendMessage to return immediately and handle messages internally. Messages will set the IsQueued and HasFailed properties to show their progress. </summary>
|
||||
public bool UseMessageQueue { get { return _useMessageQueue; } set { SetValue(ref _useMessageQueue, value); } }
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Discord.WebSockets.Voice
|
||||
private byte[] _secretKey;
|
||||
private ushort _sequence;
|
||||
private byte[] _encodingBuffer;
|
||||
private string _serverId, _userId, _sessionId, _token;
|
||||
private string _serverId, _userId, _sessionId, _token, _encryptionMode;
|
||||
|
||||
#if USE_THREAD
|
||||
private Thread _sendThread;
|
||||
@@ -213,12 +213,18 @@ namespace Discord.WebSockets.Voice
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
byte[] rtpPacket = new byte[_encodingBuffer.Length + 12];
|
||||
byte[] nonce = null;
|
||||
rtpPacket[0] = 0x80; //Flags;
|
||||
rtpPacket[1] = 0x78; //Payload Type
|
||||
rtpPacket[8] = (byte)((_ssrc >> 24) & 0xFF);
|
||||
rtpPacket[9] = (byte)((_ssrc >> 16) & 0xFF);
|
||||
rtpPacket[10] = (byte)((_ssrc >> 8) & 0xFF);
|
||||
rtpPacket[11] = (byte)((_ssrc >> 0) & 0xFF);
|
||||
if (_isEncrypted)
|
||||
{
|
||||
nonce = new byte[24];
|
||||
Buffer.BlockCopy(rtpPacket, 0, nonce, 0, 12);
|
||||
}
|
||||
|
||||
while (!cancelToken.IsCancellationRequested)
|
||||
{
|
||||
@@ -238,6 +244,13 @@ namespace Discord.WebSockets.Voice
|
||||
rtpPacket[5] = (byte)((timestamp >> 16) & 0xFF);
|
||||
rtpPacket[6] = (byte)((timestamp >> 8) & 0xFF);
|
||||
rtpPacket[7] = (byte)((timestamp >> 0) & 0xFF);
|
||||
if (_isEncrypted)
|
||||
{
|
||||
Buffer.BlockCopy(rtpPacket, 2, nonce, 2, 6); //Update nonce
|
||||
int ret = Sodium.Encrypt(packet, packet.Length, packet, nonce, _secretKey);
|
||||
if (ret != 0)
|
||||
continue;
|
||||
}
|
||||
Buffer.BlockCopy(packet, 0, rtpPacket, 12, packet.Length);
|
||||
#if USE_THREAD
|
||||
_udp.Send(rtpPacket, packet.Length + 12);
|
||||
@@ -298,8 +311,22 @@ namespace Discord.WebSockets.Voice
|
||||
_heartbeatInterval = payload.HeartbeatInterval;
|
||||
_ssrc = payload.SSRC;
|
||||
_endpoint = new IPEndPoint((await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(), payload.Port);
|
||||
//_mode = payload.Modes.LastOrDefault();
|
||||
_isEncrypted = !payload.Modes.Contains("plain");
|
||||
|
||||
if (_client.Config.EnableVoiceEncryption)
|
||||
{
|
||||
if (payload.Modes.Contains(EncryptedMode))
|
||||
{
|
||||
_encryptionMode = EncryptedMode;
|
||||
_isEncrypted = true;
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("Unexpected encryption format.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_encryptionMode = UnencryptedMode;
|
||||
_isEncrypted = false;
|
||||
}
|
||||
_udp.Connect(_endpoint);
|
||||
|
||||
_sequence = (ushort)_rand.Next(0, ushort.MaxValue);
|
||||
@@ -361,7 +388,7 @@ namespace Discord.WebSockets.Voice
|
||||
var login2 = new Login2Command();
|
||||
login2.Payload.Protocol = "udp";
|
||||
login2.Payload.SocketData.Address = ip;
|
||||
login2.Payload.SocketData.Mode = _isEncrypted ? EncryptedMode : UnencryptedMode;
|
||||
login2.Payload.SocketData.Mode = _encryptionMode;
|
||||
login2.Payload.SocketData.Port = port;
|
||||
QueueMessage(login2);
|
||||
}
|
||||
|
||||
BIN
src/Discord.Net/lib/libsodium.dll
Normal file
BIN
src/Discord.Net/lib/libsodium.dll
Normal file
Binary file not shown.
Reference in New Issue
Block a user