diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index b13fe974..a891822f 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -13,6 +13,8 @@ import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; @@ -220,9 +222,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO public LaunchServerRuntimeConfig runtime; - public final RSAPublicKey publicKey; + public final ECPublicKey publicKey; - public final RSAPrivateKey privateKey; + public final ECPrivateKey privateKey; // Launcher binary public final JARLauncherBinary launcherBinary; @@ -279,7 +281,7 @@ public void collect() } } - public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, RSAPublicKey publicKey, RSAPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException { + public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException { this.dir = directories.dir; this.env = env; this.config = config; @@ -306,9 +308,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La modulesManager.invokeEvent(new NewLaunchServerInstanceEvent(this)); // Print keypair fingerprints - CRC32 crc = new CRC32(); - crc.update(publicKey.getModulus().toByteArray()); // IDEA говорит, что это Java 9 API. WTF? - LogHelper.subInfo("Modulus CRC32: 0x%08x", crc.getValue()); // Load class bindings. launcherEXEBinaryClass = defaultLauncherEXEBinaryClass; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java index 310ac179..030e1633 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java @@ -1,6 +1,8 @@ package pro.gravit.launchserver; import java.nio.file.Path; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; @@ -16,8 +18,8 @@ public class LaunchServerBuilder { private LaunchServer.LaunchServerEnv env; private LaunchServerModulesManager modulesManager; private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories(); - private RSAPublicKey publicKey; - private RSAPrivateKey privateKey; + private ECPublicKey publicKey; + private ECPrivateKey privateKey; private LaunchServer.LaunchServerConfigManager launchServerConfigManager; public LaunchServerBuilder setConfig(LaunchServerConfig config) { @@ -55,12 +57,12 @@ public LaunchServerBuilder setDir(Path dir) { return this; } - public LaunchServerBuilder setPublicKey(RSAPublicKey publicKey) { + public LaunchServerBuilder setPublicKey(ECPublicKey publicKey) { this.publicKey = publicKey; return this; } - public LaunchServerBuilder setPrivateKey(RSAPrivateKey privateKey) { + public LaunchServerBuilder setPrivateKey(ECPrivateKey privateKey) { this.privateKey = privateKey; return this; } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index 344f71f3..040466bd 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -7,9 +7,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import pro.gravit.launcher.Launcher; import pro.gravit.launcher.hwid.HWIDProvider; import pro.gravit.launcher.modules.events.PreConfigPhase; @@ -35,8 +38,11 @@ import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.SecurityHelper; +import javax.crypto.Cipher; + public class LaunchServerStarter { public static void main(String[] args) throws Exception { + Security.addProvider(new BouncyCastleProvider()); JVMHelper.checkStackTrace(LaunchServerStarter.class); JVMHelper.verifySystemProperties(LaunchServer.class, true); LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log")); @@ -51,8 +57,8 @@ public static void main(String[] args) throws Exception { Path configFile, runtimeConfigFile; Path publicKeyFile =dir.resolve("public.key"); Path privateKeyFile = dir.resolve("private.key"); - RSAPublicKey publicKey; - RSAPrivateKey privateKey; + ECPublicKey publicKey; + ECPrivateKey privateKey; LaunchServerRuntimeConfig runtimeConfig; LaunchServerConfig config; @@ -84,19 +90,17 @@ public static void main(String[] args) throws Exception { LogHelper.warning("JLine2 isn't in classpath, using std"); } if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) { - LogHelper.info("Reading RSA keypair"); - publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)); - privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(privateKeyFile)); - if (!publicKey.getModulus().equals(privateKey.getModulus())) - throw new IOException("Private and public key modulus mismatch"); + LogHelper.info("Reading EC keypair"); + publicKey = SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile)); + privateKey = SecurityHelper.toPrivateECKey(IOHelper.read(privateKeyFile)); } else { - LogHelper.info("Generating RSA keypair"); - KeyPair pair = SecurityHelper.genRSAKeyPair(); - publicKey = (RSAPublicKey) pair.getPublic(); - privateKey = (RSAPrivateKey) pair.getPrivate(); + LogHelper.info("Generating EC keypair"); + KeyPair pair = SecurityHelper.genECKeyPair(new SecureRandom()); + publicKey = (ECPublicKey) pair.getPublic(); + privateKey = (ECPrivateKey) pair.getPrivate(); // Write key pair list - LogHelper.info("Writing RSA keypair list"); + LogHelper.info("Writing EC keypair list"); IOHelper.write(publicKeyFile, publicKey.getEncoded()); IOHelper.write(privateKeyFile, privateKey.getEncoded()); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java index 283af7d5..7c5d6e06 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java @@ -154,7 +154,7 @@ public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWI db_hwid.totalMemory = Long.valueOf(set.getString(hwidFieldTotalMemory)); db_hwid.macAddr = set.getString(hwidFieldMAC); if (LogHelper.isDevEnabled()) { - LogHelper.dev("Compare HWID: %s vs %s", hwid.getSerializeString(), db_hwid.getSerializeString()); + LogHelper.dev("Compare HWID: %s vs %s", hwid.toString(), db_hwid.toString()); } int compare_point = hwid.compare(db_hwid); if (compare_point < compare) continue; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java index 49e53c53..9494a143 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherConfigurator.java @@ -65,6 +65,10 @@ public void setAddress(String address) { setStringField("address", address); } + public void setPasswordEncryptKey(String pass) { + setStringField("passwordEncryptKey", pass); + } + public void setProjectName(String name) { setStringField("projectname", name); } @@ -146,32 +150,4 @@ private void setBooleanField(String name, boolean b) constructor.instructions.add(new InsnNode(b ? Opcodes.ICONST_1 : Opcodes.ICONST_0)); constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, name, Type.BOOLEAN_TYPE.getInternalName())); } - - public void setGuardLicense(String name, String key, String encryptKey) { - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new LdcInsnNode(name)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc)); - - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new LdcInsnNode(key)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc)); - - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new LdcInsnNode(encryptKey)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc)); - } - - public void nullGuardLicense() { - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseName", stringDesc)); - - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseKey", stringDesc)); - - constructor.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); - constructor.instructions.add(new InsnNode(Opcodes.ACONST_NULL)); - constructor.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, autoGenConfigName, "guardLicenseEncryptKey", stringDesc)); - } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java index f420cd7b..b111755d 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java @@ -124,16 +124,13 @@ public Path process(Path inputJar) throws IOException { BuildContext context = new BuildContext(output, launcherConfigurator, this); server.buildHookManager.hook(context); launcherConfigurator.setAddress(server.config.netty.address); - if (server.config.guardLicense != null) - launcherConfigurator.setGuardLicense(server.config.guardLicense.name, server.config.guardLicense.key, server.config.guardLicense.encryptKey); - else - launcherConfigurator.nullGuardLicense(); launcherConfigurator.setProjectName(server.config.projectName); launcherConfigurator.setSecretKey(SecurityHelper.randomStringAESKey()); launcherConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512)); launcherConfigurator.setGuardType(server.config.launcher.guardType); launcherConfigurator.setWarningMissArchJava(server.config.launcher.warningMissArchJava); launcherConfigurator.setEnv(server.config.env); + launcherConfigurator.setPasswordEncryptKey(server.runtime.passwordEncryptKey); String launcherSalt = SecurityHelper.randomStringToken(); byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, server.runtime.clientCheckSecret.concat(".").concat(launcherSalt)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/GetModulusCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/GetModulusCommand.java index c40eda10..b7454ecc 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/GetModulusCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/GetModulusCommand.java @@ -21,6 +21,6 @@ public String getUsageDescription() { @Override public void invoke(String... args) throws Exception { - LogHelper.info("You publickey modulus: %s", server.publicKey.getModulus().toString(16)); + //LogHelper.info("You publickey modulus: %s", server.publicKey.getModulus().toString(16)); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index a3e5aa04..7f7e01f5 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -84,7 +84,6 @@ public AuthProviderPair getAuthProviderPair() { public ExeConf launch4j; public NettyConfig netty; - public GuardLicenseConf guardLicense; public String whitelistRejectString; public LauncherConf launcher; @@ -280,12 +279,6 @@ public NettyBindAddress(String address, int port) { this.port = port; } } - - public static class GuardLicenseConf { - public String name; - public String key; - public String encryptKey; - } public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { LaunchServerConfig newConfig = new LaunchServerConfig(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java index 0e600258..7e1798f9 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerRuntimeConfig.java @@ -4,18 +4,18 @@ import pro.gravit.utils.helper.SecurityHelper; public class LaunchServerRuntimeConfig { - public String clientToken; + public String passwordEncryptKey; public String oemUnlockKey; public String registerApiKey; public String clientCheckSecret; public void verify() { - if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null"); + if (passwordEncryptKey == null) LogHelper.error("[RuntimeConfig] passwordEncryptKey must not be null"); if (clientCheckSecret == null) { LogHelper.warning("[RuntimeConfig] clientCheckSecret must not be null"); clientCheckSecret = SecurityHelper.randomStringToken(); } } public void reset() { - clientToken = SecurityHelper.randomStringToken(); + passwordEncryptKey = SecurityHelper.randomStringToken(); registerApiKey = SecurityHelper.randomStringToken(); clientCheckSecret = SecurityHelper.randomStringToken(); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserHWID.java b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserHWID.java index d81dddf3..a68298bc 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserHWID.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/dao/UserHWID.java @@ -42,13 +42,13 @@ public OshiHWID toHWID() } @Override - public String getSerializeString() { - return toHWID().getSerializeString(); + public int getLevel() { + return toHWID().getLevel(); } @Override - public int getLevel() { - return toHWID().getLevel(); + public int getAntiLevel() { + return 0; } @Override @@ -60,4 +60,9 @@ public int compare(HWID hwid) { public boolean isNull() { return toHWID().isNull(); } + + @Override + public void normalize() { + + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java index e4ec148a..7d03fb55 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/AuthResponse.java @@ -14,7 +14,7 @@ import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.request.auth.AuthRequest; import pro.gravit.launcher.request.auth.password.AuthPlainPassword; -import pro.gravit.launcher.request.auth.password.AuthRSAPassword; +import pro.gravit.launcher.request.auth.password.AuthECPassword; import pro.gravit.launchserver.auth.AuthException; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.hwid.HWIDException; @@ -59,11 +59,11 @@ public void execute(ChannelHandlerContext ctx, Client clientData) throws Excepti AuthProvider.authError("Don't skip Launcher Update"); return; } - if(password instanceof AuthRSAPassword) + if(password instanceof AuthECPassword) { try { - password = new AuthPlainPassword(IOHelper.decode(SecurityHelper.newRSADecryptCipher(server.privateKey). - doFinal(((AuthRSAPassword) password).password))); + password = new AuthPlainPassword(IOHelper.decode(SecurityHelper.decrypt(server.runtime.passwordEncryptKey + , ((AuthECPassword) password).password))); } catch (IllegalBlockSizeException | BadPaddingException ignored) { throw new AuthException("Password decryption error"); } diff --git a/LaunchServer/src/test/java/pro/gravit/launchserver/StartLaunchServerTest.java b/LaunchServer/src/test/java/pro/gravit/launchserver/StartLaunchServerTest.java index 4af453ca..d19ab520 100644 --- a/LaunchServer/src/test/java/pro/gravit/launchserver/StartLaunchServerTest.java +++ b/LaunchServer/src/test/java/pro/gravit/launchserver/StartLaunchServerTest.java @@ -3,6 +3,9 @@ import java.io.IOException; import java.nio.file.Path; import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; @@ -35,9 +38,9 @@ public static void prepare() throws Exception Launcher.gsonManager.initGson(); LaunchServerRuntimeConfig runtimeConfig = new LaunchServerRuntimeConfig(); LaunchServerBuilder builder = new LaunchServerBuilder(); - KeyPair pair = SecurityHelper.genRSAKeyPair(); - RSAPublicKey publicKey = (RSAPublicKey) pair.getPublic(); - RSAPrivateKey privateKey = (RSAPrivateKey) pair.getPrivate(); + KeyPair pair = SecurityHelper.genECKeyPair(new SecureRandom()); + ECPublicKey publicKey = (ECPublicKey) pair.getPublic(); + ECPrivateKey privateKey = (ECPrivateKey) pair.getPrivate(); builder.setDir(dir) .setEnv(LaunchServer.LaunchServerEnv.TEST) .setConfig(config) diff --git a/Launcher/build.gradle b/Launcher/build.gradle index 4d368664..a989aea5 100644 --- a/Launcher/build.gradle +++ b/Launcher/build.gradle @@ -50,6 +50,7 @@ task javadocJar(type: Jar) { pack project(':LauncherAuthlib') bundle 'com.github.oshi:oshi-core:3.13.0' bundle 'org.apache.httpcomponents:httpclient:4.5.7' + bundle 'org.bouncycastle:bcprov-jdk15:1.46' pack 'io.netty:netty-codec-http:4.1.36.Final' pack 'org.ow2.asm:asm-tree:7.1' } diff --git a/Launcher/runtime/config.js b/Launcher/runtime/config.js index 1f1f81b4..c63a5dc4 100644 --- a/Launcher/runtime/config.js +++ b/Launcher/runtime/config.js @@ -1,6 +1,6 @@ var config = { //*** Настройки лаунчера ***// - dir: "GravitLauncher", // Название папки лаунчера + // Название папки лаунчера настраивается в LaunchServer.conf(строка projectName) title: "GravitLauncher", // Заголовок окна icons: ["favicon.png"], // Путь/Пути до иконки окна @@ -36,12 +36,6 @@ var config = { settingsMagic: 0xC0DE5, // Магия вне хогвартса }; -DirBridge.dir = DirBridge.getLauncherDir(config.dir); -DirBridge.dirStore = DirBridge.getStoreDir(config.dir); -DirBridge.dirProjectStore = DirBridge.getProjectStoreDir(config.dir); -if (!IOHelper.isDir(DirBridge.dir)) { - java.nio.file.Files.createDirectory(DirBridge.dir); -} DirBridge.defaultUpdatesDir = DirBridge.dir.resolve("updates"); if (!IOHelper.isDir(DirBridge.defaultUpdatesDir)) { java.nio.file.Files.createDirectory(DirBridge.defaultUpdatesDir); diff --git a/Launcher/runtime/dialog/overlay/settings/settings.js b/Launcher/runtime/dialog/overlay/settings/settings.js index 514b5739..22c0c0a6 100644 --- a/Launcher/runtime/dialog/overlay/settings/settings.js +++ b/Launcher/runtime/dialog/overlay/settings/settings.js @@ -155,7 +155,7 @@ var settingsOverlay = { }, setPassword: function(password) { - var encrypted = SecurityHelper.newRSAEncryptCipher(Launcher.getConfig().publicKey).doFinal(IOHelper.encode(password)); + var encrypted = FunctionalBridge.encryptPassword(password); return encrypted; }, diff --git a/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java index 6d131792..38fd00b8 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java +++ b/Launcher/src/main/java/pro/gravit/launcher/LauncherEngine.java @@ -1,12 +1,16 @@ package pro.gravit.launcher; +import java.io.IOException; +import java.nio.file.Path; +import java.security.*; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.InvalidKeySpecException; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import pro.gravit.launcher.client.ClientModuleManager; -import pro.gravit.launcher.client.DirBridge; -import pro.gravit.launcher.client.FunctionalBridge; -import pro.gravit.launcher.client.LauncherUpdateController; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import pro.gravit.launcher.client.*; import pro.gravit.launcher.client.events.ClientEngineInitPhase; import pro.gravit.launcher.client.events.ClientPreGuiPhase; import pro.gravit.launcher.guard.LauncherGuardManager; @@ -22,10 +26,9 @@ import pro.gravit.launcher.request.auth.RestoreSessionRequest; import pro.gravit.launcher.request.update.UpdateRequest; import pro.gravit.launcher.request.websockets.StandartClientWebSocketService; -import pro.gravit.utils.helper.CommonHelper; -import pro.gravit.utils.helper.EnvHelper; -import pro.gravit.utils.helper.JVMHelper; -import pro.gravit.utils.helper.LogHelper; +import pro.gravit.utils.helper.*; + +import javax.crypto.Cipher; public class LauncherEngine { public static final AtomicBoolean IS_CLIENT = new AtomicBoolean(false); @@ -37,6 +40,12 @@ public static void main(String... args) throws Throwable { //if(!LauncherAgent.isStarted()) throw new SecurityException("JavaAgent not set"); LogHelper.printVersion("Launcher"); LogHelper.printLicense("Launcher"); + try { + Security.addProvider(new BouncyCastleProvider()); + } catch (Exception ignored) + { + LogHelper.warning("BouncyCastle not found"); + } LauncherEngine.modulesManager = new ClientModuleManager(); LauncherConfig.getAutogenConfig().initModules(); @@ -69,9 +78,33 @@ public static void initGson(ClientModuleManager modulesManager) { Launcher.gsonManager.initGson(); } + public void readKeys() throws IOException, InvalidKeySpecException { + if(privateKey != null || publicKey != null) return; + Path dir = DirBridge.dir; + Path publicKeyFile =dir.resolve("public.key"); + Path privateKeyFile = dir.resolve("private.key"); + if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) { + LogHelper.info("Reading EC keypair"); + publicKey = SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile)); + privateKey = SecurityHelper.toPrivateECKey(IOHelper.read(privateKeyFile)); + } else { + LogHelper.info("Generating EC keypair"); + KeyPair pair = SecurityHelper.genECKeyPair(new SecureRandom()); + publicKey = (ECPublicKey) pair.getPublic(); + privateKey = (ECPrivateKey) pair.getPrivate(); + + // Write key pair list + LogHelper.info("Writing EC keypair list"); + IOHelper.write(publicKeyFile, publicKey.getEncoded()); + IOHelper.write(privateKeyFile, privateKey.getEncoded()); + } + } + // Instance private final AtomicBoolean started = new AtomicBoolean(false); public RuntimeProvider runtimeProvider; + public ECPublicKey publicKey; + public ECPrivateKey privateKey; public static ClientModuleManager modulesManager; @@ -116,6 +149,7 @@ public void start(String... args) throws Throwable { Objects.requireNonNull(args, "args"); if (started.getAndSet(true)) throw new IllegalStateException("Launcher has been already started"); + readKeys(); LauncherEngine.modulesManager.invokeEvent(new ClientEngineInitPhase(this)); runtimeProvider.preLoad(); LauncherGuardManager.initGuard(false); diff --git a/Launcher/src/main/java/pro/gravit/launcher/bridge/GravitGuardBridge.java b/Launcher/src/main/java/pro/gravit/launcher/bridge/GravitGuardBridge.java deleted file mode 100644 index ec8e9fa5..00000000 --- a/Launcher/src/main/java/pro/gravit/launcher/bridge/GravitGuardBridge.java +++ /dev/null @@ -1,22 +0,0 @@ -package pro.gravit.launcher.bridge; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; - -import pro.gravit.launcher.LauncherAPI; - -@LauncherAPI -public class GravitGuardBridge { - @LauncherAPI - public static native void callGuard(); - - @LauncherAPI - public static int sendHTTPRequest(String strurl) throws IOException { - URL url = new URL(strurl); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("Content-Language", "en-US"); - return connection.getResponseCode(); - } -} diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java index 15e74934..7bfba319 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/ClientLauncher.java @@ -114,7 +114,7 @@ public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfil this.clientDir = clientDir; // Client params this.pp = pp; - this.accessToken = SecurityHelper.verifyToken(accessToken); + this.accessToken = accessToken; this.autoEnter = autoEnter; this.fullScreen = fullScreen; this.ram = ram; @@ -132,8 +132,7 @@ public Params(HInput input) throws Exception { // Client params pp = new PlayerProfile(input); byte[] encryptedAccessToken = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH); - String accessTokenD = new String(SecurityHelper.decrypt(Launcher.getConfig().secretKeyClient.getBytes(), encryptedAccessToken)); - accessToken = SecurityHelper.verifyToken(accessTokenD); + accessToken = new String(SecurityHelper.decrypt(Launcher.getConfig().secretKeyClient.getBytes(), encryptedAccessToken)); autoEnter = input.readBoolean(); fullScreen = input.readBoolean(); ram = input.readVarInt(); @@ -458,9 +457,7 @@ public static void main(String... args) throws Throwable { EnvHelper.checkDangerousParams(); JVMHelper.checkStackTrace(ClientLauncher.class); LogHelper.printVersion("Client Launcher"); - if (engine.runtimeProvider == null) engine.runtimeProvider = new JSRuntimeProvider(); - engine.runtimeProvider.init(true); - engine.runtimeProvider.preLoad(); + engine.readKeys(); HWIDProvider.registerHWIDs(); LauncherGuardManager.initGuard(true); LogHelper.debug("Reading ClientLauncher params"); diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java b/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java index 194ea88e..3175bc43 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/DirBridge.java @@ -5,9 +5,11 @@ import java.nio.file.Path; import java.nio.file.Paths; +import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherAPI; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.JVMHelper; +import pro.gravit.utils.helper.LogHelper; public class DirBridge { @@ -98,4 +100,18 @@ public static Path getLegacyLauncherDir(String projectname) { public static void setUseLegacyDir(boolean b) { useLegacyDir = b; } + + static { + String projectName = Launcher.getConfig().projectname; + try { + DirBridge.dir = getLauncherDir(projectName); + if(!IOHelper.exists(DirBridge.dir)) Files.createDirectories(DirBridge.dir); + DirBridge.dirStore = getStoreDir(projectName); + if(!IOHelper.exists(DirBridge.dirStore)) Files.createDirectories(DirBridge.dirStore); + DirBridge.dirProjectStore = getProjectStoreDir(projectName); + if(!IOHelper.exists(DirBridge.dirProjectStore)) Files.createDirectories(DirBridge.dirProjectStore); + } catch (IOException e) { + LogHelper.error(e); + } + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/client/FunctionalBridge.java b/Launcher/src/main/java/pro/gravit/launcher/client/FunctionalBridge.java index 560b5abe..2cdf51ab 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/client/FunctionalBridge.java +++ b/Launcher/src/main/java/pro/gravit/launcher/client/FunctionalBridge.java @@ -1,11 +1,13 @@ package pro.gravit.launcher.client; import java.nio.file.Path; +import java.util.Arrays; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.api.AuthService; import pro.gravit.launcher.events.request.AuthRequestEvent; @@ -19,7 +21,9 @@ import pro.gravit.launcher.managers.HasherStore; import pro.gravit.launcher.request.Request; import pro.gravit.utils.Version; +import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; +import pro.gravit.utils.helper.SecurityHelper; public class FunctionalBridge { @LauncherAPI @@ -133,4 +137,9 @@ public static String getLauncherVersion() { Version.BUILD ); } + @LauncherAPI + public static byte[] encryptPassword(String string) throws Exception { + byte[] encode = IOHelper.encode(string); + return SecurityHelper.encrypt(Launcher.getConfig().passwordEncryptKey, encode); + } } diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java index 92718c25..6f0ce1d9 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGuardManager.java @@ -12,7 +12,7 @@ public static void initGuard(boolean clientInstance) { LauncherConfig config = Launcher.getConfig(); switch (config.guardType) { case "gravitguard": { - guard = new LauncherGravitGuard(); + guard = new LauncherStdGuard(); break; } case "wrapper": { diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherStdGuard.java similarity index 86% rename from Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java rename to Launcher/src/main/java/pro/gravit/launcher/guard/LauncherStdGuard.java index 4052673a..d93d9baa 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherGravitGuard.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherStdGuard.java @@ -8,7 +8,6 @@ import pro.gravit.launcher.Launcher; import pro.gravit.launcher.LauncherConfig; -import pro.gravit.launcher.bridge.GravitGuardBridge; import pro.gravit.launcher.client.ClientLauncher; import pro.gravit.launcher.client.ClientLauncherContext; import pro.gravit.launcher.client.DirBridge; @@ -16,14 +15,14 @@ import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.UnpackHelper; -//Используется для всех типов защит, совместимых с новым GravitGuard API -public class LauncherGravitGuard implements LauncherGuardInterface { +//Стандартный интерфейс для всех AntiInject +public class LauncherStdGuard implements LauncherGuardInterface { public String protectToken; public Path javaBinPath; @Override public String getName() { - return "gravitguard"; + return "stdguard"; } @Override @@ -50,7 +49,7 @@ public int getClientJVMBits() { public void init(boolean clientInstance) { try { String projectName = Launcher.getConfig().projectname; - UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe"))); + UnpackHelper.unpack(Launcher.getResourceURL("wrapper64.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe"))); UnpackHelper.unpack(Launcher.getResourceURL("AntiInject64.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject64.dll")); UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("32.exe"))); @@ -58,7 +57,6 @@ public void init(boolean clientInstance) { } catch (IOException e) { throw new SecurityException(e); } - if (clientInstance && JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) GravitGuardBridge.callGuard(); } @Override @@ -74,9 +72,7 @@ public void addCustomEnv(ClientLauncherContext context) { else env.put("JAVA_HOME", javaBinPath.toAbsolutePath().toString()); LauncherConfig config = Launcher.getConfig(); - env.put("GUARD_BRIDGE", GravitGuardBridge.class.getName()); env.put("GUARD_USERNAME", context.playerProfile.username); - env.put("GUARD_PUBLICKEY", config.publicKey.getModulus().toString(16)); env.put("GUARD_PROJECTNAME", config.projectname); if (protectToken != null) env.put("GUARD_TOKEN", protectToken); diff --git a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java index 01eccbc1..550a1925 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java +++ b/Launcher/src/main/java/pro/gravit/launcher/guard/LauncherWrapperGuard.java @@ -63,7 +63,6 @@ public void addCustomEnv(ClientLauncherContext context) { env.put("JAVA_HOME", System.getProperty("java.home")); LauncherConfig config = Launcher.getConfig(); env.put("GUARD_USERNAME", context.playerProfile.username); - env.put("GUARD_PUBLICKEY", config.publicKey.getModulus().toString(16)); env.put("GUARD_PROJECTNAME", config.projectname); if (protectToken != null) env.put("GUARD_TOKEN", protectToken); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java b/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java index 05edd785..290a1e38 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/AutogenConfig.java @@ -12,6 +12,7 @@ public class AutogenConfig { public String guardLicenseEncryptKey; public String secureCheckHash; public String secureCheckSalt; + public String passwordEncryptKey; public int env; public boolean isWarningMissArchJava; // 0 - Dev (дебаг включен по умолчанию, все сообщения) diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java index 6019b49d..6b012e79 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/LauncherConfig.java @@ -1,6 +1,8 @@ package pro.gravit.launcher; import java.io.IOException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.util.Collections; @@ -31,7 +33,7 @@ public static AutogenConfig getAutogenConfig() { public String secretKeyClient; public String oemUnlockKey; @LauncherAPI - public final RSAPublicKey publicKey; + public final ECPublicKey publicKey; @LauncherAPI public final Map runtime; @@ -46,12 +48,14 @@ public static AutogenConfig getAutogenConfig() { public final String secureCheckHash; public final String secureCheckSalt; + public final String passwordEncryptKey; @LauncherAPI public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException { - publicKey = SecurityHelper.toPublicRSAKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH)); + publicKey = SecurityHelper.toPublicECKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH)); secureCheckHash = config.secureCheckHash; secureCheckSalt = config.secureCheckSalt; + passwordEncryptKey = config.passwordEncryptKey; projectname = config.projectname; clientPort = config.clientPort; secretKeyClient = config.secretKeyClient; @@ -84,7 +88,7 @@ public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException } @LauncherAPI - public LauncherConfig(String address, RSAPublicKey publicKey, Map runtime, String projectname) { + public LauncherConfig(String address, ECPublicKey publicKey, Map runtime, String projectname) { this.address = address; this.publicKey = Objects.requireNonNull(publicKey, "publicKey"); this.runtime = Collections.unmodifiableMap(new HashMap<>(runtime)); @@ -99,10 +103,11 @@ public LauncherConfig(String address, RSAPublicKey publicKey, Map runtime) { + public LauncherConfig(String address, ECPublicKey publicKey, Map runtime) { this.address = address; this.publicKey = Objects.requireNonNull(publicKey, "publicKey"); this.runtime = Collections.unmodifiableMap(new HashMap<>(runtime)); @@ -117,6 +122,7 @@ public LauncherConfig(String address, RSAPublicKey publicKey, Map 2) + { + wtfCharTypeCombo+=3; + } + //Нам подсунули серию из слишком большого числа идущих подряд чисел. Что за? + if((charType == 0) && lastCharTypeCombo > 4) + { + wtfCharTypeCombo++; + } + } + else + { + if(skipLastCharType && ( charType == -1 || charType == 3 )) + { + skipLastCharType = false; + } + else + { + skipLastCharType = true; + lastCharType = charType; + } + } + } + //Считаем результат + if(maxCombo > 3) result+= maxCombo * 3; + if(wtfCharTypeCombo > 1) result+= wtfCharTypeCombo * 2; + return result; + } + public static int getCharType(char c) + { + if(c >= '0' && c <= '9') return 0; + if(c >= 'A' && c <= 'Z') return 1; + if(c >= 'a' && c <= 'z') return 2; + if(c == ' ' || c == '-' || c == '_') return 3; + return -1; + } +} diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/NoHWID.java b/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/NoHWID.java index d03c1d82..853ec6e2 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/NoHWID.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/NoHWID.java @@ -1,16 +1,17 @@ package pro.gravit.launcher.hwid; public class NoHWID implements HWID { - @Override - public String getSerializeString() { - return ""; - } @Override public int getLevel() { return 0; } + @Override + public int getAntiLevel() { + return 0; + } + @Override public int compare(HWID hwid) { return 0; @@ -20,4 +21,9 @@ public int compare(HWID hwid) { public boolean isNull() { return true; } + + @Override + public void normalize() { + //Skip + } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/OshiHWID.java b/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/OshiHWID.java index a3f36dac..efced953 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/OshiHWID.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/hwid/OshiHWID.java @@ -20,33 +20,33 @@ public class OshiHWID implements HWID { @LauncherAPI public String macAddr; - @Override - public String getSerializeString() { - return gson.toJson(this); - } - @Override public int getLevel() //Уровень доверия, насколько уникальные значения { int result = 0; - if (totalMemory != 0) result += 8; - if (serialNumber != null && !serialNumber.equals("unknown")) result += 12; - if (HWDiskSerial != null && !HWDiskSerial.equals("unknown")) result += 30; - if (processorID != null && !processorID.equals("unknown")) result += 10; - if (macAddr != null && !macAddr.equals("00:00:00:00:00:00")) result += 15; + if (totalMemory != 0) result += 32; + if (serialNumber != null) result += isRealSerialNumber() ? 20 : 3; + if (HWDiskSerial != null && !HWDiskSerial.isEmpty()) result += 38; + if (processorID != null && !processorID.isEmpty()) result += 15; + if (macAddr != null && !macAddr.isEmpty()) result += 25; return result; } + @Override + public int getAntiLevel() { + return HWIDCheckHelper.checkString(serialNumber) + HWIDCheckHelper.checkString(HWDiskSerial); + } + @Override public int compare(HWID hwid) { if (hwid instanceof OshiHWID) { int rate = 0; OshiHWID oshi = (OshiHWID) hwid; if (Math.abs(oshi.totalMemory - totalMemory) < 1024 * 1024) rate += 5; - if (oshi.totalMemory == totalMemory) rate += 15; - if (oshi.HWDiskSerial.equals(HWDiskSerial)) rate += 45; - if (oshi.processorID.equals(processorID)) rate += 18; - if (oshi.serialNumber.equals(serialNumber)) rate += 15; + if (oshi.totalMemory == totalMemory) rate += 32; + if (oshi.HWDiskSerial.equals(HWDiskSerial) && !HWDiskSerial.isEmpty()) rate += 38; + if (oshi.processorID.equals(processorID) && !processorID.isEmpty()) rate += 15; + if (oshi.serialNumber.equals(serialNumber)) rate += isRealSerialNumber() ? 20 : 3; if (!oshi.macAddr.isEmpty() && oshi.macAddr.equals(macAddr)) rate += 19; return rate; } @@ -58,6 +58,24 @@ public boolean isNull() { return getLevel() < 15; } + @Override + public void normalize() { + HWDiskSerial = HWDiskSerial.trim(); + serialNumber = serialNumber.trim(); + processorID = processorID.trim(); + macAddr = macAddr.trim(); + } + public boolean isRealSerialNumber() + { + if(serialNumber.isEmpty()) return false; + if(serialNumber.equals("System Serial Number")) return false; + if(serialNumber.equals("To be filled by O.E.M.")) return false; + if(serialNumber.equals("unknown")) return false; + if(serialNumber.equals("None")) return false; + if(serialNumber.equals("Default string")) return false; + return true; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java index b7aef7d5..868a39b2 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/AuthRequest.java @@ -6,7 +6,7 @@ import pro.gravit.launcher.hwid.HWID; import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.auth.password.AuthPlainPassword; -import pro.gravit.launcher.request.auth.password.AuthRSAPassword; +import pro.gravit.launcher.request.auth.password.AuthECPassword; import pro.gravit.launcher.request.websockets.WebSocketRequest; import pro.gravit.utils.ProviderMap; import pro.gravit.utils.helper.VerifyHelper; @@ -48,7 +48,7 @@ public enum ConnectTypes { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.password = new AuthRSAPassword(password.clone()); + this.password = new AuthECPassword(password.clone()); this.hwid = hwid; customText = ""; auth_id = ""; @@ -59,7 +59,7 @@ public AuthRequest(String login, byte[] password, HWID hwid) { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.password = new AuthRSAPassword(password.clone()); + this.password = new AuthECPassword(password.clone()); this.hwid = hwid; this.auth_id = auth_id; customText = ""; @@ -70,7 +70,7 @@ public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) { @LauncherAPI public AuthRequest(String login, byte[] password, HWID hwid, String customText, String auth_id) { this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); - this.password = new AuthRSAPassword(password.clone()); + this.password = new AuthECPassword(password.clone()); this.hwid = hwid; this.auth_id = auth_id; this.customText = customText; @@ -80,7 +80,7 @@ public AuthRequest(String login, byte[] password, HWID hwid, String customText, public AuthRequest(String login, byte[] encryptedPassword, String auth_id, ConnectTypes authType) { this.login = login; - this.password = new AuthRSAPassword(encryptedPassword.clone()); + this.password = new AuthECPassword(encryptedPassword.clone()); this.auth_id = auth_id; this.authType = authType; this.hwid = null; @@ -106,7 +106,7 @@ public String getType() { public static void registerProviders() { if(!registerProviders) { providers.register("plain", AuthPlainPassword.class); - providers.register("rsa", AuthRSAPassword.class); + providers.register("rsa", AuthECPassword.class); registerProviders = true; } } diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthECPassword.java similarity index 72% rename from LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java rename to LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthECPassword.java index 0a8a1831..2e8854b7 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthRSAPassword.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/request/auth/password/AuthECPassword.java @@ -3,11 +3,11 @@ import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.request.auth.AuthRequest; -public class AuthRSAPassword implements AuthRequest.AuthPasswordInterface { +public class AuthECPassword implements AuthRequest.AuthPasswordInterface { @LauncherNetworkAPI public final byte[] password; - public AuthRSAPassword(byte[] password) { + public AuthECPassword(byte[] password) { this.password = password; } diff --git a/LauncherCore/build.gradle b/LauncherCore/build.gradle index f903630b..7d26a1a1 100644 --- a/LauncherCore/build.gradle +++ b/LauncherCore/build.gradle @@ -6,6 +6,7 @@ compileOnly 'org.jline:jline:3.11.0' compileOnly 'org.jline:jline-reader:3.11.0' compileOnly 'org.jline:jline-terminal:3.11.0' + compileOnly 'org.bouncycastle:bcprov-jdk15:1.46' compile 'com.google.code.gson:gson:2.8.5' testCompile 'org.junit.jupiter:junit-jupiter:5.4.1' } diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java index 22204cf1..e65b913d 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/JVMHelper.java @@ -7,6 +7,7 @@ import java.lang.management.RuntimeMXBean; import java.net.MalformedURLException; import java.net.URL; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.Locale; @@ -110,6 +111,13 @@ public static URL[] getClassPathURL() { return list; } + public static X509Certificate[] getCertificates(Class clazz) + { + Object[] signers = clazz.getSigners(); + if(signers == null) return new X509Certificate[] {}; + return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new); + } + public static void checkStackTrace(Class mainClass) { LogHelper.debug("Testing stacktrace"); Exception e = new Exception("Testing stacktrace"); diff --git a/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java b/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java index e72130a8..9f63f46a 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/helper/SecurityHelper.java @@ -4,19 +4,9 @@ import java.io.InputStream; import java.net.URL; import java.nio.file.Path; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.Signature; -import java.security.SignatureException; -import java.security.interfaces.RSAKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.ECGenParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -30,6 +20,8 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.provider.JCEIESCipher; import pro.gravit.launcher.LauncherAPI; public final class SecurityHelper { @@ -77,14 +69,17 @@ public byte[] verify(byte[] digest) { } } - // Algorithm constants + // EC Algorithm constants - public static final String RSA_ALGO = "RSA"; + public static final String EC_ALGO = "EC"; - public static final String RSA_SIGN_ALGO = "SHA256withRSA"; + public static final String EC_CURVE = "secp256k1"; + public static final String EC_SIGN_ALGO = "SHA256withECDSA"; - public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding"; + public static final String EC_CIPHER_ALGO = "ECIES"; + + // RSA Algorithm constants // Algorithm size constants public static final int TOKEN_LENGTH = 16; @@ -144,25 +139,19 @@ public static byte[] digest(DigestAlgorithm algo, URL url) throws IOException { } } - - public static KeyPair genRSAKeyPair() { - return genRSAKeyPair(newRandom()); - } - - - public static KeyPair genRSAKeyPair(SecureRandom random) { + public static KeyPair genECKeyPair(SecureRandom random) { try { - KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGO); - generator.initialize(RSA_KEY_LENGTH_BITS, random); + KeyPairGenerator generator = KeyPairGenerator.getInstance(EC_ALGO); + generator.initialize(new ECGenParameterSpec(EC_CURVE), random); return generator.genKeyPair(); - } catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { throw new InternalError(e); } } - public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { - Signature signature = newRSAVerifySignature(publicKey); + public static boolean isValidSign(byte[] bytes, byte[] sign, ECPublicKey publicKey) throws SignatureException { + Signature signature = newECVerifySignature(publicKey); try { signature.update(bytes); } catch (SignatureException e) { @@ -172,33 +161,18 @@ public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey public } - public static boolean isValidSign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - Signature signature = newRSAVerifySignature(publicKey); + public static boolean isValidSign(InputStream input, byte[] sign, ECPublicKey publicKey) throws IOException, SignatureException { + Signature signature = newECVerifySignature(publicKey); updateSignature(input, signature); return signature.verify(sign); } - public static boolean isValidSign(Path path, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - try (InputStream input = IOHelper.newInput(path)) { - return isValidSign(input, sign, publicKey); - } - } - - - public static boolean isValidSign(URL url, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { - try (InputStream input = IOHelper.newInput(url)) { - return isValidSign(input, sign, publicKey); - } - } - - public static boolean isValidToken(CharSequence token) { return token.length() == TOKEN_STRING_LENGTH && token.chars().allMatch(ch -> HEX.indexOf(ch) >= 0); } private static Cipher newCipher(String algo) { - // IDK Why, but collapsing catch blocks makes ProGuard generate invalid stackmap try { return Cipher.getInstance(algo); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { @@ -206,6 +180,19 @@ private static Cipher newCipher(String algo) { } } + /** + * @param algo Cipher algo + * @return Cipher instance + * @throws SecurityException: JCE cannot authenticate the provider BC if BouncyCastle is in unsigned jar + */ + private static Cipher newBCCipher(String algo) { + try { + return Cipher.getInstance(algo, new BouncyCastleProvider()); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new InternalError(e); + } + } + public static MessageDigest newDigest(DigestAlgorithm algo) { VerifyHelper.verify(algo, a -> a != DigestAlgorithm.PLAIN, "PLAIN digest"); @@ -221,8 +208,8 @@ public static SecureRandom newRandom() { return new SecureRandom(); } - private static Cipher newRSACipher(int mode, RSAKey key) { - Cipher cipher = newCipher(RSA_CIPHER_ALGO); + private static Cipher newECCipher(int mode, ECKey key) { + Cipher cipher = newBCCipher(EC_CIPHER_ALGO); try { cipher.init(mode, (Key) key); } catch (InvalidKeyException e) { @@ -231,35 +218,24 @@ private static Cipher newRSACipher(int mode, RSAKey key) { return cipher; } - @LauncherAPI - public static Cipher newRSADecryptCipher(RSAPrivateKey key) { - return newRSACipher(Cipher.DECRYPT_MODE, key); - } - - @LauncherAPI - public static Cipher newRSAEncryptCipher(RSAPublicKey key) { - return newRSACipher(Cipher.ENCRYPT_MODE, key); - } - - private static KeyFactory newRSAKeyFactory() { + private static KeyFactory newECKeyFactory() { try { - return KeyFactory.getInstance(RSA_ALGO); + return KeyFactory.getInstance(EC_ALGO); } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } - private static Signature newRSASignature() { + private static Signature newECSignature() { try { - return Signature.getInstance(RSA_SIGN_ALGO); + return Signature.getInstance(EC_SIGN_ALGO); } catch (NoSuchAlgorithmException e) { throw new InternalError(e); } } - - public static Signature newRSASignSignature(RSAPrivateKey key) { - Signature signature = newRSASignature(); + public static Signature newECSignSignature(ECPrivateKey key) { + Signature signature = newECSignature(); try { signature.initSign(key); } catch (InvalidKeyException e) { @@ -269,8 +245,8 @@ public static Signature newRSASignSignature(RSAPrivateKey key) { } - public static Signature newRSAVerifySignature(RSAPublicKey key) { - Signature signature = newRSASignature(); + public static Signature newECVerifySignature(ECPublicKey key) { + Signature signature = newECSignature(); try { signature.initVerify(key); } catch (InvalidKeyException e) { @@ -394,9 +370,8 @@ public static String randomUsername(Random random) { return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix); } - - public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { - Signature signature = newRSASignSignature(privateKey); + public static byte[] sign(byte[] bytes, ECPrivateKey privateKey) { + Signature signature = newECSignSignature(privateKey); try { signature.update(bytes); return signature.sign(); @@ -405,23 +380,6 @@ public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { } } - public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IOException { - Signature signature = newRSASignSignature(privateKey); - updateSignature(input, signature); - try { - return signature.sign(); - } catch (SignatureException e) { - throw new InternalError(e); - } - } - - - public static byte[] sign(Path path, RSAPrivateKey privateKey) throws IOException { - try (InputStream input = IOHelper.newInput(path)) { - return sign(input, privateKey); - } - } - public static String toHex(byte[] bytes) { int offset = 0; @@ -436,13 +394,12 @@ public static String toHex(byte[] bytes) { return new String(hex); } - - public static RSAPrivateKey toPrivateRSAKey(byte[] bytes) throws InvalidKeySpecException { - return (RSAPrivateKey) newRSAKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); + public static ECPublicKey toPublicECKey(byte[] bytes) throws InvalidKeySpecException { + return (ECPublicKey) newECKeyFactory().generatePublic(new X509EncodedKeySpec(bytes)); } - public static RSAPublicKey toPublicRSAKey(byte[] bytes) throws InvalidKeySpecException { - return (RSAPublicKey) newRSAKeyFactory().generatePublic(new X509EncodedKeySpec(bytes)); + public static ECPrivateKey toPrivateECKey(byte[] bytes) throws InvalidKeySpecException { + return (ECPrivateKey) newECKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); } private static void updateSignature(InputStream input, Signature signature) throws IOException { @@ -456,34 +413,41 @@ private static void updateSignature(InputStream input, Signature signature) thro } - public static void verifySign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { + public static void verifySign(byte[] bytes, byte[] sign, ECPublicKey publicKey) throws SignatureException { if (!isValidSign(bytes, sign, publicKey)) throw new SignatureException("Invalid sign"); } - public static void verifySign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { + public static void verifySign(InputStream input, byte[] sign, ECPublicKey publicKey) throws SignatureException, IOException { if (!isValidSign(input, sign, publicKey)) throw new SignatureException("Invalid stream sign"); } - public static void verifySign(Path path, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { - if (!isValidSign(path, sign, publicKey)) - throw new SignatureException(String.format("Invalid file sign: '%s'", path)); - } - - - public static void verifySign(URL url, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { - if (!isValidSign(url, sign, publicKey)) - throw new SignatureException(String.format("Invalid URL sign: '%s'", url)); - } - - public static String verifyToken(String token) { return VerifyHelper.verify(token, SecurityHelper::isValidToken, String.format("Invalid token: '%s'", token)); } + public static Cipher newECDecryptCipher(ECPrivateKey privateKey) + { + try { + return newECCipher(Cipher.DECRYPT_MODE, privateKey); + } catch (SecurityException e) + { + throw new InternalError(e); + } + } + public static Cipher newECEncryptCipher(ECPublicKey publicKey) + { + try { + return newECCipher(Cipher.ENCRYPT_MODE, publicKey); + } catch (SecurityException e) + { + throw new InternalError(e); + } + } + private SecurityHelper() { } @@ -521,6 +485,9 @@ public static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { cipher.init(Cipher.DECRYPT_MODE, sKeySpec); return cipher.doFinal(encrypted); } + public static byte[] decrypt(String seed, byte[] encrypted) throws Exception { + return decrypt( getRawKey(seed.getBytes()), encrypted); + } public static byte[] HexToByte(String hexString) { int len = hexString.length() / 2; diff --git a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java index 3949e2ad..42602a1f 100644 --- a/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/pro/gravit/launcher/server/ServerWrapper.java @@ -52,7 +52,7 @@ public ServerWrapper(Type type, Path configPath) { public boolean auth() { try { LauncherConfig cfg = Launcher.getConfig(); - AuthRequest request = new AuthRequest(config.login, SecurityHelper.newRSAEncryptCipher(cfg.publicKey).doFinal(IOHelper.encode(config.password)), config.auth_id, AuthRequest.ConnectTypes.SERVER); + AuthRequest request = new AuthRequest(config.login, SecurityHelper.newECEncryptCipher(cfg.publicKey).doFinal(IOHelper.encode(config.password)), config.auth_id, AuthRequest.ConnectTypes.SERVER); permissions = request.request().permissions; ProfilesRequestEvent result = new ProfilesRequest().request(); for (ClientProfile p : result.profiles) { @@ -190,7 +190,7 @@ public void updateLauncherConfig() { LauncherConfig cfg = null; try { - cfg = new LauncherConfig(config.address, SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)), new HashMap<>(), config.projectname); + cfg = new LauncherConfig(config.address, SecurityHelper.toPublicECKey(IOHelper.read(publicKeyFile)), new HashMap<>(), config.projectname); cfg.isNettyEnabled = true; cfg.address = config.address; } catch (InvalidKeySpecException | IOException e) {