Open-source multiplayer game server compatible with the RuneScape client
https://www.openrs2.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.7 KiB
143 lines
4.7 KiB
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.SymmetricKey
|
|
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: SymmetricKey,
|
|
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,
|
|
SymmetricKey(k0, k1, k2, k3),
|
|
Base37.decodeLowerCase(username),
|
|
password,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|