Initial encryption support
This commit is contained in:
@@ -62,6 +62,9 @@
|
|||||||
<Content Include="lib\libopus.so">
|
<Content Include="lib\libopus.so">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="lib\libsodium.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="lib\opus.dll">
|
<Content Include="lib\opus.dll">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -101,6 +104,9 @@
|
|||||||
<Compile Include="..\Discord.Net\Audio\OpusEncoder.cs">
|
<Compile Include="..\Discord.Net\Audio\OpusEncoder.cs">
|
||||||
<Link>Audio\OpusEncoder.cs</Link>
|
<Link>Audio\OpusEncoder.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Discord.Net\Audio\Sodium.cs">
|
||||||
|
<Link>Audio\Sodium.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Discord.Net\Collections\AsyncCollection.cs">
|
<Compile Include="..\Discord.Net\Collections\AsyncCollection.cs">
|
||||||
<Link>Collections\AsyncCollection.cs</Link>
|
<Link>Collections\AsyncCollection.cs</Link>
|
||||||
</Compile>
|
</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
|
namespace Discord.Audio
|
||||||
{
|
{
|
||||||
internal unsafe class Opus
|
internal static unsafe class Opus
|
||||||
{
|
{
|
||||||
[DllImport("lib/opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("lib/opus", EntryPoint = "opus_encoder_create", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern IntPtr CreateEncoder(int Fs, int channels, int application, out Error error);
|
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
|
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); } }
|
public LogMessageSeverity LogLevel { get { return _logLevel; } set { SetValue(ref _logLevel, value); } }
|
||||||
private LogMessageSeverity _logLevel = LogMessageSeverity.Info;
|
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>
|
/// <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); } }
|
public bool EnableVoice { get { return _enableVoice; } set { SetValue(ref _enableVoice, value); } }
|
||||||
private bool _enableVoice = false;
|
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
|
#else
|
||||||
internal bool EnableVoice => false;
|
internal bool EnableVoice => false;
|
||||||
|
internal bool EnableVoiceEncryption => false;
|
||||||
#endif
|
#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>
|
/// <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); } }
|
public bool UseMessageQueue { get { return _useMessageQueue; } set { SetValue(ref _useMessageQueue, value); } }
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Discord.WebSockets.Voice
|
|||||||
private byte[] _secretKey;
|
private byte[] _secretKey;
|
||||||
private ushort _sequence;
|
private ushort _sequence;
|
||||||
private byte[] _encodingBuffer;
|
private byte[] _encodingBuffer;
|
||||||
private string _serverId, _userId, _sessionId, _token;
|
private string _serverId, _userId, _sessionId, _token, _encryptionMode;
|
||||||
|
|
||||||
#if USE_THREAD
|
#if USE_THREAD
|
||||||
private Thread _sendThread;
|
private Thread _sendThread;
|
||||||
@@ -213,12 +213,18 @@ namespace Discord.WebSockets.Voice
|
|||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
byte[] rtpPacket = new byte[_encodingBuffer.Length + 12];
|
byte[] rtpPacket = new byte[_encodingBuffer.Length + 12];
|
||||||
|
byte[] nonce = null;
|
||||||
rtpPacket[0] = 0x80; //Flags;
|
rtpPacket[0] = 0x80; //Flags;
|
||||||
rtpPacket[1] = 0x78; //Payload Type
|
rtpPacket[1] = 0x78; //Payload Type
|
||||||
rtpPacket[8] = (byte)((_ssrc >> 24) & 0xFF);
|
rtpPacket[8] = (byte)((_ssrc >> 24) & 0xFF);
|
||||||
rtpPacket[9] = (byte)((_ssrc >> 16) & 0xFF);
|
rtpPacket[9] = (byte)((_ssrc >> 16) & 0xFF);
|
||||||
rtpPacket[10] = (byte)((_ssrc >> 8) & 0xFF);
|
rtpPacket[10] = (byte)((_ssrc >> 8) & 0xFF);
|
||||||
rtpPacket[11] = (byte)((_ssrc >> 0) & 0xFF);
|
rtpPacket[11] = (byte)((_ssrc >> 0) & 0xFF);
|
||||||
|
if (_isEncrypted)
|
||||||
|
{
|
||||||
|
nonce = new byte[24];
|
||||||
|
Buffer.BlockCopy(rtpPacket, 0, nonce, 0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
while (!cancelToken.IsCancellationRequested)
|
while (!cancelToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -238,6 +244,13 @@ namespace Discord.WebSockets.Voice
|
|||||||
rtpPacket[5] = (byte)((timestamp >> 16) & 0xFF);
|
rtpPacket[5] = (byte)((timestamp >> 16) & 0xFF);
|
||||||
rtpPacket[6] = (byte)((timestamp >> 8) & 0xFF);
|
rtpPacket[6] = (byte)((timestamp >> 8) & 0xFF);
|
||||||
rtpPacket[7] = (byte)((timestamp >> 0) & 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);
|
Buffer.BlockCopy(packet, 0, rtpPacket, 12, packet.Length);
|
||||||
#if USE_THREAD
|
#if USE_THREAD
|
||||||
_udp.Send(rtpPacket, packet.Length + 12);
|
_udp.Send(rtpPacket, packet.Length + 12);
|
||||||
@@ -298,8 +311,22 @@ namespace Discord.WebSockets.Voice
|
|||||||
_heartbeatInterval = payload.HeartbeatInterval;
|
_heartbeatInterval = payload.HeartbeatInterval;
|
||||||
_ssrc = payload.SSRC;
|
_ssrc = payload.SSRC;
|
||||||
_endpoint = new IPEndPoint((await Dns.GetHostAddressesAsync(Host.Replace("wss://", "")).ConfigureAwait(false)).FirstOrDefault(), payload.Port);
|
_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);
|
_udp.Connect(_endpoint);
|
||||||
|
|
||||||
_sequence = (ushort)_rand.Next(0, ushort.MaxValue);
|
_sequence = (ushort)_rand.Next(0, ushort.MaxValue);
|
||||||
@@ -361,7 +388,7 @@ namespace Discord.WebSockets.Voice
|
|||||||
var login2 = new Login2Command();
|
var login2 = new Login2Command();
|
||||||
login2.Payload.Protocol = "udp";
|
login2.Payload.Protocol = "udp";
|
||||||
login2.Payload.SocketData.Address = ip;
|
login2.Payload.SocketData.Address = ip;
|
||||||
login2.Payload.SocketData.Mode = _isEncrypted ? EncryptedMode : UnencryptedMode;
|
login2.Payload.SocketData.Mode = _encryptionMode;
|
||||||
login2.Payload.SocketData.Port = port;
|
login2.Payload.SocketData.Port = port;
|
||||||
QueueMessage(login2);
|
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