Progress on implementing encryption (I think)
All checks were successful
Build & Test / nix-build (push) Successful in 1m6s

This commit is contained in:
Kodi Craft 2024-07-08 22:45:57 +02:00
parent 1d741d785a
commit 0f59aaef59
Signed by: kodi
GPG Key ID: 69D9EED60B242822
5 changed files with 79 additions and 4 deletions

View File

@ -2,4 +2,5 @@ import Config
config :amethyst, config :amethyst,
port: 25599, # Bogus port for testing, avoids unexpected conflicts port: 25599, # Bogus port for testing, avoids unexpected conflicts
encryption: false encryption: true, # Whether or not to enable encryption, this should almost always be 'true' for security reasons
auth: true # Whether or not users should be authenticated.

View File

@ -26,6 +26,7 @@ defmodule Amethyst.Application do
children = [ children = [
Supervisor.child_spec({Task, fn -> Amethyst.TCPListener.accept(Application.fetch_env!(:amethyst, :port)) end}, restart: :permanent), Supervisor.child_spec({Task, fn -> Amethyst.TCPListener.accept(Application.fetch_env!(:amethyst, :port)) end}, restart: :permanent),
{Task.Supervisor, name: Amethyst.ConnectionSupervisor}, {Task.Supervisor, name: Amethyst.ConnectionSupervisor},
{Amethyst.Keys, 1024},
] ]
# See https://hexdocs.pm/elixir/Supervisor.html # See https://hexdocs.pm/elixir/Supervisor.html

65
lib/encryption.ex Normal file
View File

@ -0,0 +1,65 @@
# Amethyst - An experimental Minecraft server written in Elixir.
# Copyright (C) 2024 KodiCraft
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
defmodule Amethyst.Keys do
@moduledoc """
This module generates and manages the keys used for encryption.
Minecraft uses RSA encryption, keys are stored in ASN.1 format and should be
generated at runtime. The vanilla server uses 1024-bit keys, but we can use
a larger key size for added security.
"""
use GenServer
require Logger
def start_link(bits) do
GenServer.start_link(__MODULE__, bits, name: __MODULE__)
end
def get_priv do
GenServer.call(__MODULE__, :get_priv)
end
def get_pub do
GenServer.call(__MODULE__, :get_pub)
end
@impl true
def init(bits) do
Logger.info("Generating RSA keys with #{bits} bits")
# https://elixirforum.com/t/how-to-generate-rsa-public-key-using-crypto-provided-exponent-and-modulus/38487
{:RSAPrivateKey, _, modulus, public_exponent, _, _, _, _exponent1, _, _, _other_prime_infos} =
rsa_private_key = :public_key.generate_key({:rsa, bits, 65_537})
rsa_public_key = {:RSAPublicKey, modulus, public_exponent}
privkey = :public_key.der_encode(:RSAPrivateKey, rsa_private_key)
pubkey = :public_key.der_encode(:RSAPublicKey, rsa_public_key)
Logger.info("Generated RSA keys")
{:ok, {pubkey, privkey}}
end
@impl true
def handle_call(:get_priv, _from, {pubkey, privkey}) do
{:reply, privkey, {pubkey, privkey}}
end
@impl true
def handle_call(:get_pub, _from, {pubkey, privkey}) do
{:reply, pubkey, {pubkey, privkey}}
end
end

View File

@ -71,8 +71,12 @@ defmodule Amethyst.Server.Login do
Write.varint(0x00) <> Write.string(reason) Write.varint(0x00) <> Write.string(reason)
end end
# Encryption Request https://wiki.vg/Protocol#Encryption_Request # Encryption Request https://wiki.vg/Protocol#Encryption_Request
def serialize({:encryption_request, id, pubkey, verify_token, auth}) do def serialize({:encryption_request, server_id, pubkey, verify_token, auth}) do
Write.varint(0x01) <> Write.string(id) <> Write.varint(byte_size(pubkey)) <> pubkey <> Write.varint(byte_size(verify_token)) <> verify_token <> Write.bool(auth) Write.varint(0x01) <>
Write.string(server_id) <>
Write.varint(byte_size(pubkey)) <> pubkey <>
Write.varint(byte_size(verify_token)) <> verify_token <>
Write.bool(auth)
end end
# Login Success https://wiki.vg/Protocol#Login_Success # Login Success https://wiki.vg/Protocol#Login_Success
def serialize({:login_success, uuid, username, props, strict}) do def serialize({:login_success, uuid, username, props, strict}) do
@ -103,7 +107,10 @@ defmodule Amethyst.Server.Login do
def handle({:login_start, name, uuid}, client) do def handle({:login_start, name, uuid}, client) do
Logger.info("Logging in #{name} (#{uuid})") Logger.info("Logging in #{name} (#{uuid})")
if Application.fetch_env!(:amethyst, :encryption) do if Application.fetch_env!(:amethyst, :encryption) do
raise RuntimeError, "Encryption is not currently supported!" verify_token = :crypto.strong_rand_bytes(4)
pubkey = Amethyst.Keys.get_pub()
auth = Application.fetch_env!(:amethyst, :auth)
transmit({:encryption_request, "amethyst", pubkey, verify_token, auth}, client)
else else
transmit({:login_success, uuid, name, [], false}, client) transmit({:login_success, uuid, name, [], false}, client)
end end

View File

@ -12,6 +12,7 @@ defmodule WriteTest do
assert Amethyst.Minecraft.Write.varint(127) == <<0x7F>> assert Amethyst.Minecraft.Write.varint(127) == <<0x7F>>
assert Amethyst.Minecraft.Write.varint(128) == <<0x80, 0x01>> assert Amethyst.Minecraft.Write.varint(128) == <<0x80, 0x01>>
assert Amethyst.Minecraft.Write.varint(255) == <<0xFF, 0x01>> assert Amethyst.Minecraft.Write.varint(255) == <<0xFF, 0x01>>
assert Amethyst.Minecraft.Write.varint(25_565) == <<0xDD, 0xC7, 0x01>>
assert Amethyst.Minecraft.Write.varint(2_147_483_647) == <<0xFF, 0xFF, 0xFF, 0xFF, 0x07>> assert Amethyst.Minecraft.Write.varint(2_147_483_647) == <<0xFF, 0xFF, 0xFF, 0xFF, 0x07>>
assert Amethyst.Minecraft.Write.varint(-1) == <<0xFF, 0xFF, 0xFF, 0xFF, 0x0F>> assert Amethyst.Minecraft.Write.varint(-1) == <<0xFF, 0xFF, 0xFF, 0xFF, 0x0F>>
assert Amethyst.Minecraft.Write.varint(-2_147_483_648) == <<0x80, 0x80, 0x80, 0x80, 0x08>> assert Amethyst.Minecraft.Write.varint(-2_147_483_648) == <<0x80, 0x80, 0x80, 0x80, 0x08>>