change key exchange to ED25519

This commit is contained in:
Sen 2025-06-16 15:12:39 +02:00
parent 256721aa12
commit 6afc26e601
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
11 changed files with 148 additions and 105 deletions

View file

@ -1,13 +1,9 @@
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;
@ -15,8 +11,8 @@ public class LPacketChallenge implements Packet<ILoginHandler> {
public LPacketChallenge() {
}
public LPacketChallenge(PublicKey pubkey, byte[] token) {
this.token = EncryptUtil.encryptData(pubkey, token);
public LPacketChallenge(byte[] token) {
this.token = token;
}
public final void readPacketData(PacketBuffer buf) throws IOException {
@ -31,7 +27,7 @@ public class LPacketChallenge implements Packet<ILoginHandler> {
handler.processChallenge(this);
}
public byte[] getToken(PrivateKey key) {
return EncryptUtil.decryptData(key, this.token);
public byte[] getToken() {
return this.token;
}
}

View file

@ -1,9 +1,13 @@
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 LPacketResponse implements Packet<ILoginHandler> {
private byte[] token = new byte[0];
@ -11,8 +15,8 @@ public class LPacketResponse implements Packet<ILoginHandler> {
public LPacketResponse() {
}
public LPacketResponse(byte[] token) {
this.token = token;
public LPacketResponse(PrivateKey key, byte[] token) {
this.token = EncryptUtil.createSignature(key, token);
}
public void readPacketData(PacketBuffer buf) throws IOException {
@ -27,7 +31,7 @@ public class LPacketResponse implements Packet<ILoginHandler> {
handler.processResponse(this);
}
public byte[] getToken() {
return this.token;
public boolean verifyToken(PublicKey key, byte[] token) {
return EncryptUtil.verifySignature(key, token, this.token);
}
}

View file

@ -1,47 +1,36 @@
package common.packet;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.SecretKey;
import common.network.ILoginHandler;
import common.network.Packet;
import common.network.PacketBuffer;
import common.util.EncryptUtil;
public class LPacketStartEncrypt implements Packet<ILoginHandler> {
private byte[] key = new byte[0];
private byte[] token = new byte[0];
private PublicKey key;
public LPacketStartEncrypt() {
}
public LPacketStartEncrypt(SecretKey secret, PublicKey pubkey, byte[] token) {
this.key = EncryptUtil.encryptData(pubkey, secret.getEncoded());
this.token = EncryptUtil.encryptData(pubkey, token);
public LPacketStartEncrypt(PublicKey pubkey) {
this.key = pubkey;
}
public void readPacketData(PacketBuffer buf) throws IOException {
this.key = buf.readByteArray();
this.token = buf.readByteArray();
this.key = EncryptUtil.decodeDHPublicKey(buf.readByteArray());
}
public void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.key);
buf.writeByteArray(this.token);
buf.writeByteArray(this.key.getEncoded());
}
public void processPacket(ILoginHandler handler) {
handler.processEncryption(this);
}
public SecretKey getKey(PrivateKey key) {
return EncryptUtil.decryptSharedKey(key, this.key);
}
public byte[] getToken(PrivateKey key) {
return EncryptUtil.decryptData(key, this.token);
public PublicKey getKey() {
return this.key;
}
}

View file

@ -1,13 +1,9 @@
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;
@ -15,8 +11,8 @@ public class RPacketChallenge implements Packet<IClientLoginHandler> {
public RPacketChallenge() {
}
public RPacketChallenge(PublicKey pubkey, byte[] token) {
this.token = EncryptUtil.encryptData(pubkey, token);
public RPacketChallenge(byte[] token) {
this.token = token;
}
public final void readPacketData(PacketBuffer buf) throws IOException {
@ -31,7 +27,7 @@ public class RPacketChallenge implements Packet<IClientLoginHandler> {
handler.handleChallenge(this);
}
public byte[] getToken(PrivateKey key) {
return EncryptUtil.decryptData(key, this.token);
public byte[] getToken() {
return this.token;
}
}

View file

@ -10,24 +10,24 @@ import common.util.EncryptUtil;
public class RPacketRequestEncrypt implements Packet<IClientLoginHandler> {
private PublicKey key;
private byte[] token;
private PublicKey tempKey;
public RPacketRequestEncrypt() {
}
public RPacketRequestEncrypt(PublicKey key, byte[] token) {
public RPacketRequestEncrypt(PublicKey key, PublicKey tempKey) {
this.key = key;
this.token = token;
this.tempKey = tempKey;
}
public final void readPacketData(PacketBuffer buf) throws IOException {
this.key = EncryptUtil.decodePublicKey(buf.readByteArray());
this.token = buf.readByteArray();
this.tempKey = EncryptUtil.decodeDHPublicKey(buf.readByteArray());
}
public final void writePacketData(PacketBuffer buf) throws IOException {
buf.writeByteArray(this.key.getEncoded());
buf.writeByteArray(this.token);
buf.writeByteArray(this.tempKey.getEncoded());
}
public void processPacket(IClientLoginHandler handler) {
@ -38,7 +38,7 @@ public class RPacketRequestEncrypt implements Packet<IClientLoginHandler> {
return this.key;
}
public byte[] getToken() {
return this.token;
public PublicKey getTempKey() {
return this.tempKey;
}
}

View file

@ -1,9 +1,13 @@
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 RPacketResponse implements Packet<IClientLoginHandler> {
private byte[] token = new byte[0];
@ -11,8 +15,8 @@ public class RPacketResponse implements Packet<IClientLoginHandler> {
public RPacketResponse() {
}
public RPacketResponse(byte[] token) {
this.token = token;
public RPacketResponse(PrivateKey key, byte[] token) {
this.token = EncryptUtil.createSignature(key, token);
}
public void readPacketData(PacketBuffer buf) throws IOException {
@ -27,7 +31,7 @@ public class RPacketResponse implements Packet<IClientLoginHandler> {
handler.handleResponse(this);
}
public byte[] getToken() {
return this.token;
public boolean verifyToken(PublicKey key, byte[] token) {
return EncryptUtil.verifySignature(key, token, this.token);
}
}

View file

@ -11,6 +11,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
@ -23,7 +25,7 @@ import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.KeyAgreement;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
@ -34,28 +36,93 @@ import javax.crypto.spec.SecretKeySpec;
import common.log.Log;
public class EncryptUtil {
public static final String KEY_ALGO_NAME = "tcr-ed25519";
public static final String KEY_ALGO_DISPLAY = "Ed25519";
private static final long CRC24_INIT = 0xB704CEL;
private static final long CRC24_POLY = 0x1864CFBL;
public static SecretKey createSharedKey() {
// private static byte[] deriveKey(byte[] secret) {
// try {
// KeySpec spec = new PBEKeySpec
// SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
// return factory.generateSecret(spec).getEncoded();
// }
// catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
// Log.SYSTEM.error(e, "Konnte Passwort-Prüfwert nicht berechnen");
// return null;
// }
// }
public static SecretKey makeKeyAgreement(PrivateKey key, PublicKey pubkey) {
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
return keygen.generateKey();
KeyAgreement agreement = KeyAgreement.getInstance("X25519");
agreement.init(key);
agreement.doPhase(pubkey, true);
return new SecretKeySpec(agreement.generateSecret(), 0, 16, "AES");
}
catch(NoSuchAlgorithmException | InvalidKeyException e) {
Log.SYSTEM.error(e, "Konnte Diffie-Hellman-Schlüsselaushandlung nicht absolvieren");
return null;
}
}
public static KeyPair createDHKeypair() {
try {
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("X25519");
return pairgen.generateKeyPair();
}
catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
Log.SYSTEM.error(e, "Konnte Schlüsselpaar für Diffie-Hellman nicht generieren");
return null;
}
}
public static KeyPair createKeypair() {
try {
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
pairgen.initialize(4096);
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("Ed25519");
return pairgen.generateKeyPair();
}
catch(NoSuchAlgorithmException e) {
Log.SYSTEM.error(e, "Konnte Schlüsselpaar nicht generiren");
Log.SYSTEM.error(e, "Konnte Schlüsselpaar nicht generieren");
return null;
}
}
public static byte[] createSignature(PrivateKey key, byte[] token) {
try {
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(key);
sig.update(token);
return sig.sign();
}
catch(SignatureException | InvalidKeyException | NoSuchAlgorithmException e) {
Log.SYSTEM.error(e, "Konnte Signatur nicht generieren");
return null;
}
}
public static boolean verifySignature(PublicKey key, byte[] token, byte[] signature) {
try {
Signature sig = Signature.getInstance("Ed25519");
sig.initVerify(key);
sig.update(token);
return sig.verify(signature);
}
catch(SignatureException | InvalidKeyException | NoSuchAlgorithmException e) {
Log.SYSTEM.error(e, "Konnte Signatur nicht verifizieren");
return false;
}
}
public static PublicKey decodeDHPublicKey(byte[] encoded) {
try {
EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
KeyFactory factory = KeyFactory.getInstance("X25519");
return factory.generatePublic(spec);
}
catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
Log.SYSTEM.error(e, "Öffentlicher Schlüssel für Diffie-Hellman konnte nicht dekodiert werden");
return null;
}
}
@ -63,7 +130,7 @@ public class EncryptUtil {
public static PublicKey decodePublicKey(byte[] encoded) {
try {
EncodedKeySpec spec = new X509EncodedKeySpec(encoded);
KeyFactory factory = KeyFactory.getInstance("RSA");
KeyFactory factory = KeyFactory.getInstance("Ed25519");
return factory.generatePublic(spec);
}
catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
@ -75,7 +142,7 @@ public class EncryptUtil {
public static PrivateKey decodePrivateKey(byte[] encoded) {
try {
EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
KeyFactory factory = KeyFactory.getInstance("RSA");
KeyFactory factory = KeyFactory.getInstance("Ed25519");
return factory.generatePrivate(spec);
}
catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
@ -84,10 +151,6 @@ public class EncryptUtil {
}
}
public static SecretKey decryptSharedKey(PrivateKey key, byte[] secret) {
return new SecretKeySpec(decryptData(key, secret), "AES");
}
public static byte[] encryptData(Key key, byte[] data) {
return cipher(Cipher.ENCRYPT_MODE, key, data);
}
@ -149,7 +212,7 @@ public class EncryptUtil {
}
public static String getArmoredPubkey(PublicKey pubkey, String cn) {
StringBuilder sb = new StringBuilder("tcr-rsa-4096 ");
StringBuilder sb = new StringBuilder(EncryptUtil.KEY_ALGO_NAME + " ");
sb.append(Base64.getEncoder().encodeToString(pubkey.getEncoded()));
sb.append(' ').append(Base64.getEncoder().encodeToString(crc24(pubkey.getEncoded())));
return cn == null || cn.isEmpty() ? sb.toString() : sb.append(' ').append(Util.sanitizeCommonName(cn)).toString();
@ -159,8 +222,8 @@ public class EncryptUtil {
String[] tok = armor.trim().split(" ");
if(tok.length != 3 && tok.length != 4)
throw new IllegalArgumentException("Key muss aus 3 oder 4 Segmenten bestehen");
if(!tok[0].equals("tcr-rsa-4096"))
throw new IllegalArgumentException("Algorithmus '" + tok[0] + "' ist nicht unterstützt, es wird derzeit nur tcr-rsa-4096 verwendet");
if(!tok[0].equals(EncryptUtil.KEY_ALGO_NAME))
throw new IllegalArgumentException("Algorithmus '" + tok[0] + "' ist nicht unterstützt, es wird derzeit nur " + EncryptUtil.KEY_ALGO_NAME + " verwendet");
byte[] key;
try {
key = Base64.getDecoder().decode(tok[1]);
@ -183,7 +246,7 @@ public class EncryptUtil {
PublicKey pubkey;
try {
EncodedKeySpec spec = new X509EncodedKeySpec(key);
KeyFactory factory = KeyFactory.getInstance("RSA");
KeyFactory factory = KeyFactory.getInstance("Ed25519");
pubkey = factory.generatePublic(spec);
}
catch(NoSuchAlgorithmException | InvalidKeySpecException e) {