Skip to content

Commit

Permalink
feat: add proper CRC decoding (excluding beta support for now)
Browse files Browse the repository at this point in the history
  • Loading branch information
Z-Kris committed Apr 23, 2024
1 parent f8a36a5 commit 7d862e3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package net.rsprot.protocol.loginprot.incoming.util

/**
* CRC blocks are helper structures used for the server to verify that the CRC is up-to-date.
* As the client transmits less CRCs than there are cache indices, we provide validation methods
* through this abstract class at the respective revision's decoder level, so we can perform checks
* that correspond to the information received from the client, and not what the server fully knows of.
* @property clientCrc the int array of client CRCs, indexed by the cache archives.
*/
public abstract class CyclicRedundancyCheckBlock(
protected val clientCrc: IntArray,
) {
public abstract fun validate(serverCrc: IntArray): Boolean

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is CyclicRedundancyCheckBlock) return false

if (!clientCrc.contentEquals(other.clientCrc)) return false

return true
}

override fun hashCode(): Int {
return clientCrc.contentHashCode()
}

override fun toString(): String {
return "CyclicRedundancyCheckBlock(clientCrc=${clientCrc.contentToString()})"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class LoginBlock<T>(
public val hostPlatformStats: HostPlatformStats,
private val _secondClientType: UByte,
private val _crcBlockHeader: UByte,
public val crc: IntArray,
public val crc: CyclicRedundancyCheckBlock,
public val authentication: T,
) : IncomingMessage {
public val firstClientType: Int
Expand Down Expand Up @@ -68,7 +68,7 @@ public class LoginBlock<T>(
if (hostPlatformStats != other.hostPlatformStats) return false
if (_secondClientType != other._secondClientType) return false
if (_crcBlockHeader != other._crcBlockHeader) return false
if (!crc.contentEquals(other.crc)) return false
if (crc != other.crc) return false
if (authentication != other.authentication) return false

return true
Expand All @@ -94,7 +94,7 @@ public class LoginBlock<T>(
result = 31 * result + hostPlatformStats.hashCode()
result = 31 * result + _secondClientType.hashCode()
result = 31 * result + _crcBlockHeader.hashCode()
result = 31 * result + crc.contentHashCode()
result = 31 * result + crc.hashCode()
result = 31 * result + authentication.hashCode()
return result
}
Expand All @@ -112,7 +112,7 @@ public class LoginBlock<T>(
"siteSettings='$siteSettings', " +
"affiliate=$affiliate, " +
"hostPlatformStats=$hostPlatformStats, " +
"crc=${crc.contentToString()}, " +
"crc=$crc, " +
"firstClientType=$firstClientType, " +
"platformType=$platformType, " +
"constZero1=$constZero1, " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.rsprot.protocol.common.loginprot.incoming.codec.shared
import net.rsprot.buffer.JagByteBuf
import net.rsprot.protocol.cryptography.decipherRsa
import net.rsprot.protocol.cryptography.xteaDecrypt
import net.rsprot.protocol.loginprot.incoming.util.CyclicRedundancyCheckBlock
import net.rsprot.protocol.loginprot.incoming.util.HostPlatformStats
import net.rsprot.protocol.loginprot.incoming.util.LoginBlock
import java.math.BigInteger
Expand Down Expand Up @@ -52,11 +53,7 @@ public abstract class LoginBlockDecoder<T>(
val hostPlatformStats = decodeHostPlatformStats(xteaBuffer)
val secondClientType = xteaBuffer.g1()
val crcBlockHeader = xteaBuffer.g4()
// As revision 221 isn't out yet, we will just naively read the values
val crc =
IntArray(21) {
xteaBuffer.g4()
}
val crc = decodeCrc(xteaBuffer)
return LoginBlock(
version,
subVersion,
Expand All @@ -82,6 +79,46 @@ public abstract class LoginBlockDecoder<T>(
)
}

private fun decodeCrc(buffer: JagByteBuf): CyclicRedundancyCheckBlock {
val transmittedCount = 21
val crc = IntArray(transmittedCount)
crc[0] = buffer.g4Alt1()
crc[4] = buffer.g4Alt3()
crc[15] = buffer.g4Alt3()
crc[17] = buffer.g4Alt1()
crc[13] = buffer.g4Alt2()
crc[16] = buffer.g4Alt1()
crc[1] = buffer.g4Alt1()
crc[10] = buffer.g4()
crc[9] = buffer.g4Alt2()
crc[7] = buffer.g4()
crc[8] = buffer.g4Alt2()
crc[6] = buffer.g4Alt1()
crc[20] = buffer.g4Alt3()
crc[19] = buffer.g4Alt3()
crc[14] = buffer.g4()
crc[12] = buffer.g4()
crc[5] = buffer.g4Alt2()
crc[3] = buffer.g4Alt3()
crc[11] = buffer.g4Alt3()
crc[2] = buffer.g4Alt3()
crc[18] = buffer.g4Alt3()

return object : CyclicRedundancyCheckBlock(crc) {
override fun validate(serverCrc: IntArray): Boolean {
require(serverCrc.size >= transmittedCount) {
"Server CRC length less than expected: ${serverCrc.size}, expected >= $transmittedCount"
}
for (i in 0..<transmittedCount) {
if (serverCrc[i] != this.clientCrc[i]) {
return false
}
}
return true
}
}
}

private fun decodeHostPlatformStats(buffer: JagByteBuf): HostPlatformStats {
val version = buffer.g1()
val osType = buffer.g1()
Expand Down

0 comments on commit 7d862e3

Please sign in to comment.