using System; using System.Threading; using System.Threading.Tasks; namespace Discord.Audio.Streams { /// /// Decrypts an RTP frame using libsodium. /// public class SodiumDecryptStream : AudioOutStream { private readonly AudioClient _client; private readonly AudioStream _next; private readonly byte[] _nonce; public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => true; public SodiumDecryptStream(AudioStream next, IAudioClient client) { _next = next; _client = (AudioClient)client; _nonce = new byte[24]; } public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancelToken) { cancelToken.ThrowIfCancellationRequested(); if (_client.SecretKey == null) return; Buffer.BlockCopy(buffer, 0, _nonce, 0, 12); //Copy RTP header to nonce count = SecretBox.Decrypt(buffer, offset + 12, count - 12, buffer, offset + 12, _nonce, _client.SecretKey); await _next.WriteAsync(buffer, 0, count + 12, cancelToken).ConfigureAwait(false); } public override async Task FlushAsync(CancellationToken cancelToken) { await _next.FlushAsync(cancelToken).ConfigureAwait(false); } public override async Task ClearAsync(CancellationToken cancelToken) { await _next.ClearAsync(cancelToken).ConfigureAwait(false); } } }