Пример #1
0
        public void VerifyDecryptFailsWithInvalidParameters()
        {
            // Encrypt a message
            var sb  = new SecretBox();
            var key = new byte[KeyBytes];

            sb.GenerateKey(key);
            var          message    = Encoding.UTF8.GetBytes("You are old Father William, the young man said");
            const int    messageId  = 1;
            const string context    = "test";
            var          ciphertext = new byte[sb.CalculateCiphertextLength(message.Length)];

            sb.Encrypt(ciphertext, message, message.Length, key, context, messageId);

            // Buffer to hold decrypted message
            var decryptedMessage = new byte[message.Length];

            // CiphertextLength is incorrect
            Assert.That(
                () => sb.Decrypt(decryptedMessage, ciphertext, HeaderBytes, key, context, messageId),
                Throws.TypeOf <CryptographicException>().With.Message.EqualTo("MAC check failed"));
            Assert.That(
                sb.TryDecrypt(decryptedMessage, ciphertext, HeaderBytes, key, context, messageId),
                Is.False);

            // MessageId is incorrect
            Assert.That(
                () => sb.Decrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, 2),
                Throws.TypeOf <CryptographicException>().With.Message.EqualTo("MAC check failed"));

            // Verify the decrypted message is not equal to the message, as a failed MAC check should not
            // leak the plaintext
            Assert.That(decryptedMessage, Is.Not.EqualTo(message));

            Assert.That(
                sb.TryDecrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, 2),
                Is.False);
            Assert.That(decryptedMessage, Is.Not.EqualTo(message));

            // Key is invalid
            key[0]++;
            Assert.That(
                () => sb.Decrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId),
                Throws.TypeOf <CryptographicException>().With.Message.EqualTo("MAC check failed"));
            Assert.That(
                sb.TryDecrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId),
                Is.False);
            key[0]--;

            // Ciphertext is invalid
            ciphertext[12]++;
            Assert.That(
                () => sb.Decrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId),
                Throws.TypeOf <CryptographicException>().With.Message.EqualTo("MAC check failed"));
            Assert.That(
                sb.TryDecrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId),
                Is.False);
        }
        public void VerifyLibhydrogenEncryptedMessageCanBeDecrypted()
        {
            var sb = new SecretBox();

            // Generate a key
            var key = new byte[SecretBox.KeyBytes];

            sb.GenerateKey(key);

            // Generate a message to encrypt
            var          message   = Encoding.UTF8.GetBytes("You are old Father William, the young man said");
            const int    messageId = 1;
            const string context   = "test";

            // Buffer to hold the ciphertext
            var ciphertext = new byte[sb.CalculateCiphertextLength(message.Length)];

            // Encrypt using libhydrogen
            var result = hydro_secretbox_encrypt(
                ciphertext, message, message.Length, messageId, context, key);

            // Verify that some ciphertext was generated
            Assert.That(ciphertext, Is.Not.All.Zero);
            Assert.That(result, Is.EqualTo(0));

            // Decrypt using SecretBox
            var decryptedMessage = new byte[message.Length];

            sb.Decrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId);

            // Verify the decrypt was successful
            Assert.That(decryptedMessage, Is.EqualTo(message));
        }
Пример #3
0
        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);
        }
Пример #4
0
        public void Decrypt_ValidateKeyLength(int keyLength)
        {
            var       sb   = new SecretBox();
            var       key  = new byte[keyLength];
            const int clen = 100;
            var       c    = new byte[clen];
            var       m    = new byte[sb.CalculateMessageLength(clen)];
            var       ctx  = "test";

            Assert.That(
                () => sb.Decrypt(m, c, clen, key, ctx),
                Throws.ArgumentException.With.Message.EqualTo(
                    $"'key' length must be {KeyBytes} bytes"));
        }
Пример #5
0
        public void Decrypt_ValidateContextLength_TooLong()
        {
            var       sb   = new SecretBox();
            var       key  = new byte[KeyBytes];
            const int clen = 100;
            var       c    = new byte[clen];
            var       m    = new byte[sb.CalculateMessageLength(clen)];
            var       ctx  = "you are old father william";

            Assert.That(
                () => sb.Decrypt(m, c, clen, key, ctx),
                Throws.ArgumentException.With.Message.EqualTo(
                    $"'context' must be at most {ContextBytes} characters"));
        }
