forked from openrs2/openrs2
parent
508d9526ea
commit
6d43e0392e
@ -0,0 +1,19 @@ |
||||
package org.openrs2.protocol.common |
||||
|
||||
public enum class AntiAliasingMode { |
||||
NONE, |
||||
X2, |
||||
X4; |
||||
|
||||
public companion object { |
||||
private val values = values() |
||||
|
||||
public fun fromOrdinal(ordinal: Int): AntiAliasingMode? { |
||||
return if (ordinal >= 0 && ordinal < values.size) { |
||||
values[ordinal] |
||||
} else { |
||||
null |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,20 @@ |
||||
package org.openrs2.protocol.common |
||||
|
||||
public enum class DisplayMode { |
||||
SD, |
||||
HD_SMALL, |
||||
HD, |
||||
HD_FULLSCREEN; |
||||
|
||||
public companion object { |
||||
private val values = values() |
||||
|
||||
public fun fromOrdinal(ordinal: Int): DisplayMode? { |
||||
return if (ordinal >= 0 && ordinal < values.size) { |
||||
values[ordinal] |
||||
} else { |
||||
null |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
package org.openrs2.protocol.common |
||||
|
||||
import io.netty.buffer.ByteBuf |
||||
import io.netty.buffer.ByteBufUtil |
||||
|
||||
public class Uid private constructor( |
||||
private val bytes: ByteArray, |
||||
) { |
||||
init { |
||||
require(bytes.size == LENGTH) |
||||
} |
||||
|
||||
public fun write(buf: ByteBuf) { |
||||
buf.writeBytes(bytes) |
||||
} |
||||
|
||||
public override fun toString(): String { |
||||
return ByteBufUtil.hexDump(bytes) |
||||
} |
||||
|
||||
public companion object { |
||||
public const val LENGTH: Int = 24 |
||||
|
||||
public fun read(buf: ByteBuf): Uid { |
||||
val bytes = ByteArray(LENGTH) |
||||
buf.readBytes(bytes) |
||||
return Uid(bytes) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
package org.openrs2.protocol.login.upstream |
||||
|
||||
import io.netty.buffer.ByteBuf |
||||
import jakarta.inject.Inject |
||||
import jakarta.inject.Singleton |
||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters |
||||
import org.openrs2.crypto.StreamCipher |
||||
import org.openrs2.protocol.VariableShortPacketCodec |
||||
|
||||
@Singleton |
||||
public class GameLoginCodec @Inject constructor( |
||||
private val key: RSAPrivateCrtKeyParameters, |
||||
) : VariableShortPacketCodec<LoginRequest.GameLogin>( |
||||
type = LoginRequest.GameLogin::class.java, |
||||
opcode = 16, |
||||
) { |
||||
override fun decode(input: ByteBuf, cipher: StreamCipher): LoginRequest.GameLogin { |
||||
return LoginRequest.GameLogin(GameLoginPayload.read(input, key)) |
||||
} |
||||
|
||||
override fun encode(input: LoginRequest.GameLogin, output: ByteBuf, cipher: StreamCipher) { |
||||
input.payload.write(output, key) |
||||
} |
||||
} |
@ -0,0 +1,143 @@ |
||||
package org.openrs2.protocol.login.upstream |
||||
|
||||
import io.netty.buffer.ByteBuf |
||||
import org.bouncycastle.crypto.params.RSAKeyParameters |
||||
import org.openrs2.buffer.readString |
||||
import org.openrs2.buffer.use |
||||
import org.openrs2.buffer.writeString |
||||
import org.openrs2.crypto.Rsa |
||||
import org.openrs2.crypto.XteaKey |
||||
import org.openrs2.crypto.rsa |
||||
import org.openrs2.protocol.common.AntiAliasingMode |
||||
import org.openrs2.protocol.common.DisplayMode |
||||
import org.openrs2.protocol.common.Uid |
||||
import org.openrs2.util.Base37 |
||||
|
||||
public data class GameLoginPayload( |
||||
val build: Int, |
||||
val advertSuppressed: Boolean, |
||||
val clientSigned: Boolean, |
||||
val displayMode: DisplayMode, |
||||
val canvasWidth: Int, |
||||
val canvasHeight: Int, |
||||
val antiAliasingMode: AntiAliasingMode, |
||||
val uid: Uid, |
||||
val siteSettings: String, |
||||
val affiliate: Int, |
||||
val detailOptions: Int, |
||||
val verifyId: Int, |
||||
val js5ArchiveChecksums: List<Int>, |
||||
// TODO(gpe): XteaKey needs a better name, as it represents an ISAAC key here |
||||
val key: XteaKey, |
||||
val username: String, |
||||
val password: String, |
||||
) { |
||||
init { |
||||
require(js5ArchiveChecksums.size == JS5_ARCHIVES) |
||||
} |
||||
|
||||
internal fun write(buf: ByteBuf, rsaKey: RSAKeyParameters) { |
||||
buf.writeInt(build) |
||||
buf.writeByte(0) |
||||
buf.writeBoolean(advertSuppressed) |
||||
buf.writeBoolean(clientSigned) |
||||
buf.writeByte(displayMode.ordinal) |
||||
buf.writeShort(canvasWidth) |
||||
buf.writeShort(canvasHeight) |
||||
buf.writeByte(antiAliasingMode.ordinal) |
||||
uid.write(buf) |
||||
buf.writeString(siteSettings) |
||||
buf.writeInt(affiliate) |
||||
buf.writeInt(detailOptions) |
||||
buf.writeShort(verifyId) |
||||
|
||||
for (checksum in js5ArchiveChecksums) { |
||||
buf.writeInt(checksum) |
||||
} |
||||
|
||||
buf.alloc().buffer().use { plaintext -> |
||||
plaintext.writeByte(Rsa.MAGIC) |
||||
plaintext.writeInt(key.k0) |
||||
plaintext.writeInt(key.k1) |
||||
plaintext.writeInt(key.k2) |
||||
plaintext.writeInt(key.k3) |
||||
plaintext.writeLong(Base37.encode(username)) |
||||
plaintext.writeString(password) |
||||
|
||||
plaintext.rsa(rsaKey).use { ciphertext -> |
||||
buf.writeByte(ciphertext.readableBytes()) |
||||
buf.writeBytes(ciphertext) |
||||
} |
||||
} |
||||
} |
||||
|
||||
public companion object { |
||||
public const val JS5_ARCHIVES: Int = 29 |
||||
|
||||
internal fun read(buf: ByteBuf, rsaKey: RSAKeyParameters): GameLoginPayload { |
||||
val build = buf.readInt() |
||||
|
||||
require(buf.readUnsignedByte().toInt() == 0) { |
||||
"Unknown byte is non-zero" |
||||
} |
||||
|
||||
val advertSuppressed = buf.readBoolean() |
||||
val clientSigned = buf.readBoolean() |
||||
|
||||
val displayMode = DisplayMode.fromOrdinal(buf.readUnsignedByte().toInt()) |
||||
?: throw IllegalArgumentException("Invalid DisplayMode") |
||||
|
||||
val canvasWidth = buf.readUnsignedShort() |
||||
val canvasHeight = buf.readUnsignedShort() |
||||
|
||||
val antiAliasingMode = AntiAliasingMode.fromOrdinal(buf.readUnsignedByte().toInt()) |
||||
?: throw IllegalArgumentException("Invalid AntiAliasingMode") |
||||
|
||||
val uid = Uid.read(buf) |
||||
val siteSettings = buf.readString() |
||||
val affiliate = buf.readInt() |
||||
val detailOptions = buf.readInt() |
||||
val verifyId = buf.readUnsignedShort() |
||||
|
||||
val js5ArchiveChecksums = mutableListOf<Int>() |
||||
for (i in 0 until JS5_ARCHIVES) { |
||||
js5ArchiveChecksums += buf.readInt() |
||||
} |
||||
|
||||
val ciphertextLen = buf.readUnsignedByte().toInt() |
||||
val ciphertext = buf.readSlice(ciphertextLen) |
||||
|
||||
ciphertext.rsa(rsaKey).use { plaintext -> |
||||
require(plaintext.readUnsignedByte().toInt() == Rsa.MAGIC) { |
||||
"Invalid RSA magic" |
||||
} |
||||
|
||||
val k0 = plaintext.readInt() |
||||
val k1 = plaintext.readInt() |
||||
val k2 = plaintext.readInt() |
||||
val k3 = plaintext.readInt() |
||||
val username = plaintext.readLong() |
||||
val password = plaintext.readString() |
||||
|
||||
return GameLoginPayload( |
||||
build, |
||||
advertSuppressed, |
||||
clientSigned, |
||||
displayMode, |
||||
canvasWidth, |
||||
canvasHeight, |
||||
antiAliasingMode, |
||||
uid, |
||||
siteSettings, |
||||
affiliate, |
||||
detailOptions, |
||||
verifyId, |
||||
js5ArchiveChecksums, |
||||
XteaKey(k0, k1, k2, k3), |
||||
Base37.decodeLowerCase(username), |
||||
password, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
package org.openrs2.protocol.login.upstream |
||||
|
||||
import io.netty.buffer.ByteBuf |
||||
import jakarta.inject.Inject |
||||
import jakarta.inject.Singleton |
||||
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters |
||||
import org.openrs2.crypto.StreamCipher |
||||
import org.openrs2.protocol.VariableShortPacketCodec |
||||
|
||||
@Singleton |
||||
public class GameReconnectCodec @Inject constructor( |
||||
private val key: RSAPrivateCrtKeyParameters, |
||||
) : VariableShortPacketCodec<LoginRequest.GameReconnect>( |
||||
type = LoginRequest.GameReconnect::class.java, |
||||
opcode = 18, |
||||
) { |
||||
override fun decode(input: ByteBuf, cipher: StreamCipher): LoginRequest.GameReconnect { |
||||
return LoginRequest.GameReconnect(GameLoginPayload.read(input, key)) |
||||
} |
||||
|
||||
override fun encode(input: LoginRequest.GameReconnect, output: ByteBuf, cipher: StreamCipher) { |
||||
input.payload.write(output, key) |
||||
} |
||||
} |
Loading…
Reference in new issue