2024-07-08 22:45:57 +02:00
|
|
|
# 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
|
|
|
|
|
2024-07-09 10:28:57 +02:00
|
|
|
def decrypt(encrypted) do
|
|
|
|
GenServer.call(__MODULE__, {:decrypt, encrypted})
|
|
|
|
end
|
|
|
|
|
2024-07-08 22:45:57 +02:00
|
|
|
@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}
|
|
|
|
|
|
|
|
Logger.info("Generated RSA keys")
|
2024-07-09 10:28:57 +02:00
|
|
|
{:ok, {rsa_public_key, rsa_private_key}}
|
2024-07-08 22:45:57 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_call(:get_priv, _from, {pubkey, privkey}) do
|
2024-07-09 10:28:57 +02:00
|
|
|
{:reply, :public_key.der_encode(:RSAPrivateKey, privkey), {pubkey, privkey}}
|
2024-07-08 22:45:57 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_call(:get_pub, _from, {pubkey, privkey}) do
|
2024-07-09 10:28:57 +02:00
|
|
|
{:reply, :public_key.der_encode(:RSAPublicKey, pubkey), {pubkey, privkey}}
|
|
|
|
end
|
|
|
|
|
|
|
|
@impl true
|
|
|
|
def handle_call({:decrypt, encrypted}, _from, {pubkey, privkey}) do
|
|
|
|
plaintext = :public_key.decrypt_private(encrypted, privkey)
|
|
|
|
{:reply, plaintext, {pubkey, privkey}}
|
2024-07-08 22:45:57 +02:00
|
|
|
end
|
|
|
|
end
|