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)); }
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 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")); }
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")); }
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'")); }
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)}")); }
/// <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); }
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); }
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 }
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 }); } } } } }
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()); } }