Большинство аннтоаций LauncherAPI удалены из SecurityHelper

This commit is contained in:
Gravit 2018-10-25 15:43:42 +07:00
parent 5155bf292a
commit d6f203d9bf
No known key found for this signature in database
GPG key ID: 061981E1E85D3216
4 changed files with 70 additions and 69 deletions

View file

@ -50,23 +50,6 @@ var processing = {
} }
}; };
function offlineLauncherRequest() {
if (settings.lastSign === null || settings.lastProfiles.isEmpty()) {
Request.requestError("Запуск в оффлайн-режиме невозможен");
return;
}
// Verify launcher signature
SecurityHelper.verifySign(LauncherRequest.BINARY_PATH,
settings.lastSign, Launcher.getConfig().publicKey);
// Return last sign and profiles
return {
sign: settings.lastSign,
profiles: settings.lastProfiles
};
}
function offlineAuthRequest(login) { function offlineAuthRequest(login) {
return function() { return function() {
if (!VerifyHelper.isValidUsername(login)) { if (!VerifyHelper.isValidUsername(login)) {
@ -84,7 +67,7 @@ function offlineAuthRequest(login) {
/* Export functions */ /* Export functions */
function makeLauncherRequest(callback) { function makeLauncherRequest(callback) {
var task = settings.offline ? newTask(offlineLauncherRequest) : var task = settings.offline ? newTask(FunctionalBridge.offlineLauncherRequest) :
newRequestTask(new LauncherRequest()); newRequestTask(new LauncherRequest());
// Set task properties and start // Set task properties and start

View file

@ -1,14 +1,22 @@
package ru.gravit.launcher.client; package ru.gravit.launcher.client;
import ru.gravit.launcher.Launcher;
import ru.gravit.launcher.LauncherAPI; import ru.gravit.launcher.LauncherAPI;
import ru.gravit.launcher.hasher.FileNameMatcher; import ru.gravit.launcher.hasher.FileNameMatcher;
import ru.gravit.launcher.hasher.HashedDir; import ru.gravit.launcher.hasher.HashedDir;
import ru.gravit.launcher.request.Request; import ru.gravit.launcher.request.Request;
import ru.gravit.launcher.request.RequestException;
import ru.gravit.launcher.request.update.LauncherRequest;
import ru.gravit.launcher.serialize.signed.SignedObjectHolder; import ru.gravit.launcher.serialize.signed.SignedObjectHolder;
import ru.gravit.utils.helper.SecurityHelper;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.SignatureException;
public class FunctionalBridge { public class FunctionalBridge {
@LauncherAPI
public static LauncherSettings settings;
@LauncherAPI @LauncherAPI
public HashedDirRunnable offlineUpdateRequest(String dirName, Path dir, SignedObjectHolder<HashedDir> hdir, FileNameMatcher matcher, boolean digest) throws Exception public HashedDirRunnable offlineUpdateRequest(String dirName, Path dir, SignedObjectHolder<HashedDir> hdir, FileNameMatcher matcher, boolean digest) throws Exception
{ {
@ -21,6 +29,19 @@ public HashedDirRunnable offlineUpdateRequest(String dirName, Path dir, SignedOb
return hdir; return hdir;
}; };
} }
@LauncherAPI
public LauncherRequest.Result offlineLauncherRequest() throws IOException, SignatureException {
if (settings.lastSign == null || settings.lastProfiles.isEmpty()) {
Request.requestError("Запуск в оффлайн-режиме невозможен");
}
// Verify launcher signature
SecurityHelper.verifySign(LauncherRequest.BINARY_PATH,
settings.lastSign, Launcher.getConfig().publicKey);
// Return last sign and profiles
return new LauncherRequest.Result(null,settings.lastSign,settings.lastProfiles);
}
@FunctionalInterface @FunctionalInterface
public interface HashedDirRunnable { public interface HashedDirRunnable {
SignedObjectHolder<HashedDir> run() throws Exception; SignedObjectHolder<HashedDir> run() throws Exception;

View file

@ -30,7 +30,7 @@ public static final class Result {
private final byte[] binary; private final byte[] binary;
private final byte[] sign; private final byte[] sign;
private Result(byte[] binary, byte[] sign, List<SignedObjectHolder<ClientProfile>> profiles) { public Result(byte[] binary, byte[] sign, List<SignedObjectHolder<ClientProfile>> profiles) {
this.binary = binary == null ? null : binary.clone(); this.binary = binary == null ? null : binary.clone();
this.sign = sign.clone(); this.sign = sign.clone();
this.profiles = Collections.unmodifiableList(profiles); this.profiles = Collections.unmodifiableList(profiles);

View file

@ -1,6 +1,5 @@
package ru.gravit.utils.helper; package ru.gravit.utils.helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@ -34,7 +33,7 @@
import ru.gravit.launcher.LauncherAPI; import ru.gravit.launcher.LauncherAPI;
public final class SecurityHelper { public final class SecurityHelper {
@LauncherAPI
public enum DigestAlgorithm { public enum DigestAlgorithm {
PLAIN("plain", -1), MD5("MD5", 128), SHA1("SHA-1", 160), SHA224("SHA-224", 224), SHA256("SHA-256", 256), SHA512("SHA-512", 512); PLAIN("plain", -1), MD5("MD5", 128), SHA1("SHA-1", 160), SHA224("SHA-224", 224), SHA256("SHA-256", 256), SHA512("SHA-512", 512);
private static final Map<String, DigestAlgorithm> ALGORITHMS; private static final Map<String, DigestAlgorithm> ALGORITHMS;
@ -79,45 +78,45 @@ public byte[] verify(byte[] digest) {
} }
// Algorithm constants // Algorithm constants
@LauncherAPI
public static final String RSA_ALGO = "RSA"; public static final String RSA_ALGO = "RSA";
@LauncherAPI
public static final String RSA_SIGN_ALGO = "SHA256withRSA"; public static final String RSA_SIGN_ALGO = "SHA256withRSA";
@LauncherAPI
public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding"; public static final String RSA_CIPHER_ALGO = "RSA/ECB/PKCS1Padding";
// Algorithm size constants // Algorithm size constants
@LauncherAPI
public static final int TOKEN_LENGTH = 16; public static final int TOKEN_LENGTH = 16;
@LauncherAPI
public static final int AES_KEY_LENGTH = 8; public static final int AES_KEY_LENGTH = 8;
@LauncherAPI
public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1; public static final int TOKEN_STRING_LENGTH = TOKEN_LENGTH << 1;
@LauncherAPI
public static final int RSA_KEY_LENGTH_BITS = 2048; public static final int RSA_KEY_LENGTH_BITS = 2048;
@LauncherAPI
public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE; public static final int RSA_KEY_LENGTH = RSA_KEY_LENGTH_BITS / Byte.SIZE;
@LauncherAPI
public static final int CRYPTO_MAX_LENGTH = 2048; public static final int CRYPTO_MAX_LENGTH = 2048;
// Certificate constants // Certificate constants
@LauncherAPI
public static final String HEX = "0123456789abcdef"; public static final String HEX = "0123456789abcdef";
public static final byte[] NUMBERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; public static final byte[] NUMBERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
@LauncherAPI
public static final SecureRandom secureRandom = new SecureRandom(); public static final SecureRandom secureRandom = new SecureRandom();
// Random generator constants // Random generator constants
private static final char[] VOWELS = {'e', 'u', 'i', 'o', 'a'}; private static final char[] VOWELS = {'e', 'u', 'i', 'o', 'a'};
private static final char[] CONS = {'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm'}; private static final char[] CONS = {'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'k', 'l', 'c', 'v', 'b', 'n', 'm'};
@LauncherAPI
public static byte[] digest(DigestAlgorithm algo, byte[] bytes) { public static byte[] digest(DigestAlgorithm algo, byte[] bytes) {
return newDigest(algo).digest(bytes); return newDigest(algo).digest(bytes);
} }
@LauncherAPI
public static byte[] digest(DigestAlgorithm algo, InputStream input) throws IOException { public static byte[] digest(DigestAlgorithm algo, InputStream input) throws IOException {
byte[] buffer = IOHelper.newBuffer(); byte[] buffer = IOHelper.newBuffer();
MessageDigest digest = newDigest(algo); MessageDigest digest = newDigest(algo);
@ -126,31 +125,31 @@ public static byte[] digest(DigestAlgorithm algo, InputStream input) throws IOEx
return digest.digest(); return digest.digest();
} }
@LauncherAPI
public static byte[] digest(DigestAlgorithm algo, Path file) throws IOException { public static byte[] digest(DigestAlgorithm algo, Path file) throws IOException {
try (InputStream input = IOHelper.newInput(file)) { try (InputStream input = IOHelper.newInput(file)) {
return digest(algo, input); return digest(algo, input);
} }
} }
@LauncherAPI
public static byte[] digest(DigestAlgorithm algo, String s) { public static byte[] digest(DigestAlgorithm algo, String s) {
return digest(algo, IOHelper.encode(s)); return digest(algo, IOHelper.encode(s));
} }
@LauncherAPI
public static byte[] digest(DigestAlgorithm algo, URL url) throws IOException { public static byte[] digest(DigestAlgorithm algo, URL url) throws IOException {
try (InputStream input = IOHelper.newInput(url)) { try (InputStream input = IOHelper.newInput(url)) {
return digest(algo, input); return digest(algo, input);
} }
} }
@LauncherAPI
public static KeyPair genRSAKeyPair() { public static KeyPair genRSAKeyPair() {
return genRSAKeyPair(newRandom()); return genRSAKeyPair(newRandom());
} }
@LauncherAPI
public static KeyPair genRSAKeyPair(SecureRandom random) { public static KeyPair genRSAKeyPair(SecureRandom random) {
try { try {
KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGO); KeyPairGenerator generator = KeyPairGenerator.getInstance(RSA_ALGO);
@ -161,7 +160,7 @@ public static KeyPair genRSAKeyPair(SecureRandom random) {
} }
} }
@LauncherAPI
public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException {
Signature signature = newRSAVerifySignature(publicKey); Signature signature = newRSAVerifySignature(publicKey);
try { try {
@ -172,28 +171,28 @@ public static boolean isValidSign(byte[] bytes, byte[] sign, RSAPublicKey public
return signature.verify(sign); return signature.verify(sign);
} }
@LauncherAPI
public static boolean isValidSign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { public static boolean isValidSign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException {
Signature signature = newRSAVerifySignature(publicKey); Signature signature = newRSAVerifySignature(publicKey);
updateSignature(input, signature); updateSignature(input, signature);
return signature.verify(sign); return signature.verify(sign);
} }
@LauncherAPI
public static boolean isValidSign(Path path, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { public static boolean isValidSign(Path path, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException {
try (InputStream input = IOHelper.newInput(path)) { try (InputStream input = IOHelper.newInput(path)) {
return isValidSign(input, sign, publicKey); return isValidSign(input, sign, publicKey);
} }
} }
@LauncherAPI
public static boolean isValidSign(URL url, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException { public static boolean isValidSign(URL url, byte[] sign, RSAPublicKey publicKey) throws IOException, SignatureException {
try (InputStream input = IOHelper.newInput(url)) { try (InputStream input = IOHelper.newInput(url)) {
return isValidSign(input, sign, publicKey); return isValidSign(input, sign, publicKey);
} }
} }
@LauncherAPI
public static boolean isValidToken(CharSequence token) { public static boolean isValidToken(CharSequence token) {
return token.length() == TOKEN_STRING_LENGTH && token.chars().allMatch(ch -> HEX.indexOf(ch) >= 0); return token.length() == TOKEN_STRING_LENGTH && token.chars().allMatch(ch -> HEX.indexOf(ch) >= 0);
} }
@ -207,7 +206,7 @@ private static Cipher newCipher(String algo) {
} }
} }
@LauncherAPI
public static MessageDigest newDigest(DigestAlgorithm algo) { public static MessageDigest newDigest(DigestAlgorithm algo) {
VerifyHelper.verify(algo, a -> a != DigestAlgorithm.PLAIN, "PLAIN digest"); VerifyHelper.verify(algo, a -> a != DigestAlgorithm.PLAIN, "PLAIN digest");
try { try {
@ -217,7 +216,7 @@ public static MessageDigest newDigest(DigestAlgorithm algo) {
} }
} }
@LauncherAPI
public static SecureRandom newRandom() { public static SecureRandom newRandom() {
return new SecureRandom(); return new SecureRandom();
} }
@ -258,7 +257,7 @@ private static Signature newRSASignature() {
} }
} }
@LauncherAPI
public static Signature newRSASignSignature(RSAPrivateKey key) { public static Signature newRSASignSignature(RSAPrivateKey key) {
Signature signature = newRSASignature(); Signature signature = newRSASignature();
try { try {
@ -269,7 +268,7 @@ public static Signature newRSASignSignature(RSAPrivateKey key) {
return signature; return signature;
} }
@LauncherAPI
public static Signature newRSAVerifySignature(RSAPublicKey key) { public static Signature newRSAVerifySignature(RSAPublicKey key) {
Signature signature = newRSASignature(); Signature signature = newRSASignature();
try { try {
@ -280,12 +279,12 @@ public static Signature newRSAVerifySignature(RSAPublicKey key) {
return signature; return signature;
} }
@LauncherAPI
public static byte[] randomBytes(int length) { public static byte[] randomBytes(int length) {
return randomBytes(newRandom(), length); return randomBytes(newRandom(), length);
} }
@LauncherAPI
public static byte[] randomBytes(Random random, int length) { public static byte[] randomBytes(Random random, int length) {
byte[] bytes = new byte[length]; byte[] bytes = new byte[length];
random.nextBytes(bytes); random.nextBytes(bytes);
@ -302,41 +301,41 @@ public static String randomStringToken(Random random) {
return toHex(randomToken(random)); return toHex(randomToken(random));
} }
@LauncherAPI
public static byte[] randomToken() { public static byte[] randomToken() {
return randomToken(newRandom()); return randomToken(newRandom());
} }
@LauncherAPI
public static byte[] randomToken(Random random) { public static byte[] randomToken(Random random) {
return randomBytes(random, TOKEN_LENGTH); return randomBytes(random, TOKEN_LENGTH);
} }
@LauncherAPI
public static String randomStringAESKey() { public static String randomStringAESKey() {
return toHex(randomAESKey(newRandom())); return toHex(randomAESKey(newRandom()));
} }
@LauncherAPI
public static String randomStringAESKey(Random random) { public static String randomStringAESKey(Random random) {
return toHex(randomAESKey(random)); return toHex(randomAESKey(random));
} }
@LauncherAPI
public static byte[] randomAESKey() { public static byte[] randomAESKey() {
return randomAESKey(newRandom()); return randomAESKey(newRandom());
} }
@LauncherAPI
public static byte[] randomAESKey(Random random) { public static byte[] randomAESKey(Random random) {
return randomBytes(random, AES_KEY_LENGTH); return randomBytes(random, AES_KEY_LENGTH);
} }
@LauncherAPI
public static String randomUsername() { public static String randomUsername() {
return randomUsername(newRandom()); return randomUsername(newRandom());
} }
@LauncherAPI
public static String randomUsername(Random random) { public static String randomUsername(Random random) {
int usernameLength = 3 + random.nextInt(7); // 3-9 int usernameLength = 3 + random.nextInt(7); // 3-9
@ -395,7 +394,7 @@ public static String randomUsername(Random random) {
return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix); return VerifyHelper.verifyUsername(prefix + new String(chars) + suffix);
} }
@LauncherAPI
public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) { public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) {
Signature signature = newRSASignSignature(privateKey); Signature signature = newRSASignSignature(privateKey);
try { try {
@ -406,7 +405,6 @@ public static byte[] sign(byte[] bytes, RSAPrivateKey privateKey) {
} }
} }
@LauncherAPI
public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IOException { public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IOException {
Signature signature = newRSASignSignature(privateKey); Signature signature = newRSASignSignature(privateKey);
updateSignature(input, signature); updateSignature(input, signature);
@ -417,14 +415,14 @@ public static byte[] sign(InputStream input, RSAPrivateKey privateKey) throws IO
} }
} }
@LauncherAPI
public static byte[] sign(Path path, RSAPrivateKey privateKey) throws IOException { public static byte[] sign(Path path, RSAPrivateKey privateKey) throws IOException {
try (InputStream input = IOHelper.newInput(path)) { try (InputStream input = IOHelper.newInput(path)) {
return sign(input, privateKey); return sign(input, privateKey);
} }
} }
@LauncherAPI
public static String toHex(byte[] bytes) { public static String toHex(byte[] bytes) {
int offset = 0; int offset = 0;
char[] hex = new char[bytes.length << 1]; char[] hex = new char[bytes.length << 1];
@ -438,12 +436,11 @@ public static String toHex(byte[] bytes) {
return new String(hex); return new String(hex);
} }
@LauncherAPI
public static RSAPrivateKey toPrivateRSAKey(byte[] bytes) throws InvalidKeySpecException { public static RSAPrivateKey toPrivateRSAKey(byte[] bytes) throws InvalidKeySpecException {
return (RSAPrivateKey) newRSAKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); return (RSAPrivateKey) newRSAKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes));
} }
@LauncherAPI
public static RSAPublicKey toPublicRSAKey(byte[] bytes) throws InvalidKeySpecException { public static RSAPublicKey toPublicRSAKey(byte[] bytes) throws InvalidKeySpecException {
return (RSAPublicKey) newRSAKeyFactory().generatePublic(new X509EncodedKeySpec(bytes)); return (RSAPublicKey) newRSAKeyFactory().generatePublic(new X509EncodedKeySpec(bytes));
} }
@ -458,31 +455,31 @@ private static void updateSignature(InputStream input, Signature signature) thro
} }
} }
@LauncherAPI
public static void verifySign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException { public static void verifySign(byte[] bytes, byte[] sign, RSAPublicKey publicKey) throws SignatureException {
if (!isValidSign(bytes, sign, publicKey)) if (!isValidSign(bytes, sign, publicKey))
throw new SignatureException("Invalid sign"); throw new SignatureException("Invalid sign");
} }
@LauncherAPI
public static void verifySign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { public static void verifySign(InputStream input, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException {
if (!isValidSign(input, sign, publicKey)) if (!isValidSign(input, sign, publicKey))
throw new SignatureException("Invalid stream sign"); throw new SignatureException("Invalid stream sign");
} }
@LauncherAPI
public static void verifySign(Path path, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { public static void verifySign(Path path, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException {
if (!isValidSign(path, sign, publicKey)) if (!isValidSign(path, sign, publicKey))
throw new SignatureException(String.format("Invalid file sign: '%s'", path)); throw new SignatureException(String.format("Invalid file sign: '%s'", path));
} }
@LauncherAPI
public static void verifySign(URL url, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException { public static void verifySign(URL url, byte[] sign, RSAPublicKey publicKey) throws SignatureException, IOException {
if (!isValidSign(url, sign, publicKey)) if (!isValidSign(url, sign, publicKey))
throw new SignatureException(String.format("Invalid URL sign: '%s'", url)); throw new SignatureException(String.format("Invalid URL sign: '%s'", url));
} }
@LauncherAPI
public static String verifyToken(String token) { public static String verifyToken(String token) {
return VerifyHelper.verify(token, SecurityHelper::isValidToken, String.format("Invalid token: '%s'", token)); return VerifyHelper.verify(token, SecurityHelper::isValidToken, String.format("Invalid token: '%s'", token));
} }