Add runelite-proxy with some work on the login packet sequence

This commit is contained in:
Adam
2017-04-22 20:54:07 -04:00
parent 9024417b77
commit 74f23300bc
9 changed files with 848 additions and 0 deletions

View File

@@ -76,6 +76,7 @@
<module>runescape-client-injector-plugin</module>
<module>http-api</module>
<module>http-service</module>
<module>runelite-proxy</module>
</modules>
<build>

64
runelite-proxy/pom.xml Normal file
View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2017, Adam <Adam@sigterm.info>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.runelite</groupId>
<artifactId>runelite-parent</artifactId>
<version>1.1.26-SNAPSHOT</version>
</parent>
<groupId>net.runelite</groupId>
<artifactId>proxy</artifactId>
<name>Runelite Proxy</name>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IOCopy extends Thread
{
private static final Logger logger = LoggerFactory.getLogger(IOCopy.class);
private final DataInputStream in;
private final DataOutputStream out;
public IOCopy(String name, DataInputStream in, DataOutputStream out)
{
super(name);
this.in = in;
this.out = out;
}
@Override
public void run()
{
try
{
int i;
while ((i = in.read()) != -1)
{
out.write(i);
}
}
catch (IOException ex)
{
logger.error(null, ex);
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PacketCopy extends Thread
{
private static final Logger logger = LoggerFactory.getLogger(PacketCopy.class);
private final DataInputStream in;
private final DataOutputStream out;
private final RLISAACCipher inCipher;
private final RLISAACCipher outCipher;
public PacketCopy(String name, DataInputStream in, DataOutputStream out, RLISAACCipher inCipher, RLISAACCipher outCipher)
{
super(name);
this.in = in;
this.out = out;
this.inCipher = inCipher;
this.outCipher = outCipher;
}
@Override
public void run()
{
try
{
for (;;)
{
int packetOpcode = ProxyRunner.readOpcode(inCipher, in);
int packetLength = Proxy.PACKET_LENGHTS[packetOpcode];
if (packetLength == -1)
{
packetLength = in.read() & 0xff;
}
if (packetLength == -2)
{
packetLength = in.readShort() & 0xffff;
}
byte[] b = new byte[packetLength];
int read = 0;
while (read < packetLength)
{
int r = in.read(b, read, packetLength - read);
if (r <= 0)
{
throw new IOException();
}
read += r;
}
logger.info("Read packet opcode {} length {}", packetOpcode, packetLength);
// Write out
ProxyRunner.writeOpcode(outCipher, out, packetOpcode);
switch (Proxy.PACKET_LENGHTS[packetOpcode])
{
case -1:
assert packetLength >= 0 && packetLength < 256;
out.write(packetLength);
break;
case -2:
out.writeShort(packetLength);
break;
}
out.write(b);
}
}
catch (IOException ex)
{
logger.error(null, ex);
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.io.IOException;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Proxy
{
private static final Logger logger = LoggerFactory.getLogger(Proxy.class);
public static final int REVISION = 139;
// For revision 139
public static final BigInteger SERVER_RSA_KEY_MODULUS = new BigInteger("a0211b55eb8010fd56feae6b163a67945b2ffcb6b3cd976a477f2d88e4cafefebd7174268fa9708acf26dbb44a772d4781f41ecb812f9ae459cf23fd7dc76bd70ac5b9ddaee2c1f6de8f8a8a39750f5f4a5c784079d6e7ba39a8915a6336cd681f3ce8083a344072adf5eec02a7221a05b8fda1e4ff4cf117ea89d290ed6fb7d", 16);
public static final BigInteger SERVER_RSA_KEY_EXPONENT = new BigInteger("10001", 16);
public static final int[] PACKET_LENGHTS = new int[]
{
0, 0, 0, 0, 0, -1, 0, -2, 0, 5, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 4, 4, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 2, 0, 0, -2, 0, 0, 0, 6, -2, 8, 0, 0, 0, 0, -2, -1, 0, 0, -2, 6, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, -2, 0, 0, 0, 0, 2, 0, 0, 3, -2, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, -1, -2, 1, 0, 0, 0, 0, 6, 0, 0, 0, 28, 0, 6, 0, 0, 6, 0, 0, 0, 0, 3, -2, 6, 0, 0, 2, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, -2, 6, 0, -2, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, -1, 2, 4, 0, 0, 0, 2, 0, -2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 15, 0, 0, 0, -2, 0, 0, 0, 0, 0, -2, 14, 8, 20, 0, 2, 0, 0, 0, -2, 5, 4, 0, 0, 0, 10, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 8, 0, 4, 0, 1, -2, 7, 0, 12, 0, 6, 4, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0
};
public static final RSA myRsa = new RSA();
public static final RSA rsRsa = new RSA(SERVER_RSA_KEY_MODULUS, null);
public static void main(String[] args) throws IOException
{
ServerSocket socket = new ServerSocket(43594);
logger.info("Running with RSA modulus {}", myRsa.getN().toString(16));
Socket s;
while ((s = socket.accept()) != null)
{
new ProxyRunner(s).start();
}
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProxyRunner extends Thread
{
private static final Logger logger = LoggerFactory.getLogger(ProxyRunner.class);
private final Socket client;
private final Socket server;
//private RLISAACCipher clientInCipher;
private RLISAACCipher clientOutCipher;
private RLISAACCipher serverInCipher;
//private RLISAACCipher serverOutCipher;
public ProxyRunner(Socket client) throws IOException
{
this.client = client;
this.server = new Socket("localhost", 8080);
}
@Override
public void run()
{
try
{
go();
}
catch (IOException ex)
{
logger.error(null, ex);
}
}
private void go() throws IOException
{
DataInputStream in = new DataInputStream(client.getInputStream());
DataOutputStream out = new DataOutputStream(client.getOutputStream());
DataInputStream serverIn = new DataInputStream(server.getInputStream());
DataOutputStream serverOut = new DataOutputStream(server.getOutputStream());
// For the http proxy..
serverOut.write("CONNECT oldschool78.runescape.com:43594 HTTP/1.0\r\n\r\n".getBytes());
System.out.println(serverIn.readLine());
System.out.println(serverIn.readLine());
int handshakeType = in.read();
logger.info("Handshake from client: {}", handshakeType);
if (handshakeType != 14) // login?
{
return;
}
// Forward to server
serverOut.write(handshakeType);
int handshakeResponse = serverIn.read();
logger.info("Handshake response from server: {}", handshakeResponse);
// Forward to client
out.write(handshakeResponse);
byte[] b = new byte[8];
int len = serverIn.read(b);
assert len == 8;
logger.info("Nonce from server: {}", Longs.fromByteArray(b));
// Forward to client
out.write(b);
// Now the client sends the login packet, some of it is rsa encrypted with a rsa key
// that is hardcoded into the client. In this data is the xtea key which is used later
// for the isaac cipher seeding and for encrypting the rest of the packet.
int gameState = in.read(); // 18 or 16 depending on some game state
int length = in.readShort(); // length of remaining packet
int revision = in.readInt(); // client revision
logger.info("Client game state: {}, revision: {}", gameState, revision);
if (revision != Proxy.REVISION)
{
client.close();
server.close();
return;
}
int encrypedDataLength = in.readShort();
byte[] rsaData = new byte[encrypedDataLength];
len = in.read(rsaData);
assert len == encrypedDataLength;
rsaData = Proxy.myRsa.decrypt(rsaData);
// Reencrypt data
byte[] reencrypted = Proxy.rsRsa.encrypt(rsaData);
// Extract xtea key
b = rsaData;
int key1 = Ints.fromBytes(b[2], b[3], b[4], b[5]);
int key2 = Ints.fromBytes(b[6], b[7], b[8], b[9]);
int key3 = Ints.fromBytes(b[10], b[11], b[12], b[13]);
int key4 = Ints.fromBytes(b[14], b[15], b[16], b[17]);
int[] keys = new int[]
{
key1, key2, key3, key4
};
logger.info("Xtea key is {} {} {} {}", key1, key2, key3, key4);
//clientInCipher = new RLISAACCipher(keys);
clientOutCipher = new RLISAACCipher(keys);
serverInCipher = new RLISAACCipher(keys);
//serverOutCipher = new RLISAACCipher(keys);
// Following this is xtea encrypted data
int xteaDataLength = length - 4 - encrypedDataLength - 2; // total length - revision - rsa encrypted data - rsa encrypted data length
byte[] xteaData = new byte[xteaDataLength];
len = in.read(xteaData);
assert len == xteaDataLength;
ByteBuffer buffer = ByteBuffer.allocate(4096);
buffer.put((byte) gameState);
buffer.putShort((short) 0); // length
buffer.putInt(revision);
buffer.putShort((short) reencrypted.length);
buffer.put(reencrypted);
buffer.put(xteaData);
len = buffer.position();
buffer.putShort(1, (short) (len - 3));
serverOut.write(buffer.array(), 0, len);
handshakeResponse = serverIn.read();
logger.info("Handshake response: {}", handshakeResponse);
out.write(handshakeResponse);
if (handshakeResponse != 2)
{
client.close();
server.close();
return;
}
int hasPreferenceValue = serverIn.read();
logger.info("Has preference value: {}", hasPreferenceValue);
out.write(hasPreferenceValue);
assert hasPreferenceValue != 1;
int byte1 = serverIn.read();
int byte2 = serverIn.read();
int interactingIndex = serverIn.readShort() & 0xffff;
int byte3 = serverIn.read();
logger.info("B1/B2/interactingIndex/B3: {}/{}/{}/{}", byte1, byte2, interactingIndex, byte3);
out.write(byte1);
out.write(byte2);
out.writeShort(interactingIndex);
out.write(byte3);
int packetOpcode = readOpcode(serverInCipher, serverIn);
int packetLength = serverIn.readShort() & 0xffff;
logger.info("Packet opcode: {}", packetOpcode);
writeOpcode(clientOutCipher, out, packetOpcode);
out.writeShort(packetLength);
byte[] packetData = new byte[packetLength];
len = serverIn.read(packetData);
assert len == packetData.length;
out.write(packetData);
new IOCopy("Client to Server", in, serverOut).start();
new IOCopy("Server to Client", serverIn, out).start();
//new PacketCopy("Server to Client", serverIn, out, serverInCipher, clientOutCipher).start();
}
public static int readOpcode(RLISAACCipher cipher, InputStream in) throws IOException
{
return (in.read() - cipher.nextInt()) & 0xff;
}
public static void writeOpcode(RLISAACCipher cipher, OutputStream out, int opcode) throws IOException
{
byte encrytpedOpcode = (byte) (opcode + cipher.nextInt());
out.write(encrytpedOpcode & 0xff);
}
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.util.Arrays;
/**
* Based off of the implementation from
* https://rosettacode.org/wiki/The_ISAAC_Cipher#Java Modified to not extend
* java.util.Random, and return results in reverse order
*
* @author Adam
*/
public class RLISAACCipher
{
private final int[] randResult = new int[256]; // output of last generation
private int valuesLeft; // the number of values already left in randResult
// internal generator state
private final int[] mm = new int[256];
private int aa, bb, cc;
public RLISAACCipher(int[] key)
{
init(key);
}
private void generateMoreResults()
{
cc++;
bb += cc;
for (int i = 0; i < 256; i++)
{
int x = mm[i];
switch (i & 3)
{
case 0:
aa = aa ^ (aa << 13);
break;
case 1:
aa = aa ^ (aa >>> 6);
break;
case 2:
aa = aa ^ (aa << 2);
break;
case 3:
aa = aa ^ (aa >>> 16);
break;
}
aa = mm[i ^ 128] + aa;
int y = mm[i] = mm[(x >>> 2) & 0xFF] + aa + bb;
randResult[i] = bb = mm[(y >>> 10) & 0xFF] + x;
}
valuesLeft = 256;
}
private static void mix(int[] s)
{
s[0] ^= s[1] << 11;
s[3] += s[0];
s[1] += s[2];
s[1] ^= s[2] >>> 2;
s[4] += s[1];
s[2] += s[3];
s[2] ^= s[3] << 8;
s[5] += s[2];
s[3] += s[4];
s[3] ^= s[4] >>> 16;
s[6] += s[3];
s[4] += s[5];
s[4] ^= s[5] << 10;
s[7] += s[4];
s[5] += s[6];
s[5] ^= s[6] >>> 4;
s[0] += s[5];
s[6] += s[7];
s[6] ^= s[7] << 8;
s[1] += s[6];
s[7] += s[0];
s[7] ^= s[0] >>> 9;
s[2] += s[7];
s[0] += s[1];
}
private void init(int[] seed)
{
if (seed != null && seed.length != 256)
{
seed = Arrays.copyOf(seed, 256);
}
aa = bb = cc = 0;
int[] initState = new int[8];
Arrays.fill(initState, 0x9e3779b9); // the golden ratio
for (int i = 0; i < 4; i++)
{
mix(initState);
}
for (int i = 0; i < 256; i += 8)
{
if (seed != null)
{
for (int j = 0; j < 8; j++)
{
initState[j] += seed[i + j];
}
}
mix(initState);
for (int j = 0; j < 8; j++)
{
mm[i + j] = initState[j];
}
}
if (seed != null)
{
for (int i = 0; i < 256; i += 8)
{
for (int j = 0; j < 8; j++)
{
initState[j] += mm[i + j];
}
mix(initState);
for (int j = 0; j < 8; j++)
{
mm[i + j] = initState[j];
}
}
}
valuesLeft = 0; // Make sure generateMoreResults() will be called by the next nextInt() call.
}
public int nextInt()
{
if (valuesLeft == 0)
{
generateMoreResults();
assert valuesLeft == 256;
}
int value = randResult[--valuesLeft];
return value;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.math.BigInteger;
import java.util.Random;
public class RSA
{
private final BigInteger e = Proxy.SERVER_RSA_KEY_EXPONENT; // Use same exponent as server
private final BigInteger n;
private final BigInteger d;
public RSA()
{
// This taken from http://stackoverflow.com/a/24547249
int keySize = Proxy.SERVER_RSA_KEY_MODULUS.bitLength(); // pick same key size as server
//SecureRandom random = new SecureRandom();
Random random = new Random(42); // Hack to make the modulus always the same
// Choose two distinct prime numbers p and q.
BigInteger p = BigInteger.probablePrime(keySize / 2, random);
BigInteger q = BigInteger.probablePrime(keySize / 2, random);
// Compute n = pq (modulus)
n = p.multiply(q);
// Compute φ(n) = φ(p)φ(q) = (p 1)(q 1) = n - (p + q -1), where φ is Euler's totient function.
// and choose an integer e such that 1 < e < φ(n) and gcd(e, φ(n)) = 1; i.e., e and φ(n) are coprime.
BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
assert m.gcd(e).equals(BigInteger.ONE); // We always pick SERVER_RSA_KEY_EXPONENT instead
// Determine d as d ≡ e1 (mod φ(n)); i.e., d is the multiplicative inverse of e (modulo φ(n)).
d = e.modInverse(m);
}
public RSA(BigInteger n, BigInteger d)
{
this.n = n;
this.d = d;
}
public BigInteger encrypt(BigInteger value)
{
// C = P**e % n
return value.modPow(e, n);
}
public BigInteger decrypt(BigInteger value)
{
// P = C**d % n
return value.modPow(d, n);
}
public byte[] encrypt(byte[] value)
{
return encrypt(new BigInteger(value)).toByteArray();
}
public byte[] decrypt(byte[] value)
{
return decrypt(new BigInteger(value)).toByteArray();
}
public BigInteger getE()
{
return e;
}
public BigInteger getN()
{
return n;
}
public BigInteger getD()
{
return d;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.proxy;
import java.math.BigInteger;
import org.junit.Assert;
import org.junit.Test;
public class RSATest
{
@Test
public void testSomeMethod()
{
RSA rsa = new RSA();
BigInteger C = rsa.encrypt(BigInteger.valueOf(42));
int value = rsa.decrypt(C).intValue();
Assert.assertEquals(42, value);
}
}