Пример #6
0
        public void Decrypt_ValidateCiphertextLength_TooLong()
        {
            var       sb         = new SecretBox();
            var       key        = new byte[KeyBytes];
            const int clen       = 200;
            const int clenActual = 100;
            var       c          = new byte[clenActual];
            var       m          = new byte[sb.CalculateMessageLength(clenActual)];
            var       ctx        = "test";

            Assert.That(
                () => sb.Decrypt(m, c, clen, key, ctx),
                Throws.ArgumentException.With.Message.EqualTo(
                    $"'ciphertextLength' must be at most the length of 'ciphertext'"));
        }
Пример #7
0
        public void Decrypt_ValidateMessageLength_TooShort()
        {
            var       key  = new byte[KeyBytes];
            const int clen = 100;
            var       c    = new byte[clen];
            var       m    = new byte[10];
            var       ctx  = "test";

            var sb = new SecretBox();

            Assert.That(
                () => sb.Decrypt(m, c, clen, key, ctx),
                Throws.ArgumentException.With.Message.EqualTo(
                    $"'message' length must be at least ciphertextLength - {nameof(HeaderBytes)}"));
        }
Пример #8
0
        /// <exception cref="InvalidOperationException">Received payload without an RTP header.</exception>
        /// <exception cref="OperationCanceledException">The token has had cancellation requested.</exception>
        /// <exception cref="ObjectDisposedException">The associated <see cref="T:System.Threading.CancellationTokenSource" /> has been disposed.</exception>
        public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancelToken)
        {
            cancelToken.ThrowIfCancellationRequested();
            if (count < 12)
            {
                throw new InvalidOperationException("Received payload without an RTP header.");
            }

            if (_client.SecretKey == null)
            {
                return;
            }

            Buffer.BlockCopy(buffer, offset, _nonce, 0, 12); //Copy RTP header to nonce
            Buffer.BlockCopy(buffer, offset, _buffer, 0, 12);
            count = SecretBox.Decrypt(buffer, offset + 12, count - 12, _buffer, 12, _nonce, _client.SecretKey);
            await _next.WriteAsync(_buffer, 0, count + 12, cancelToken).ConfigureAwait(false);
        }
Пример #9
0
        public void VerifyMessageCanBeEncryptedAndDecrypted()
        {
            var sb = new SecretBox();

            // Generate a key
            var key = new byte[KeyBytes];

            sb.GenerateKey(key);

            // Generate a message to encrypt
            var          message   = Encoding.UTF8.GetBytes("You are old Father William, the young man said");
            const int    messageId = 1;
            const string context   = "test";

            // Buffer to hold the ciphertext
            var ciphertext = new byte[sb.CalculateCiphertextLength(message.Length)];

            // Encrypt
            sb.Encrypt(ciphertext, message, message.Length, key, context, messageId);

            // Buffer to hold decrypted message
            var decryptedMessage = new byte[message.Length];

            // Decrypt
            sb.Decrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId);

            // Verify the decrypted message
            Assert.That(decryptedMessage, Is.EqualTo(message));

            // Decrypt using TryDecrypt
            Array.Clear(decryptedMessage, 0, decryptedMessage.Length);
            var result = sb.TryDecrypt(decryptedMessage, ciphertext, ciphertext.Length, key, context, messageId);

            // Verify the decrypted message
            Assert.That(decryptedMessage, Is.EqualTo(message));
            Assert.That(result, Is.True);
        }
