add pubkey auth

This commit is contained in:
Sen 2025-05-29 03:04:44 +02:00
parent bdf67a89f7
commit 5a394749bf
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
24 changed files with 822 additions and 107 deletions

View file

@ -333,6 +333,16 @@ public abstract class Config {
public static boolean register = true;
@Var(name = "signEditing")
public static boolean editSigns = true;
@Var(name = "passwordAuthentication")
public static boolean passwordAuth = true;
@Var(name = "pubkeyAuthentication")
public static boolean pubkeyAuth = true;
@Var(name = "requireAccessPassword")
public static boolean accessRequired = true;
@Var(name = "encryption")
public static boolean encrypt = true;
@Var(name = "requireAuthentication")
public static boolean authenticate = true;
@Var(name = "keepInventory")
public static boolean keepInventory = false;

View file

@ -1,13 +1,19 @@
package common.network;
import common.packet.RPacketChallenge;
import common.packet.RPacketDisconnect;
import common.packet.RPacketEnableCompression;
import common.packet.RPacketLoginSuccess;
import common.packet.RPacketRequestEncrypt;
import common.packet.RPacketResponse;
import common.packet.RPacketServerConfig;
public interface IClientLoginHandler {
void handleDisconnect(RPacketDisconnect packet);
void handleLoginSuccess(RPacketLoginSuccess packet);
void handleEnableCompression(RPacketEnableCompression packet);
void handleEncrypt(RPacketRequestEncrypt packet);
void handleConfig(RPacketServerConfig packet);
void handleResponse(RPacketResponse packet);
void handleChallenge(RPacketChallenge packet);
}

View file

@ -1,9 +1,15 @@
package common.network;
import common.packet.LPacketPasswordResponse;
import common.packet.LPacketChallenge;
import common.packet.LPacketPassword;
import common.packet.LPacketPubkey;
import common.packet.LPacketResponse;
import common.packet.LPacketStartEncrypt;
public interface ILoginHandler {
void processPasswordResponse(LPacketPasswordResponse packet);
void processEncryption(LPacketStartEncrypt packet);
void processPassword(LPacketPassword packet);
void processPubkey(LPacketPubkey packet);
void processResponse(LPacketResponse packet);
void processChallenge(LPacketChallenge packet);
}

View file

@ -22,12 +22,18 @@ import common.packet.CPacketPlayer;
import common.packet.CPacketSign;
import common.packet.CPacketSkin;
import common.packet.HPacketHandshake;
import common.packet.LPacketPasswordResponse;
import common.packet.LPacketChallenge;
import common.packet.LPacketPassword;
import common.packet.LPacketPubkey;
import common.packet.LPacketResponse;
import common.packet.LPacketStartEncrypt;
import common.packet.RPacketChallenge;
import common.packet.RPacketDisconnect;
import common.packet.RPacketEnableCompression;
import common.packet.RPacketLoginSuccess;
import common.packet.RPacketRequestEncrypt;
import common.packet.RPacketResponse;
import common.packet.RPacketServerConfig;
import common.packet.SPacketEntityRelMove;
import common.packet.SPacketEntityLook;
import common.packet.SPacketEntityLookMove;
@ -101,11 +107,17 @@ public enum PacketRegistry {
LOGIN {{
this.server(RPacketDisconnect.class);
this.server(RPacketRequestEncrypt.class);
this.server(RPacketResponse.class);
this.server(RPacketChallenge.class);
this.server(RPacketServerConfig.class);
this.server(RPacketLoginSuccess.class);
this.server(RPacketEnableCompression.class);
this.client(LPacketStartEncrypt.class);
this.client(LPacketPasswordResponse.class);
this.client(LPacketPassword.class);
this.client(LPacketChallenge.class);
this.client(LPacketPubkey.class);
this.client(LPacketResponse.class);
}},
PLAY {{
this.server(SPacketKeepAlive.class);

View file

@ -0,0 +1,37 @@
package common.packet;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import common.network.ILoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
import common.util.EncryptUtil;
public class LPacketChallenge implements Packet<ILoginHandler> {
private byte[] token;
public LPacketChallenge() {
}
public LPacketChallenge(PublicKey pubkey, byte[] token) {
this.token = EncryptUtil.encryptData(pubkey, token);
}
public final void readPacketData(PacketBuffer buf) throws IOException {
this.token = buf.readByteArray();
}
public final void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.token);
}
public void processPacket(ILoginHandler handler) {
handler.processChallenge(this);
}
public byte[] getToken(PrivateKey key) {
return EncryptUtil.decryptData(key, this.token);
}
}

View file

@ -7,20 +7,20 @@ import common.network.IPlayer;
import common.network.Packet;
import common.network.PacketBuffer;
public class LPacketPasswordResponse implements Packet<ILoginHandler>
public class LPacketPassword implements Packet<ILoginHandler>
{
private String user;
private String access;
private String password;
public LPacketPasswordResponse()
public LPacketPassword()
{
}
public LPacketPasswordResponse(String userIn, String accessIn, String passwordIn)
public LPacketPassword(String user, String access, String passwordIn)
{
this.user = userIn;
this.access = accessIn;
this.user = user;
this.access = access;
this.password = passwordIn;
}
@ -49,7 +49,7 @@ public class LPacketPasswordResponse implements Packet<ILoginHandler>
*/
public void processPacket(ILoginHandler handler)
{
handler.processPasswordResponse(this);
handler.processPassword(this);
}
public String getUser()

View file

@ -0,0 +1,53 @@
package common.packet;
import java.io.IOException;
import java.security.PublicKey;
import common.network.ILoginHandler;
import common.network.IPlayer;
import common.network.Packet;
import common.network.PacketBuffer;
import common.util.EncryptUtil;
public class LPacketPubkey implements Packet<ILoginHandler> {
private String user;
private String access;
private PublicKey key;
public LPacketPubkey() {
}
public LPacketPubkey(String user, String access, PublicKey key) {
this.user = user;
this.access = access;
this.key = key;
}
public final void readPacketData(PacketBuffer buf) throws IOException {
this.user = buf.readString(IPlayer.MAX_USER_LENGTH);
this.access = buf.readString(IPlayer.MAX_PASS_LENGTH);
this.key = EncryptUtil.decodePublicKey(buf.readByteArray());
}
public final void writePacketData(PacketBuffer buf) throws IOException {
buf.writeString(this.user);
buf.writeString(this.access);
buf.writeByteArray(this.key.getEncoded());
}
public void processPacket(ILoginHandler handler) {
handler.processPubkey(this);
}
public String getUser() {
return this.user;
}
public String getAccess() {
return this.access;
}
public PublicKey getKey() {
return this.key;
}
}

View file

@ -0,0 +1,33 @@
package common.packet;
import java.io.IOException;
import common.network.ILoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
public class LPacketResponse implements Packet<ILoginHandler> {
private byte[] token = new byte[0];
public LPacketResponse() {
}
public LPacketResponse(byte[] token) {
this.token = token;
}
public void readPacketData(PacketBuffer buf) throws IOException {
this.token = buf.readByteArray();
}
public void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.token);
}
public void processPacket(ILoginHandler handler) {
handler.processResponse(this);
}
public byte[] getToken() {
return this.token;
}
}

View file

@ -42,6 +42,6 @@ public class LPacketStartEncrypt implements Packet<ILoginHandler> {
}
public byte[] getToken(PrivateKey key) {
return key == null ? this.token : EncryptUtil.decryptData(key, this.token);
return EncryptUtil.decryptData(key, this.token);
}
}

