Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate RSA key reading from login decoding #210

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
15 changes: 13 additions & 2 deletions src/main/java/io/luna/net/LunaChannelInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import io.luna.net.client.IdleClient;
import io.luna.net.codec.login.LoginDecoder;
import io.luna.net.codec.login.LoginEncoder;
import io.luna.security.RsaKey;
import io.luna.security.RsaKeyReader;
import io.luna.security.TomlPrivateRsaKeyReader;
import io.luna.net.msg.GameMessageRepository;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandler.Sharable;
Expand Down Expand Up @@ -46,10 +49,15 @@ public final class LunaChannelInitializer extends ChannelInitializer<SocketChann
*/
private final GameMessageRepository msgRepository;

/**
* The private RSA key, only to be seen by the server.
*/
private final RsaKey privateKey;

/**
* Creates a new {@link LunaChannelInitializer}.
*
* @param context The context instance.
* @param context The context instance.
* @param channelFilter A channel handler that will filter channels.
* @param msgRepository The message repository.
*/
Expand All @@ -58,6 +66,9 @@ public LunaChannelInitializer(LunaContext context, LunaChannelFilter channelFilt
this.context = context;
this.channelFilter = channelFilter;
this.msgRepository = msgRepository;

RsaKeyReader reader = new TomlPrivateRsaKeyReader();
this.privateKey = reader.read();
}

@Override
Expand All @@ -67,7 +78,7 @@ protected void initChannel(SocketChannel ch) throws Exception {

ch.pipeline().addLast("read-timeout", new ReadTimeoutHandler(5));
ch.pipeline().addLast("channel-filter", channelFilter);
ch.pipeline().addLast("login-decoder", new LoginDecoder(context, msgRepository));
ch.pipeline().addLast("login-decoder", new LoginDecoder(context, msgRepository, privateKey));
ch.pipeline().addLast("login-encoder", loginEncoder);
ch.pipeline().addLast("upstream-handler", upstreamHandler);
}
Expand Down
37 changes: 6 additions & 31 deletions src/main/java/io/luna/net/codec/login/LoginDecoder.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package io.luna.net.codec.login;

import com.moandjiezana.toml.Toml;
import io.luna.LunaContext;
import io.luna.net.client.Client;
import io.luna.net.client.LoginClient;
import io.luna.net.codec.ByteMessage;
import io.luna.net.codec.IsaacCipher;
import io.luna.net.codec.ProgressiveMessageDecoder;
import io.luna.net.msg.GameMessageRepository;
import io.luna.security.RsaKey;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.Attribute;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;
Expand All @@ -29,18 +28,7 @@
*/
public final class LoginDecoder extends ProgressiveMessageDecoder<LoginDecoder.DecodeState> {

static {
try {
// Initializes RSA modulus and exponent values.
Toml tomlReader = new Toml().
read(new File("./data/rsa/rsapriv.toml")).
getTable("key");
RSA_MOD = new BigInteger(tomlReader.getString("modulus"));
RSA_EXP = new BigInteger(tomlReader.getString("exponent"));
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private final RsaKey privateRsaKey;

/**
* An enumerated type representing login decoder states.
Expand All @@ -51,21 +39,6 @@ enum DecodeState {
RSA_BLOCK
}

/**
* The asynchronous logger.
*/
private static final Logger logger = LogManager.getLogger();

/**
* The private RSA modulus value.
*/
private static final BigInteger RSA_MOD;

/**
* The private RSA exponent value.
*/
private static final BigInteger RSA_EXP;

/**
* A cryptographically secure RNG.
*/
Expand All @@ -91,11 +64,13 @@ enum DecodeState {
*
* @param context The context instance.
* @param repository The message repository.
* @param privateRsaKey The private RSA key.
*/
public LoginDecoder(LunaContext context, GameMessageRepository repository) {
public LoginDecoder(LunaContext context, GameMessageRepository repository, RsaKey privateRsaKey) {
super(DecodeState.HANDSHAKE);
this.context = context;
this.repository = repository;
this.privateRsaKey = privateRsaKey;
}

@Override
Expand Down Expand Up @@ -206,7 +181,7 @@ private Object decodeRsaBlock(ChannelHandlerContext ctx, ByteBuf in) {

ByteBuf rsaBuffer = ByteMessage.pooledBuffer();
try {
rsaBuffer.writeBytes(new BigInteger(rsaBytes).modPow(RSA_EXP, RSA_MOD).toByteArray());
rsaBuffer.writeBytes(new BigInteger(rsaBytes).modPow(privateRsaKey.exponent, privateRsaKey.modulus).toByteArray());

int rsaOpcode = rsaBuffer.readUnsignedByte();
checkState(rsaOpcode == 10, "rsaOpcode != 10");
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/io/luna/security/RsaKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.luna.security;

import java.math.BigInteger;

/**
* An RSA key consisting of a modulus and exponent.
* <p>
* For more information on the RSA encryption algorithm,
* read <a href="https://www.comparitech.com/blog/information-security/rsa-encryption/"> this article.</a>
* <br>
* <b>NOTE: </b> Luna and/or it's contributors have no affiliation with the website linked above.
*/
public final class RsaKey {
/**
* The private RSA modulus value.
*/
public final BigInteger modulus;

/**
* The private RSA exponent value.
*/
public final BigInteger exponent;

RsaKey(BigInteger modulus, BigInteger exponent) {
this.modulus = modulus;
this.exponent = exponent;
}
}
10 changes: 10 additions & 0 deletions src/main/java/io/luna/security/RsaKeyReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.luna.security;


public interface RsaKeyReader {

/**
* Reads an RSA key from memory.
*/
RsaKey read();
}
30 changes: 30 additions & 0 deletions src/main/java/io/luna/security/TomlPrivateRsaKeyReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.luna.security;

import com.moandjiezana.toml.Toml;

import java.io.File;
import java.math.BigInteger;

/**
* Responsible for reading a RSA private key from a TOML file.
*/
public class TomlPrivateRsaKeyReader implements RsaKeyReader {

private final String filePath = "./data/rsa/rsapriv.toml";

@Override
public RsaKey read() {

File file = new File(filePath);

if (!file.exists()) {
throw new IllegalStateException("Could not find RSA key file at location: " + filePath);
}

Toml reader = new Toml().read(file).getTable("key");

BigInteger mod = new BigInteger(reader.getString("modulus"));
BigInteger exp = new BigInteger(reader.getString("exponent"));
return new RsaKey(mod, exp);
}
}
17 changes: 17 additions & 0 deletions src/test/java/io/luna/security/TomlPrivateRsaKeyReaderTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.luna.security;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class TomlPrivateRsaKeyReaderTest {

@Test
void read() {
RsaKeyReader reader = new TomlPrivateRsaKeyReader();
RsaKey key = reader.read();

assertNotNull(key.modulus);
assertNotNull(key.exponent);
}
}