diff --git a/protocol/build.gradle.kts b/protocol/build.gradle.kts index 04c81b01..1b0949d7 100644 --- a/protocol/build.gradle.kts +++ b/protocol/build.gradle.kts @@ -9,6 +9,7 @@ dependencies { api(libs.netty.codec.core) implementation(projects.buffer) + implementation(projects.util) } publishing { diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt b/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt index 8af99593..8417994b 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/ProtocolModule.kt @@ -12,6 +12,7 @@ import org.openrs2.protocol.login.downstream.IpLimitCodec import org.openrs2.protocol.login.downstream.Js5OkCodec import org.openrs2.protocol.login.downstream.LoginDownstream import org.openrs2.protocol.login.downstream.ServerFullCodec +import org.openrs2.protocol.login.upstream.CheckWorldSuitabilityCodec import org.openrs2.protocol.login.upstream.InitCrossDomainConnectionCodec import org.openrs2.protocol.login.upstream.InitGameConnectionCodec import org.openrs2.protocol.login.upstream.InitJaggrabConnectionCodec @@ -32,6 +33,7 @@ public object ProtocolModule : AbstractModule() { InitJs5RemoteConnectionCodec::class.java, InitJaggrabConnectionCodec::class.java, RequestWorldListCodec::class.java, + CheckWorldSuitabilityCodec::class.java, InitCrossDomainConnectionCodec::class.java ) diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/CheckWorldSuitabilityCodec.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/CheckWorldSuitabilityCodec.kt new file mode 100644 index 00000000..dcc353ef --- /dev/null +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/CheckWorldSuitabilityCodec.kt @@ -0,0 +1,67 @@ +package org.openrs2.protocol.login.upstream + +import io.netty.buffer.ByteBuf +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters +import org.openrs2.buffer.readString +import org.openrs2.buffer.use +import org.openrs2.buffer.writeString +import org.openrs2.crypto.Rsa +import org.openrs2.crypto.StreamCipher +import org.openrs2.crypto.rsa +import org.openrs2.crypto.secureRandom +import org.openrs2.protocol.PacketCodec +import org.openrs2.protocol.PacketLength +import org.openrs2.util.Base37 +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +public class CheckWorldSuitabilityCodec @Inject constructor( + private val key: RSAPrivateCrtKeyParameters +) : PacketCodec( + type = LoginRequest.CheckWorldSuitability::class.java, + opcode = 24, + length = PacketLength.VARIABLE_BYTE +) { + override fun decode(input: ByteBuf, cipher: StreamCipher): LoginRequest.CheckWorldSuitability { + val build = input.readShort().toInt() + + val ciphertextLen = input.readUnsignedByte().toInt() + val ciphertext = input.readSlice(ciphertextLen) + + ciphertext.rsa(key).use { plaintext -> + require(plaintext.readUnsignedByte().toInt() == Rsa.MAGIC) { + "Invalid RSA magic" + } + plaintext.skipBytes(4) + + val username = Base37.decodeLowerCase(plaintext.readLong()) + plaintext.skipBytes(4) + + val password = plaintext.readString() + plaintext.skipBytes(4) + + return LoginRequest.CheckWorldSuitability(build, username, password) + } + } + + override fun encode(input: LoginRequest.CheckWorldSuitability, output: ByteBuf, cipher: StreamCipher) { + output.writeShort(input.build) + + output.alloc().buffer().use { plaintext -> + plaintext.writeByte(Rsa.MAGIC) + plaintext.writeInt(secureRandom.nextInt()) + + plaintext.writeLong(Base37.encode(input.username)) + plaintext.writeInt(secureRandom.nextInt()) + + plaintext.writeString(input.password) + plaintext.writeInt(secureRandom.nextInt()) + + plaintext.rsa(key).use { ciphertext -> + output.writeByte(ciphertext.readableBytes()) + output.writeBytes(ciphertext) + } + } + } +} diff --git a/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt index 577670e6..a83d7255 100644 --- a/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt +++ b/protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/LoginRequest.kt @@ -7,5 +7,10 @@ public sealed class LoginRequest : Packet { public data class InitJs5RemoteConnection(public val build: Int) : LoginRequest() public object InitJaggrabConnection : LoginRequest() public data class RequestWorldList(public val checksum: Int) : LoginRequest() + public data class CheckWorldSuitability( + public val build: Int, + public val username: String, + public val password: String + ) : LoginRequest() public object InitCrossDomainConnection : LoginRequest() }