mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-22 16:41:46 +03:00
[FEATURE] переход на EC ключи. Отказ от RSA
This commit is contained in:
parent
897f799aac
commit
ce28ac4057
23 changed files with 164 additions and 167 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ public Path process(Path inputJar) throws IOException {
|
|||
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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
import java.security.*;
|
||||
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 +21,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 {
|
||||
|
||||
|
@ -36,6 +34,7 @@ public static void main(String... args) throws Throwable {
|
|||
//if(!LauncherAgent.isStarted()) throw new SecurityException("JavaAgent not set");
|
||||
LogHelper.printVersion("Launcher");
|
||||
LogHelper.printLicense("Launcher");
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherConfig.getAutogenConfig().initModules();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public void addCustomEnv(ClientLauncherContext context) {
|
|||
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_PUBLICKEY", config.publicKey.getModulus().toString(16));
|
||||
env.put("GUARD_PROJECTNAME", config.projectname);
|
||||
if (protectToken != null)
|
||||
env.put("GUARD_TOKEN", protectToken);
|
||||
|
|
|
@ -63,7 +63,7 @@ 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_PUBLICKEY", config.publicKey.getModulus().toString(16));
|
||||
env.put("GUARD_PROJECTNAME", config.projectname);
|
||||
if (protectToken != null)
|
||||
env.put("GUARD_TOKEN", protectToken);
|
||||
|
|
|
@ -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 (дебаг включен по умолчанию, все сообщения)
|
||||
|
|
|
@ -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<String, byte[]> 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<String, byte[]> runtime, String projectname) {
|
||||
public LauncherConfig(String address, ECPublicKey publicKey, Map<String, byte[]> 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<String, byte[]
|
|||
environment = LauncherEnvironment.STD;
|
||||
secureCheckSalt = null;
|
||||
secureCheckHash = null;
|
||||
passwordEncryptKey = null;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public LauncherConfig(String address, RSAPublicKey publicKey, Map<String, byte[]> runtime) {
|
||||
public LauncherConfig(String address, ECPublicKey publicKey, Map<String, byte[]> 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<String, byte[]
|
|||
environment = LauncherEnvironment.STD;
|
||||
secureCheckSalt = null;
|
||||
secureCheckHash = null;
|
||||
passwordEncryptKey = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
|||
Subproject commit 960e178bc658835dc8aff93ee51e10e52bc7afb5
|
||||
Subproject commit a770ac083f9e940122f888fa6ffd9e0485d3292b
|
Loading…
Reference in a new issue