mirror of
https://github.com/DieReicheErethons/Brewery.git
synced 2024-11-26 12:15:19 +01:00
Added XOR Scrambler for Brew data
Very fast obfuscator for brew data so that a client cant easily read it
This commit is contained in:
parent
cdb36b1736
commit
9bf3268fb4
@ -1,10 +1,7 @@
|
||||
package com.dre.brewery;
|
||||
|
||||
import org.bukkit.Color;
|
||||
import com.dre.brewery.lore.Base91DecoderStream;
|
||||
import com.dre.brewery.lore.Base91EncoderStream;
|
||||
import com.dre.brewery.lore.LoreLoadStream;
|
||||
import com.dre.brewery.lore.LoreSaveStream;
|
||||
import com.dre.brewery.lore.*;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.BrewerInventory;
|
||||
@ -20,6 +17,7 @@ import org.bukkit.potion.PotionType;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -28,7 +26,7 @@ import java.util.Map;
|
||||
public class Brew {
|
||||
|
||||
// represents the liquid in the brewed Potions
|
||||
|
||||
private static long saveSeed;
|
||||
public static Map<Integer, Brew> legacyPotions = new HashMap<>();
|
||||
public static long installTime = System.currentTimeMillis(); // plugin install time in millis after epoch
|
||||
public static Boolean colorInBarrels; // color the Lore while in Barrels
|
||||
@ -732,18 +730,26 @@ public class Brew {
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
return null;
|
||||
}
|
||||
try (DataInputStream in = new DataInputStream(new Base91DecoderStream(loreStream))) {
|
||||
XORUnscrambleStream unscrambler = new XORUnscrambleStream(new Base91DecoderStream(loreStream), saveSeed);
|
||||
try (DataInputStream in = new DataInputStream(unscrambler)) {
|
||||
boolean parityFailed = false;
|
||||
if (in.readByte() != 86) {
|
||||
P.p.errorLog("parity check failed on Brew while loading, trying to load anyways!");
|
||||
P.p.errorLog("Parity check failed on Brew while loading, trying to load anyways!");
|
||||
parityFailed = true;
|
||||
}
|
||||
Brew brew = new Brew();
|
||||
byte ver = in.readByte();
|
||||
switch (ver) {
|
||||
case 1:
|
||||
unscrambler.start();
|
||||
brew.loadFromStream(in);
|
||||
break;
|
||||
default:
|
||||
P.p.errorLog("Brew has data stored in v" + ver + " this version supports up to v1");
|
||||
if (parityFailed) {
|
||||
P.p.errorLog("Failed to load Brew. Maybe something corrupted the Lore of the Item?");
|
||||
} else {
|
||||
P.p.errorLog("Brew has data stored in v" + ver + " this Plugin version supports up to v1");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return brew;
|
||||
@ -779,7 +785,11 @@ public class Brew {
|
||||
|
||||
// Save brew data into meta/lore
|
||||
public void save(ItemMeta meta) {
|
||||
try (DataOutputStream out = new DataOutputStream(new Base91EncoderStream(new LoreSaveStream(meta, 0)))) {
|
||||
XORScrambleStream scrambler = new XORScrambleStream(new Base91EncoderStream(new LoreSaveStream(meta, 0)), saveSeed);
|
||||
try (DataOutputStream out = new DataOutputStream(scrambler)) {
|
||||
out.writeByte(86); // Parity/sanity
|
||||
out.writeByte(1); // Version
|
||||
scrambler.start();
|
||||
saveToStream(out);
|
||||
} catch (IOException e) {
|
||||
P.p.errorLog("IO Error while saving Brew");
|
||||
@ -801,8 +811,6 @@ public class Brew {
|
||||
}
|
||||
|
||||
public void saveToStream(DataOutputStream out) throws IOException {
|
||||
out.writeByte(86); // Parity/sanity
|
||||
out.writeByte(1); // Version
|
||||
if (quality > 10) {
|
||||
quality = 10;
|
||||
}
|
||||
@ -831,6 +839,20 @@ public class Brew {
|
||||
ingredients.save(out);
|
||||
}
|
||||
|
||||
public static void writeSeed(ConfigurationSection section) {
|
||||
section.set("seed", saveSeed);
|
||||
}
|
||||
|
||||
public static void loadSeed(ConfigurationSection section) {
|
||||
if (section.contains("seed")) {
|
||||
saveSeed = section.getLong("seed");
|
||||
} else {
|
||||
while (saveSeed == 0) {
|
||||
saveSeed = new SecureRandom().nextLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load potion data from data file for backwards compatibility
|
||||
public static void loadLegacy(BIngredients ingredients, int uid, int quality, byte distillRuns, float ageTime, float wood, String recipe, boolean unlabeled, boolean persistent, boolean stat) {
|
||||
Brew brew = new Brew(ingredients, quality, distillRuns, ageTime, wood, recipe, unlabeled, stat);
|
||||
|
@ -86,6 +86,136 @@ public class P extends JavaPlugin {
|
||||
|
||||
//P.p.log("§" + (use1_9 ? "a":"c") + "1.9 " + "§" + (use1_11 ? "a":"c") + "1.11 " + "§" + (use1_13 ? "a":"c") + "1.13 " + "§" + (use1_14 ? "a":"c") + "1.14");
|
||||
|
||||
/*long master = new SecureRandom().nextLong();
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
XORScrambleStream scramble = new XORScrambleStream(new Base91EncoderStream(byteStream), master);
|
||||
DataOutputStream data = new DataOutputStream(scramble);
|
||||
DataInputStream dataIn = null;
|
||||
try {
|
||||
scramble.start();
|
||||
data.writeLong(12345L);
|
||||
scramble.stop();
|
||||
data.writeInt(1);
|
||||
data.writeInt(1);
|
||||
scramble.start();
|
||||
data.writeDouble(0.55555D);
|
||||
data.writeInt(234323);
|
||||
//data.writeUTF("Hallo Peter");
|
||||
data.writeLong(5419L); // Skip
|
||||
data.writeDouble(0.55555D);
|
||||
|
||||
data.close();
|
||||
|
||||
XORUnscrambleStream unscramble = new XORUnscrambleStream(new Base91DecoderStream(new ByteArrayInputStream(byteStream.toByteArray())), master);
|
||||
dataIn = new DataInputStream(unscramble);
|
||||
unscramble.start();
|
||||
P.p.log(dataIn.readLong() + "");
|
||||
unscramble.stop();
|
||||
P.p.log(dataIn.readInt() + "");
|
||||
P.p.log(dataIn.readInt() + "");
|
||||
unscramble.start();
|
||||
P.p.log(dataIn.readDouble() + "");
|
||||
dataIn.mark(1000);
|
||||
P.p.log(dataIn.readInt() + "");
|
||||
//P.p.log(dataIn.readUTF());
|
||||
dataIn.skip(8);
|
||||
P.p.log(dataIn.readDouble() + "");
|
||||
P.p.log("reset");
|
||||
dataIn.reset();
|
||||
P.p.log(dataIn.readInt() + "");
|
||||
//P.p.log(dataIn.readUTF());
|
||||
dataIn.skip(8);
|
||||
P.p.log(dataIn.readDouble() + "");
|
||||
|
||||
dataIn.close();
|
||||
|
||||
*//*for (int i = 0; i < 10; i++) {
|
||||
byteStream = new ByteArrayOutputStream();
|
||||
scramble = new XORScrambleStream(new Base91EncoderStream(byteStream));
|
||||
data = new DataOutputStream(scramble);
|
||||
data.writeInt(i);
|
||||
scramble.start();
|
||||
data.writeLong(12345L);
|
||||
data.writeLong(12345L);
|
||||
scramble.stop();
|
||||
data.writeInt(1);
|
||||
data.writeInt(1);
|
||||
scramble.start();
|
||||
data.writeInt(234323);
|
||||
data.writeDouble(0.55555D);
|
||||
|
||||
P.p.log(byteStream.toString());
|
||||
data.close();
|
||||
}*//*
|
||||
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
unscramble = new XORUnscrambleStream(new Base91DecoderStream(new ByteArrayInputStream(byteStream.toByteArray())), master);
|
||||
dataIn = new DataInputStream(unscramble);
|
||||
unscramble.start();
|
||||
dataIn.readLong();
|
||||
unscramble.stop();
|
||||
dataIn.readInt();
|
||||
dataIn.readInt();
|
||||
unscramble.start();
|
||||
dataIn.readDouble();
|
||||
dataIn.mark(1000);
|
||||
dataIn.readInt();
|
||||
//dataIn.readUTF();
|
||||
dataIn.skip(8);
|
||||
dataIn.readDouble();
|
||||
dataIn.reset();
|
||||
dataIn.readInt();
|
||||
//dataIn.readUTF();
|
||||
dataIn.skip(8);
|
||||
dataIn.readDouble();
|
||||
|
||||
dataIn.close();
|
||||
}
|
||||
long time2 = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
unscramble = new XORUnscrambleStream(new ByteArrayInputStream(byteStream.toByteArray()), master);
|
||||
dataIn = new DataInputStream(unscramble);
|
||||
unscramble.start();
|
||||
dataIn.skip(2);
|
||||
dataIn.readLong();
|
||||
unscramble.stop();
|
||||
dataIn.readInt();
|
||||
dataIn.readInt();
|
||||
unscramble.start();
|
||||
dataIn.readDouble();
|
||||
dataIn.mark(1000);
|
||||
dataIn.readInt();
|
||||
//dataIn.readUTF();
|
||||
dataIn.skip(8);
|
||||
dataIn.readDouble();
|
||||
dataIn.reset();
|
||||
dataIn.readInt();
|
||||
//dataIn.readUTF();
|
||||
dataIn.skip(8);
|
||||
dataIn.readDouble();
|
||||
|
||||
dataIn.close();
|
||||
}
|
||||
long time3 = System.currentTimeMillis();
|
||||
|
||||
P.p.log("Time with base91: " + (time2 - time));
|
||||
P.p.log("Time without base91: " + (time3 - time2));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
data.close();
|
||||
if (dataIn != null) {
|
||||
dataIn.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*try {
|
||||
ItemMeta meta = new ItemStack(Material.POTION).getItemMeta();
|
||||
@ -577,8 +707,11 @@ public class P extends JavaPlugin {
|
||||
FileConfiguration data = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
Brew.installTime = data.getLong("installTime", System.currentTimeMillis());
|
||||
|
||||
MCBarrel.mcBarrelTime = data.getLong("MCBarrelTime", 0);
|
||||
|
||||
Brew.loadSeed(data);
|
||||
|
||||
// Check if data is the newest version
|
||||
String version = data.getString("Version", null);
|
||||
if (version != null) {
|
||||
|
@ -62,8 +62,11 @@ public class DataSave extends BukkitRunnable {
|
||||
FileConfiguration configFile = new YamlConfiguration();
|
||||
|
||||
configFile.set("installTime", Brew.installTime);
|
||||
|
||||
configFile.set("MCBarrelTime", MCBarrel.mcBarrelTime);
|
||||
|
||||
Brew.writeSeed(configFile);
|
||||
|
||||
if (!Brew.legacyPotions.isEmpty()) {
|
||||
Brew.save(configFile.createSection("Brew"));
|
||||
}
|
||||
|
94
src/com/dre/brewery/lore/SeedInputStream.java
Normal file
94
src/com/dre/brewery/lore/SeedInputStream.java
Normal file
@ -0,0 +1,94 @@
|
||||
package com.dre.brewery.lore;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SeedInputStream extends InputStream {
|
||||
// From java.util.Random
|
||||
private static final long multiplier = 0x5DEECE66DL;
|
||||
private static final long addend = 0xBL;
|
||||
private static final long mask = (1L << 48) - 1;
|
||||
|
||||
private long seed;
|
||||
private byte[] buf = new byte[4];
|
||||
private byte reader = 4;
|
||||
private long markSeed;
|
||||
private byte[] markbuf;
|
||||
|
||||
public SeedInputStream(long seed) {
|
||||
this.seed = (seed ^ multiplier) & mask;
|
||||
}
|
||||
|
||||
private void calcSeed() {
|
||||
seed = (seed * multiplier + addend) & mask;
|
||||
}
|
||||
|
||||
private void genNext() {
|
||||
calcSeed();
|
||||
int next = (int)(seed >>> 16);
|
||||
buf[0] = (byte) (next >> 24);
|
||||
buf[1] = (byte) (next >> 16);
|
||||
buf[2] = (byte) (next >> 8);
|
||||
buf[3] = (byte) next;
|
||||
reader = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) {
|
||||
for (int i = off; i < len; i++) {
|
||||
if (reader >= 4) {
|
||||
genNext();
|
||||
}
|
||||
b[i] = buf[reader++];
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (reader == 4) {
|
||||
genNext();
|
||||
}
|
||||
return buf[reader++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long toSkip) {
|
||||
long n = toSkip;
|
||||
while (n > 0) {
|
||||
if (reader < 4) {
|
||||
reader++;
|
||||
n--;
|
||||
} else if (n >= 4) {
|
||||
calcSeed();
|
||||
n -= 4;
|
||||
} else {
|
||||
genNext();
|
||||
}
|
||||
}
|
||||
return toSkip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
buf = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
markbuf = new byte[] {buf[0], buf[1], buf[2], buf[3], reader};
|
||||
markSeed = seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() {
|
||||
seed = markSeed;
|
||||
buf = Arrays.copyOfRange(markbuf, 0, 4);
|
||||
reader = markbuf[4];
|
||||
}
|
||||
}
|
67
src/com/dre/brewery/lore/XORScrambleStream.java
Normal file
67
src/com/dre/brewery/lore/XORScrambleStream.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.dre.brewery.lore;
|
||||
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
public class XORScrambleStream extends FilterOutputStream {
|
||||
|
||||
private final long seed;
|
||||
private SeedInputStream xorStream;
|
||||
private boolean running;
|
||||
|
||||
public XORScrambleStream(OutputStream out, long seed) {
|
||||
super(out);
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
running = true;
|
||||
if (xorStream == null) {
|
||||
short id = 0;
|
||||
while (id == 0) {
|
||||
id = (short) new Random().nextInt();
|
||||
}
|
||||
xorStream = new SeedInputStream(seed ^ id);
|
||||
out.write((byte) (id >> 8));
|
||||
out.write((byte) id);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (!running) {
|
||||
out.write(b);
|
||||
return;
|
||||
}
|
||||
out.write(b ^ xorStream.read());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
if (!running) {
|
||||
out.write(b, off, len);
|
||||
return;
|
||||
}
|
||||
byte[] xored = new byte[len];
|
||||
xorStream.read(xored);
|
||||
int j = off;
|
||||
for (int i = 0; i < len; i++) {
|
||||
xored[i] ^= b[j++];
|
||||
}
|
||||
out.write(xored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
running = false;
|
||||
xorStream = null;
|
||||
super.close();
|
||||
}
|
||||
}
|
100
src/com/dre/brewery/lore/XORUnscrambleStream.java
Normal file
100
src/com/dre/brewery/lore/XORUnscrambleStream.java
Normal file
@ -0,0 +1,100 @@
|
||||
package com.dre.brewery.lore;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class XORUnscrambleStream extends FilterInputStream {
|
||||
|
||||
private final long seed;
|
||||
private SeedInputStream xorStream;
|
||||
private boolean running;
|
||||
private boolean markRunning;
|
||||
private boolean markxor;
|
||||
|
||||
public XORUnscrambleStream(InputStream in, long seed) {
|
||||
super(in);
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public void start() throws IOException {
|
||||
running = true;
|
||||
if (xorStream == null) {
|
||||
short id = (short) (in.read() << 8 | in.read());
|
||||
if (id == 0) {
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
xorStream = new SeedInputStream(seed ^ id);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!running) {
|
||||
return in.read();
|
||||
}
|
||||
return (in.read() ^ xorStream.read()) & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (!running) {
|
||||
return in.read(b, off, len);
|
||||
}
|
||||
len = in.read(b, off, len);
|
||||
for (int i = off; i < len + off; i++) {
|
||||
b[i] ^= xorStream.read();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long skipped = in.skip(n);
|
||||
if (running && skipped > 0) {
|
||||
xorStream.skip(skipped);
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (xorStream != null) {
|
||||
xorStream.close();
|
||||
xorStream = null;
|
||||
}
|
||||
running = false;
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return in.markSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
in.reset();
|
||||
if (markxor) {
|
||||
xorStream.reset();
|
||||
} else {
|
||||
xorStream = null;
|
||||
}
|
||||
running = markRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
in.mark(readlimit);
|
||||
if (xorStream != null) {
|
||||
xorStream.mark(readlimit);
|
||||
markxor = true;
|
||||
}
|
||||
markRunning = running;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user