Skip to content
This repository was archived by the owner on Oct 30, 2024. It is now read-only.

Attestation

amplitudes edited this page Apr 14, 2023 · 6 revisions

Attestation allows you to securely verify a user's device using cryptography.


public final class APITest extends JavaPlugin implements Listener {
    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    private List<UUID> expecting = new ArrayList<>();

    private HashMap<UUID, X509EncodedKeySpec> keys = new HashMap<>();

    private HashMap<UUID, byte[]> validationData = new HashMap<>();

    @EventHandler
    public void onPlayerChatMessage(PlayerCommandPreprocessEvent event) { // Simple example, so we're not going to make a proper command handler.
        Player player = event.getPlayer();
        String message = event.getMessage();

        if (message.equalsIgnoreCase("/register") || message.equalsIgnoreCase("/auth")) {
            event.setCancelled(true);
        } else {
            return;
        }

        ECServerAPI serverAPI = ECServerAPI.getInstance();

        if (event.getMessage().equalsIgnoreCase("/register")) {
            player.sendMessage(ChatColor.GREEN + "Registering your device...");
            expecting.add(player.getUniqueId());

            serverAPI.sendPacket(player, new OutAttestationRegister());
        } else if (event.getMessage().equalsIgnoreCase("/auth")) {
            if (!keys.containsKey(player.getUniqueId())) {
                player.sendMessage(ChatColor.RED + "You have not yet registered your device.");
                return;
            }

            player.sendMessage(ChatColor.GREEN + "Authenticating your device...");

            byte[] data = new byte[512];
            try {
                SecureRandom.getInstanceStrong().nextBytes(data);
            } catch (NoSuchAlgorithmException e) {
                player.sendMessage(ChatColor.RED + "Failed to generate random data.");
                return;
            }

            validationData.put(player.getUniqueId(), data);

            serverAPI.sendPacket(player, new OutAttestationSign(data));
        }
    }

    @EventHandler
    public void onEmberAttestationResult(EmberAttestationRegisterEvent event) {
        Player player = event.getPlayer();
        UUID playerUUID = player.getUniqueId();

        if (!expecting.contains(playerUUID)) {
            player.sendMessage(ChatColor.RED + "Failed to register public key: You have not requested a registration.");
            return;
        }

        expecting.remove(playerUUID);

        if (!event.getStatus().equals(AttestationRegisterResult.SUCCESS)) {
            player.sendMessage(ChatColor.RED + "Failed to register device: " + event.getStatus().name());
            return;
        }

        keys.put(playerUUID, event.getPublicKey());
        player.sendMessage(ChatColor.GREEN + "Successfully registered device.");
    }

    @EventHandler
    public void onEmberAttestationSign(EmberAttestationSignEvent event) {
        Player player = event.getPlayer();
        UUID playerUUID = player.getUniqueId();

        if (!validationData.containsKey(playerUUID)) {
            player.sendMessage(ChatColor.RED + "Failed to verify data: You have not requested verification.");
            return;
        }

        byte[] data = validationData.get(playerUUID);
        validationData.remove(playerUUID);

        if (!event.getStatus().equals(AttestationSignResult.SUCCESS)) {
            player.sendMessage(ChatColor.RED + "Failed to sign data: " + event.getStatus().name());
            return;
        }

        try {
            Signature sig = Signature.getInstance("SHA256withRSA");
            sig.initVerify(KeyFactory.getInstance("RSA").generatePublic(keys.get(event.getPlayer().getUniqueId())));

            sig.update(data);

            if (!sig.verify(event.getSignedData())) {
                event.getPlayer().sendMessage(ChatColor.RED + "Failed to verify attestation: Signature mismatch.");
                return;
            }

            event.getPlayer().sendMessage(ChatColor.GREEN + "Successfully verified attestation.");
        } catch (Exception e) {
            event.getPlayer().sendMessage(ChatColor.RED + "Failed to verify attestation: " + e.getMessage());
        }
    }
}
Clone this wiki locally