View file

@ -0,0 +1,37 @@
package common.packet;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import common.network.IClientLoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
import common.util.EncryptUtil;
public class RPacketChallenge implements Packet<IClientLoginHandler> {
private byte[] token;
public RPacketChallenge() {
}
public RPacketChallenge(PublicKey pubkey, byte[] token) {
this.token = EncryptUtil.encryptData(pubkey, token);
}
public final void readPacketData(PacketBuffer buf) throws IOException {
this.token = buf.readByteArray();
}
public final void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.token);
}
public void processPacket(IClientLoginHandler handler) {
handler.handleChallenge(this);
}
public byte[] getToken(PrivateKey key) {
return EncryptUtil.decryptData(key, this.token);
}
}

View file

@ -0,0 +1,33 @@
package common.packet;
import java.io.IOException;
import common.network.IClientLoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
public class RPacketResponse implements Packet<IClientLoginHandler> {
private byte[] token = new byte[0];
public RPacketResponse() {
}
public RPacketResponse(byte[] token) {
this.token = token;
}
public void readPacketData(PacketBuffer buf) throws IOException {
this.token = buf.readByteArray();
}
public void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.token);
}
public void processPacket(IClientLoginHandler handler) {
handler.handleResponse(this);
}
public byte[] getToken() {
return this.token;
}
}