Пример #10
0
        private async Task ReceiveVoiceAsync(CancellationToken cancelToken)
        {
            var closeTask = cancelToken.Wait();

            try
            {
                byte[]     packet, decodingBuffer = null, nonce = null, result;
                int        packetLength, resultOffset, resultLength;
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);

                if ((_audioConfig.Mode & AudioMode.Incoming) != 0)
                {
                    decodingBuffer = new byte[MaxOpusSize];
                    nonce          = new byte[24];
                }

                while (!cancelToken.IsCancellationRequested)
                {
                    await Task.Delay(1).ConfigureAwait(false);

                    if (_udp.Available > 0)
                    {
#if !NETSTANDARD1_3
                        packet = _udp.Receive(ref endpoint);
#else
                        //TODO: Is this really the only way to end a Receive call in DOTNET5_4?
                        var receiveTask = _udp.ReceiveAsync();
                        var task        = Task.WhenAny(closeTask, receiveTask).Result;
                        if (task == closeTask)
                        {
                            break;
                        }
                        var udpPacket = receiveTask.Result;
                        packet   = udpPacket.Buffer;
                        endpoint = udpPacket.RemoteEndPoint;
#endif
                        packetLength = packet.Length;

                        if (packetLength > 0 && endpoint.Equals(_endpoint))
                        {
                            if (State != ConnectionState.Connected)
                            {
                                if (packetLength != 70)
                                {
                                    return;
                                }

                                string ip   = Encoding.UTF8.GetString(packet, 4, 70 - 6).TrimEnd('\0');
                                int    port = packet[68] | packet[69] << 8;

                                SendSelectProtocol(ip, port);
                                if ((_audioConfig.Mode & AudioMode.Incoming) == 0)
                                {
                                    return; //We dont need this thread anymore
                                }
                            }
                            else
                            {
                                //Parse RTP Data
                                if (packetLength < 12)
                                {
                                    return;
                                }
                                if (packet[0] != 0x80)
                                {
                                    return;                    //Flags
                                }
                                if (packet[1] != 0x78)
                                {
                                    return;                    //Payload Type
                                }
                                ushort sequenceNumber = (ushort)((packet[2] << 8) |
                                                                 packet[3] << 0);
                                uint timestamp = (uint)((packet[4] << 24) |
                                                        (packet[5] << 16) |
                                                        (packet[6] << 8) |
                                                        (packet[7] << 0));
                                uint ssrc = (uint)((packet[8] << 24) |
                                                   (packet[9] << 16) |
                                                   (packet[10] << 8) |
                                                   (packet[11] << 0));

                                //Decrypt
                                if (_isEncrypted)
                                {
                                    if (packetLength < 28) //12 + 16 (RTP + Poly1305 MAC)
                                    {
                                        return;
                                    }

                                    Buffer.BlockCopy(packet, 0, nonce, 0, 12);
                                    int ret = SecretBox.Decrypt(packet, 12, packetLength - 12, decodingBuffer, nonce, _secretKey);
                                    if (ret != 0)
                                    {
                                        continue;
                                    }
                                    result       = decodingBuffer;
                                    resultOffset = 0;
                                    resultLength = packetLength - 28;
                                }
                                else //Plain
                                {
                                    result       = packet;
                                    resultOffset = 12;
                                    resultLength = packetLength - 12;
                                }

                                /*if (_logLevel >= LogMessageSeverity.Debug)
                                 *                                      RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/

                                ulong userId;
                                if (_ssrcMapping.TryGetValue(ssrc, out userId))
                                {
                                    OnFrameReceived(userId, Channel.Id, result, resultOffset, resultLength);
                                }
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (InvalidOperationException) { } //Includes ObjectDisposedException
        }
Пример #11
0
        private async Task DoReceiveVoice()
        {
            _udp.DontFragment = false;
            if (_udp.Available > 0)
            {
                //the packet received, the 4000 size buffer for decoding, the nonce header for encryption and the decrypted/decoded result :)
                byte[] packet, decodingBuffer = null, nonce = null, result;

                //UdpReceiveResult receivedResult = await _udp.ReceiveAsync().ConfigureAwait(false);
                packet = _udp.Receive(ref udpEndpoint);
                int packetLength, resultOffset, resultLength;
                decodingBuffer = new byte[4000];
                nonce          = new byte[24];
                packetLength   = packet.Length;

                if (packet.Length > 0)
                {
                    if (packetLength < 12)
                    {
                        return;                    //irrelevant packet
                    }
                    if (packet[0] != 0x80)
                    {
                        return;                    //flags
                    }
                    if (packet[1] != 0x78)
                    {
                        return;                    //payload type. you know, from before.
                    }
                    ushort sequenceNumber = (ushort)((packet[2] << 8) | packet[3] << 0);
                    uint   timDocuestamp  = (uint)((packet[4] << 24) | packet[5] << 16 | packet[6] << 8 | packet[7] << 0);
                    uint   ssrc           = (uint)((packet[8] << 24) | (packet[9] << 16) | (packet[10] << 8) | (packet[11] << 0));

                    //encryption is enabled by default
                    if (packetLength < 28)
                    {
                        return;                                //irrelevant packet
                    }
                    Buffer.BlockCopy(packet, 0, nonce, 0, 12); //copy nonce
                    var length      = Convert.ToUInt64(packetLength - 12);
                    int returnValue = SecretBox.Decrypt(packet, 12, length, decodingBuffer, nonce, __secretKey);
                    if (returnValue != 0)
                    {
                        return;
                    }
                    result       = decodingBuffer;
                    resultOffset = 0; resultLength = packetLength - 28;

                    if (SsrcDictionary.ContainsValue((int)ssrc))
                    {
                        if (PacketReceived != null)
                        {
                            PacketReceived(this, new DiscordAudioPacketEventArgs
                            {
                                Channel         = this.Channel,
                                FromUser        = GetUserBySsrc(ssrc),
                                OpusAudio       = result,
                                OpusAudioLength = resultLength
                            });
                        }
                    }
                }
            }
        }
Пример #12
0
        private async Task ReceiveVoiceAsync(CancellationToken cancelToken)
        {
            Logger.Verbose("Starting to receive...");
            var closeTask = cancelToken.Wait();

            byte[]     packet, decodingBuffer = null, nonce = null, result;
            int        packetLength, resultOffset, resultLength;
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);

            if ((_audioConfig.Mode & AudioMode.Incoming) != 0)
            {
                decodingBuffer = new byte[MaxOpusSize];
                nonce          = new byte[24];
            }

            try
            {
                while (!cancelToken.IsCancellationRequested)
                {
                    await Task.Delay(1).ConfigureAwait(false);

                    if (_udp.Available > 0)
                    {
                        Logger.Verbose("Received some data...");
#if !NETSTANDARD1_3
                        packet = _udp.Receive(ref endpoint);
#else
                        //TODO: Is this really the only way to end a Receive call in DOTNET5_4?
                        var receiveTask = _udp.ReceiveAsync();
                        var task        = Task.WhenAny(closeTask, receiveTask).Result;
                        if (task == closeTask)
                        {
                            break;
                        }
                        var udpPacket = receiveTask.Result;
                        packet   = udpPacket.Buffer;
                        endpoint = udpPacket.RemoteEndPoint;
#endif
                        packetLength = packet.Length;

                        if (packetLength > 0 && endpoint.Equals(_endpoint))
                        {
                            Logger.Verbose("Received " + packetLength + " while " + State);
                            if (State != ConnectionState.Connected)
                            {
                                if (packetLength != 70)
                                {
                                    Logger.Warning("Packet length not 70!");
                                    continue;
                                }
                                string ip   = Encoding.UTF8.GetString(packet, 4, 70 - 6).TrimEnd('\0');
                                int    port = packet[68] | packet[69] << 8;

                                SendSelectProtocol(ip, port);
                                if ((_audioConfig.Mode & AudioMode.Incoming) == 0)
                                {
                                    Logger.Warning("Audio not configured for incoming mode!");
                                    return;
                                }
                            }
                            else
                            {
                                //Parse RTP Data
                                if (packetLength < 12)
                                {
                                    Logger.Warning("Invalid short packet length : " + packetLength);
                                    continue;
                                }
                                if (packet[0] != 0x80)
                                {
                                    Logger.Warning("Invalid packet, not flags: " + packet[0]);
                                    continue;
                                }
                                if (packet[1] != 0x78)
                                {
                                    Logger.Warning("Invalid packet, not payload: " + packet[1]);
                                    continue;
                                }

                                ushort sequenceNumber = (ushort)((packet[2] << 8) |
                                                                 packet[3] << 0);
                                uint timestamp = (uint)((packet[4] << 24) |
                                                        (packet[5] << 16) |
                                                        (packet[6] << 8) |
                                                        (packet[7] << 0));
                                uint ssrc = (uint)((packet[8] << 24) |
                                                   (packet[9] << 16) |
                                                   (packet[10] << 8) |
                                                   (packet[11] << 0));

                                //Decrypt
                                if (_isEncrypted)
                                {
                                    if (packetLength < 28) //12 + 16 (RTP + Poly1305 MAC)
                                    {
                                        Logger.Warning("Invalid packet length : " + packetLength);
                                        continue;
                                    }

                                    Buffer.BlockCopy(packet, 0, nonce, 0, 12);
                                    int ret = SecretBox.Decrypt(packet, 12, packetLength - 12, decodingBuffer, nonce, _secretKey);
                                    if (ret != 0)
                                    {
                                        Logger.Warning("Invalid packet, failed to decrypt: " + ret);
                                        continue;
                                    }
                                    result       = decodingBuffer;
                                    resultOffset = 0;
                                    resultLength = packetLength - 28;
                                }
                                else //Plain
                                {
                                    result       = packet;
                                    resultOffset = 12;
                                    resultLength = packetLength - 12;
                                }

                                /*if (_logLevel >= LogMessageSeverity.Debug)
                                 *  RaiseOnLog(LogMessageSeverity.Debug, $"Received {buffer.Length - 12} bytes.");*/

                                ulong userId;
                                if (_ssrcMapping.TryGetValue(ssrc, out userId))
                                {
                                    OnFrameReceived(userId, Channel.Id, result, resultOffset, resultLength, sequenceNumber);
                                }
                                else
                                {
                                    OnFrameReceived(ssrc, Channel.Id, result, resultOffset, resultLength, sequenceNumber);
                                }
                            }
                        }
                    }
                }
                Logger.Warning("Voice socket IMMEDIATE STOP");
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                Console.WriteLine(ex.ToString());
            }
        }