mirror of
https://github.com/TuxCoding/FastLogin.git
synced 2025-07-29 18:27:36 +02:00
Extract login decryption int utilities
This commit is contained in:
@ -3,11 +3,11 @@ package com.github.games647.fastlogin.bukkit.listener.protocollib;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Random;
|
||||
|
||||
@ -36,6 +36,7 @@ public class EncryptionUtil {
|
||||
* @return The RSA key pair.
|
||||
*/
|
||||
public static KeyPair generateKeyPair() {
|
||||
// KeyPair b()
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
|
||||
|
||||
@ -55,6 +56,7 @@ public class EncryptionUtil {
|
||||
* @return an error with 4 bytes long
|
||||
*/
|
||||
public static byte[] generateVerifyToken(Random random) {
|
||||
// extracted from LoginListener
|
||||
byte[] token = new byte[VERIFY_TOKEN_LENGTH];
|
||||
random.nextBytes(token);
|
||||
return token;
|
||||
@ -68,9 +70,10 @@ public class EncryptionUtil {
|
||||
* @param publicKey public key of the server
|
||||
* @return the server id formatted as a hexadecimal string.
|
||||
*/
|
||||
public static String getServerIdHashString(String sessionId, Key sharedSecret, PublicKey publicKey) {
|
||||
public static String getServerIdHashString(String sessionId, SecretKey sharedSecret, PublicKey publicKey) {
|
||||
// found in LoginListener
|
||||
try {
|
||||
byte[] serverHash = getServerIdHash(sessionId, sharedSecret, publicKey);
|
||||
byte[] serverHash = getServerIdHash(sessionId, publicKey, sharedSecret);
|
||||
return (new BigInteger(serverHash)).toString(16);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
@ -87,8 +90,16 @@ public class EncryptionUtil {
|
||||
* @return shared secret key
|
||||
* @throws GeneralSecurityException if it fails to decrypt the data
|
||||
*/
|
||||
public static SecretKey decryptSharedKey(Cipher cipher, byte[] sharedKey) throws GeneralSecurityException {
|
||||
return new SecretKeySpec(decrypt(cipher, sharedKey), "AES");
|
||||
public static SecretKey decryptSharedKey(PrivateKey privateKey, byte[] sharedKey) throws GeneralSecurityException {
|
||||
// SecretKey a(PrivateKey var0, byte[] var1)
|
||||
return new SecretKeySpec(decrypt(privateKey, sharedKey), "AES");
|
||||
}
|
||||
|
||||
public static byte[] decrypt(PrivateKey key, byte[] data) throws GeneralSecurityException {
|
||||
// b(Key var0, byte[] var1)
|
||||
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
|
||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
||||
return decrypt(cipher, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,14 +110,17 @@ public class EncryptionUtil {
|
||||
* @return clear text data
|
||||
* @throws GeneralSecurityException if it fails to decrypt the data
|
||||
*/
|
||||
public static byte[] decrypt(Cipher cipher, byte[] data) throws GeneralSecurityException {
|
||||
private static byte[] decrypt(Cipher cipher, byte[] data) throws GeneralSecurityException {
|
||||
// inlined: byte[] a(int var0, Key var1, byte[] var2), Cipher a(int var0, String var1, Key var2)
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
private static byte[] getServerIdHash(String sessionId, Key sharedSecret, PublicKey publicKey)
|
||||
private static byte[] getServerIdHash(String sessionId, PublicKey publicKey, SecretKey sharedSecret)
|
||||
throws NoSuchAlgorithmException {
|
||||
// byte[] a(String var0, PublicKey var1, SecretKey var2)
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
|
||||
// inlined from byte[] a(String var0, byte[]... var1)
|
||||
digest.update(sessionId.getBytes(StandardCharsets.ISO_8859_1));
|
||||
digest.update(sharedSecret.getEncoded());
|
||||
digest.update(publicKey.getEncoded());
|
||||
|
@ -26,7 +26,6 @@ import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
@ -76,20 +75,16 @@ public class VerifyResponseTask implements Runnable {
|
||||
private void verifyResponse(BukkitLoginSession session) {
|
||||
PrivateKey privateKey = serverKey.getPrivate();
|
||||
|
||||
Cipher cipher;
|
||||
SecretKey loginKey;
|
||||
try {
|
||||
cipher = Cipher.getInstance(privateKey.getAlgorithm());
|
||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
||||
|
||||
loginKey = EncryptionUtil.decryptSharedKey(cipher, sharedSecret);
|
||||
loginKey = EncryptionUtil.decryptSharedKey(privateKey, sharedSecret);
|
||||
} catch (GeneralSecurityException securityEx) {
|
||||
disconnect("error-kick", false, "Cannot decrypt received contents", securityEx);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!checkVerifyToken(session, cipher, privateKey) || !encryptConnection(loginKey)) {
|
||||
if (!checkVerifyToken(session) || !enableEncryption(loginKey)) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@ -141,14 +136,13 @@ public class VerifyResponseTask implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkVerifyToken(BukkitLoginSession session, Cipher cipher, PrivateKey privateKey)
|
||||
throws GeneralSecurityException {
|
||||
private boolean checkVerifyToken(BukkitLoginSession session) throws GeneralSecurityException {
|
||||
byte[] requestVerify = session.getVerifyToken();
|
||||
//encrypted verify token
|
||||
byte[] responseVerify = packetEvent.getPacket().getByteArrays().read(1);
|
||||
|
||||
//https://github.com/bergerkiller/CraftSource/blob/master/net.minecraft.server/LoginListener.java#L182
|
||||
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(cipher, responseVerify))) {
|
||||
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(serverKey.getPrivate(), responseVerify))) {
|
||||
//check if the verify token are equal to the server sent one
|
||||
disconnect("invalid-verify-token", true
|
||||
, "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
|
||||
@ -169,7 +163,7 @@ public class VerifyResponseTask implements Runnable {
|
||||
return FieldUtils.readField(rawInjector, "networkManager", true);
|
||||
}
|
||||
|
||||
private boolean encryptConnection(SecretKey loginKey) throws IllegalArgumentException {
|
||||
private boolean enableEncryption(SecretKey loginKey) throws IllegalArgumentException {
|
||||
try {
|
||||
//get the NMS connection handle of this player
|
||||
Object networkManager = getNetworkManager();
|
||||
|
Reference in New Issue
Block a user