Implement protocol encryption #2

Merged
kodi merged 6 commits from encryption into main 2024-10-05 12:07:04 +02:00
2 changed files with 42 additions and 22 deletions
Showing only changes of commit 7f3bb357db - Show all commits

View File

@ -107,7 +107,11 @@ defmodule Amethyst.ConnectionHandler do
send_packet(socket, connstate, packet, version, state)
loop(socket, connstate, version, state)
after 0 ->
# Received stuff from the connection receiver is lower priority
receive do
{:get_encryption, from} ->
send(from, Map.get(state, :decryption_state))
loop(socket, connstate, version, state)
{:packet, id, data} ->
state = handle_packet(id, data, connstate, version, state)
loop(socket, connstate, version, state)
@ -216,13 +220,7 @@ defmodule Amethyst.ConnectionHandler do
defp handle_packet(id, data, connstate, version, state) do
try do
packet = case Map.get(state, :decryption_state) do
nil ->
connstate.deserialize(id, version, data)
dstate ->
data = :crypto.crypto_update(dstate, data)
connstate.deserialize(id, version, data)
end
packet = connstate.deserialize(id, version, data)
case connstate.handle(packet, version, state) do
:ok -> state
{:error, reason} ->

View File

@ -35,7 +35,7 @@ defmodule Amethyst.ConnectionReceiver do
{:ok, spawn(fn ->
Process.set_label("ConnectionReceiver for #{inspect(socket)}")
{:ok, pid} = Amethyst.ConnectionHandler.start_link(socket, Amethyst.ConnectionState.Handshake, 0)
receive(socket, pid)
receive(socket, pid, nil)
end)}
end
@ -44,42 +44,64 @@ defmodule Amethyst.ConnectionReceiver do
{:ok, spawn_link(fn ->
Process.set_label("ConnectionReceiver for #{inspect(socket)}")
{:ok, pid} = Amethyst.ConnectionHandler.start_link(socket, Amethyst.ConnectionState.Handshake, 0)
receive(socket, pid)
receive(socket, pid, nil)
end)}
end
@spec receive(:gen_tcp.socket(), pid()) :: no_return()
def receive(socket, sender) do
case get_packet(socket) do
@spec receive(:gen_tcp.socket(), pid(), nil | :crypto.crypto_state()) :: no_return()
def receive(socket, sender, cstate) do
case get_packet(socket, cstate) do
:closed -> send(sender, :closed)
Process.exit(self(), :normal)
{:error, error} -> Logger.error("Error reading packet: #{error}")
{id, data} -> send(sender, {:packet, id, data})
end
receive(socket, sender)
if cstate == nil do
# Ask the handler if the encryption state has changed
send(sender, {:get_encryption, self()})
Logger.debug("Asking for news on encryption...")
receive do
nil -> receive(socket, sender, cstate)
some ->
Logger.debug("Enabling decryption!")
receive(socket, sender, some)
end
else
receive(socket, sender, cstate)
end
end
def get_packet(client) do
case get_varint(client, "") do
def get_packet(client, cstate) do
case get_varint(client, "", cstate) do
:closed -> :closed
{:error, error} -> {:error, error}
{[length], ""} ->
recv = :gen_tcp.recv(client, length)
case recv do
{:ok, full_packet} -> ({[id], data} = Read.start(full_packet) |> Read.varint() |> Read.stop()
{id, data})
{:ok, full_packet} ->
full_packet = case cstate do
nil -> full_packet
ds -> :crypto.crypto_update(ds, full_packet)
end
({[id], data} = Read.start(full_packet) |> Read.varint() |> Read.stop()
{id, data})
{:error, :closed} -> :closed
{:error, error} -> {:error, error}
end
end
end
defp get_varint(client, acc) do
defp get_varint(client, acc, cstate) do
case :gen_tcp.recv(client, 1) do
{:ok, byte} -> case byte do
<<0::1, _::7>> -> Read.start(acc <> byte) |> Read.varint() |> Read.stop()
<<1::1, _::7>> -> get_varint(client, acc <> byte)
end
{:ok, byte} ->
byte = case cstate do
nil -> byte
ds -> :crypto.crypto_update(ds, byte)
end
case byte do
<<0::1, _::7>> -> Read.start(acc <> byte) |> Read.varint() |> Read.stop()
<<1::1, _::7>> -> get_varint(client, acc <> byte, cstate)
end
{:error, :closed} -> :closed
{:error, error} -> {:error, error}
end