Brewery/src/com/dre/brewery/lore/XORScrambleStream.java
Sn0wStorm f431c13100 Load Scramble Seed key from Config
Remember all used Scramble seeds to unscramble potions
2019-10-18 16:30:03 +02:00

104 lines
2.9 KiB
Java

package com.dre.brewery.lore;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
/**
* A Scramble Stream that uses XOR operations to scramble an outputstream.
* a byte generator feeded with the seed is used as xor source
* The resulting data can be unscrambled by the XORUnscrambleStream
*/
public class XORScrambleStream extends FilterOutputStream {
private final long seed;
private SeedInputStream xorStream;
private boolean running;
/**
* Create a new instance of an XORScrambler, scrambling the given outputstream
*
* @param out The Outputstream to be scrambled
* @param seed The seed used for scrambling
*/
public XORScrambleStream(OutputStream out, long seed) {
super(out);
this.seed = seed;
}
/**
* To start the scrambling process this has to be called before writing any data to this stream.
* Before starting the scrambler, any data will just be passed through unscrambled to the underlying stream.
* The Scrambling can be started and stopped arbitrarily at any point, allowing for parts of unscrambled data in the stream.
*
* @throws IOException IOException
*/
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);
write((int) (seed >> 48) & 0xFF); // parity/sanity
}
}
/**
* Stop the scrambling, any following data will be passed through unscrambled.
* The scrambling can be started again at any point after calling this
*/
public void stop() {
running = false;
}
/**
* Mark the stream as unscrambled, any effort of unscrambing the data later will automatically read the already unscrambled data
* Useful if a stream may be scrambled or unscrambled, the unscrambler will automatically identify either way.
*
* @throws IOException IOException
* @throws IllegalStateException If the Scrambler was started in normal scrambling mode before
*/
public void startUnscrambled() throws IOException, IllegalStateException {
if (xorStream != null) throw new IllegalStateException("The Scrambler was started in scrambling mode before");
short id = 0;
out.write((byte) (id >> 8));
out.write((byte) id);
}
@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();
}
}