View file

@ -0,0 +1,60 @@
package common.packet;
import java.io.IOException;
import common.network.IClientLoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
public class RPacketServerConfig implements Packet<IClientLoginHandler> {
private boolean requiresAccess;
private boolean requiresAuth;
private boolean passwordAuth;
private boolean pubkeyAuth;
public RPacketServerConfig() {
}
public RPacketServerConfig(boolean requiresAccess, boolean requiresAuth, boolean passwordAuth, boolean pubkeyAuth) {
this.requiresAccess = requiresAccess;
this.requiresAuth = requiresAuth;
this.passwordAuth = passwordAuth;
this.pubkeyAuth = pubkeyAuth;
}
public final void readPacketData(PacketBuffer buf) throws IOException {
byte flags = buf.readByte();
this.requiresAccess = (flags & 1) != 0;
this.requiresAuth = (flags & 2) != 0;
this.passwordAuth = (flags & 4) != 0;
this.pubkeyAuth = (flags & 8) != 0;
}
public final void writePacketData(PacketBuffer buf) throws IOException {
byte flags = 0;
flags |= this.requiresAccess ? 1 : 0;
flags |= this.requiresAuth ? 2 : 0;
flags |= this.passwordAuth ? 4 : 0;
flags |= this.pubkeyAuth ? 8 : 0;
buf.writeByte(flags);
}
public void processPacket(IClientLoginHandler handler) {
handler.handleConfig(this);
}
public boolean hasAccessPassword() {
return this.requiresAccess;
}
public boolean isAuthenticating() {
return this.passwordAuth;
}
public boolean canUsePassword() {
return this.passwordAuth;
}
public boolean canUsePubkey() {
return this.pubkeyAuth;
}
}

View file

@ -12,6 +12,7 @@ import java.security.PublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@ -59,6 +60,18 @@ public class EncryptUtil {
return null;
}
}
public static PrivateKey decodePrivateKey(byte[] encoded) {
try {
EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
Log.SYSTEM.error(e, "Privater Schlüssel konnte nicht dekodiert werden");
return null;
}
}
public static SecretKey decryptSharedKey(PrivateKey key, byte[] secret) {
return new SecretKeySpec(decryptData(key, secret), "AES");

View file

@ -408,4 +408,27 @@ int utf_len(const char *str) {
}
return sb.toString();
}
public static String getHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for(int z = 0; z < bytes.length; z++) {
sb.append(String.format("%02x", bytes[z]));
}
return sb.toString();
}
public static byte[] fromHexString(String str) {
if((str.length() & 1) == 1)
str = "0" + str;
byte[] bytes = new byte[str.length() / 2];
try {
for(int z = 0; z < bytes.length; z++) {
bytes[z] = (byte)Integer.parseUnsignedInt(str.substring(z * 2, (z + 1) * 2), 16);
}
}
catch(NumberFormatException e) {
return null;
}
return bytes;
}
}