Rename XteaKey to SymmetricKey

It's now used for both XTEA and ISAAC keys, and there's nothing
XTEA-specific about it so there's no need to duplicate it.

Signed-off-by: Graham <gpe@openrs2.org>
master
Graham 11 months ago
parent 4ac91e4f29
commit 71b1ac8e20
  1. 6
      archive/src/main/kotlin/org/openrs2/archive/cache/CacheExporter.kt
  2. 20
      archive/src/main/kotlin/org/openrs2/archive/key/BinaryKeyReader.kt
  3. 8
      archive/src/main/kotlin/org/openrs2/archive/key/HdosKeyDownloader.kt
  4. 6
      archive/src/main/kotlin/org/openrs2/archive/key/HexKeyReader.kt
  5. 4
      archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyDownloader.kt
  6. 10
      archive/src/main/kotlin/org/openrs2/archive/key/JsonKeyReader.kt
  7. 10
      archive/src/main/kotlin/org/openrs2/archive/key/KeyBruteForcer.kt
  8. 4
      archive/src/main/kotlin/org/openrs2/archive/key/KeyDownloader.kt
  9. 12
      archive/src/main/kotlin/org/openrs2/archive/key/KeyExporter.kt
  10. 10
      archive/src/main/kotlin/org/openrs2/archive/key/KeyImporter.kt
  11. 4
      archive/src/main/kotlin/org/openrs2/archive/key/KeyReader.kt
  12. 6
      archive/src/main/kotlin/org/openrs2/archive/key/TextKeyReader.kt
  13. 4
      archive/src/main/kotlin/org/openrs2/archive/web/KeysController.kt
  14. 38
      cache/src/main/kotlin/org/openrs2/cache/Archive.kt
  15. 48
      cache/src/main/kotlin/org/openrs2/cache/Cache.kt
  16. 14
      cache/src/main/kotlin/org/openrs2/cache/Js5Compression.kt
  17. 62
      cache/src/test/kotlin/org/openrs2/cache/Js5CompressionTest.kt
  18. 4
      crypto/src/main/kotlin/org/openrs2/crypto/CryptoJacksonModule.kt
  19. 18
      crypto/src/main/kotlin/org/openrs2/crypto/SymmetricKey.kt
  20. 6
      crypto/src/main/kotlin/org/openrs2/crypto/SymmetricKeyDeserializer.kt
  21. 4
      crypto/src/main/kotlin/org/openrs2/crypto/SymmetricKeySerializer.kt
  22. 4
      crypto/src/main/kotlin/org/openrs2/crypto/Xtea.kt
  23. 2
      crypto/src/test/kotlin/org/openrs2/crypto/XteaTest.kt
  24. 6
      protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/CreateAccountCodec.kt
  25. 6
      protocol/src/main/kotlin/org/openrs2/protocol/login/upstream/GameLoginPayload.kt

@ -16,7 +16,7 @@ import org.openrs2.cache.Js5Compression
import org.openrs2.cache.Js5MasterIndex
import org.openrs2.cache.MasterIndexFormat
import org.openrs2.cache.Store
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.db.Database
import org.postgresql.util.PGobject
import java.sql.Connection
@ -196,7 +196,7 @@ public class CacheExporter @Inject constructor(
val nameHash: Int?,
val name: String?,
@JsonProperty("mapsquare") val mapSquare: Int?,
val key: XteaKey
val key: SymmetricKey
)
public suspend fun totalSize(): Long {
@ -779,7 +779,7 @@ public class CacheExporter @Inject constructor(
val k3 = rows.getInt(8)
val mapSquare = getMapSquare(name)
keys += Key(archive, group, nameHash, name, mapSquare, XteaKey(k0, k1, k2, k3))
keys += Key(archive, group, nameHash, name, mapSquare, SymmetricKey(k0, k1, k2, k3))
}
keys

@ -3,17 +3,17 @@ package org.openrs2.archive.key
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import org.openrs2.buffer.use
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import java.io.InputStream
public object BinaryKeyReader : KeyReader {
override fun read(input: InputStream): Sequence<XteaKey> {
override fun read(input: InputStream): Sequence<SymmetricKey> {
Unpooled.wrappedBuffer(input.readBytes()).use { buf ->
val len = buf.readableBytes()
if (len == (128 * 128 * 16)) {
val keys = read(buf, 0)
require(XteaKey.ZERO in keys)
require(SymmetricKey.ZERO in keys)
return keys.asSequence()
}
@ -22,19 +22,19 @@ public object BinaryKeyReader : KeyReader {
if (maybeShort && !maybeInt) {
val keys = read(buf, 2)
require(XteaKey.ZERO in keys)
require(SymmetricKey.ZERO in keys)
return keys.asSequence()
} else if (!maybeShort && maybeInt) {
val keys = read(buf, 4).asSequence()
require(XteaKey.ZERO in keys)
require(SymmetricKey.ZERO in keys)
return keys.asSequence()
} else if (maybeShort && maybeInt) {
val shortKeys = read(buf, 2)
val intKeys = read(buf, 4)
return if (XteaKey.ZERO in shortKeys && XteaKey.ZERO !in intKeys) {
return if (SymmetricKey.ZERO in shortKeys && SymmetricKey.ZERO !in intKeys) {
shortKeys.asSequence()
} else if (XteaKey.ZERO !in shortKeys && XteaKey.ZERO in intKeys) {
} else if (SymmetricKey.ZERO !in shortKeys && SymmetricKey.ZERO in intKeys) {
intKeys.asSequence()
} else {
throw IllegalArgumentException("Failed to determine if map square IDs are 2 or 4 bytes")
@ -47,8 +47,8 @@ public object BinaryKeyReader : KeyReader {
}
}
private fun read(buf: ByteBuf, mapSquareLen: Int): Set<XteaKey> {
val keys = mutableSetOf<XteaKey>()
private fun read(buf: ByteBuf, mapSquareLen: Int): Set<SymmetricKey> {
val keys = mutableSetOf<SymmetricKey>()
while (buf.isReadable) {
buf.skipBytes(mapSquareLen)
@ -57,7 +57,7 @@ public object BinaryKeyReader : KeyReader {
val k1 = buf.readInt()
val k2 = buf.readInt()
val k3 = buf.readInt()
keys += XteaKey(k0, k1, k2, k3)
keys += SymmetricKey(k0, k1, k2, k3)
}
return keys

@ -5,7 +5,7 @@ import jakarta.inject.Singleton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.future.await
import kotlinx.coroutines.withContext
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.http.checkStatusCode
import java.net.URI
import java.net.http.HttpClient
@ -21,7 +21,7 @@ public class HdosKeyDownloader @Inject constructor(
return setOf(ENDPOINT)
}
override suspend fun download(url: String): Sequence<XteaKey> {
override suspend fun download(url: String): Sequence<SymmetricKey> {
val request = HttpRequest.newBuilder(URI(url))
.GET()
.timeout(Duration.ofSeconds(30))
@ -33,7 +33,7 @@ public class HdosKeyDownloader @Inject constructor(
return withContext(Dispatchers.IO) {
response.body().use { input ->
input.bufferedReader().use { reader ->
val keys = mutableSetOf<XteaKey>()
val keys = mutableSetOf<SymmetricKey>()
for (line in reader.lineSequence()) {
val parts = line.split(',')
@ -41,7 +41,7 @@ public class HdosKeyDownloader @Inject constructor(
continue
}
val key = XteaKey.fromHexOrNull(parts[2]) ?: continue
val key = SymmetricKey.fromHexOrNull(parts[2]) ?: continue
keys += key
}

@ -1,13 +1,13 @@
package org.openrs2.archive.key
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import java.io.InputStream
public object HexKeyReader : KeyReader {
override fun read(input: InputStream): Sequence<XteaKey> {
override fun read(input: InputStream): Sequence<SymmetricKey> {
return input.bufferedReader()
.lineSequence()
.map(XteaKey::fromHexOrNull)
.map(SymmetricKey::fromHexOrNull)
.filterNotNull()
}
}

@ -3,7 +3,7 @@ package org.openrs2.archive.key
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.future.await
import kotlinx.coroutines.withContext
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.http.checkStatusCode
import java.net.URI
import java.net.http.HttpClient
@ -16,7 +16,7 @@ public abstract class JsonKeyDownloader(
private val client: HttpClient,
private val jsonKeyReader: JsonKeyReader
) : KeyDownloader(source) {
override suspend fun download(url: String): Sequence<XteaKey> {
override suspend fun download(url: String): Sequence<SymmetricKey> {
val request = HttpRequest.newBuilder(URI(url))
.GET()
.timeout(Duration.ofSeconds(30))

@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.treeToValue
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.json.Json
import java.io.IOException
import java.io.InputStream
@ -13,21 +13,21 @@ import java.io.InputStream
public class JsonKeyReader @Inject constructor(
@Json private val mapper: ObjectMapper
) : KeyReader {
override fun read(input: InputStream): Sequence<XteaKey> {
val keys = mutableSetOf<XteaKey>()
override fun read(input: InputStream): Sequence<SymmetricKey> {
val keys = mutableSetOf<SymmetricKey>()
val root = mapper.readTree(input)
when {
root.isArray -> {
for (entry in root) {
val key = entry["key"] ?: entry["keys"] ?: throw IOException("Missing 'key' or 'keys' field")
keys += mapper.treeToValue<XteaKey?>(key) ?: throw IOException("Key must be non-null")
keys += mapper.treeToValue<SymmetricKey?>(key) ?: throw IOException("Key must be non-null")
}
}
root.isObject -> {
for (entry in root.fields()) {
keys += mapper.treeToValue<XteaKey?>(entry.value) ?: throw IOException("Key must be non-null")
keys += mapper.treeToValue<SymmetricKey?>(entry.value) ?: throw IOException("Key must be non-null")
}
}

@ -6,7 +6,7 @@ import jakarta.inject.Singleton
import org.openrs2.buffer.crc32
import org.openrs2.buffer.use
import org.openrs2.cache.Js5Compression
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.db.Database
import java.sql.Connection
import java.sql.Types
@ -203,7 +203,7 @@ public class KeyBruteForcer @Inject constructor(
val k1 = rows.getInt(3)
val k2 = rows.getInt(4)
val k3 = rows.getInt(5)
val key = XteaKey(k0, k1, k2, k3)
val key = SymmetricKey(k0, k1, k2, k3)
validatedKey = validateKey(data, key, keyId, containerId)
if (validatedKey != null) {
@ -326,7 +326,7 @@ public class KeyBruteForcer @Inject constructor(
}
}
private fun nextKey(connection: Connection, lastKeyId: Long?): Pair<Long, XteaKey>? {
private fun nextKey(connection: Connection, lastKeyId: Long?): Pair<Long, SymmetricKey>? {
connection.prepareStatement(
"""
SELECT id, (key).k0, (key).k1, (key).k2, (key).k3
@ -350,7 +350,7 @@ public class KeyBruteForcer @Inject constructor(
val k1 = rows.getInt(3)
val k2 = rows.getInt(4)
val k3 = rows.getInt(5)
val key = XteaKey(k0, k1, k2, k3)
val key = SymmetricKey(k0, k1, k2, k3)
return Pair(keyId, key)
}
@ -359,7 +359,7 @@ public class KeyBruteForcer @Inject constructor(
private fun validateKey(
data: ByteArray,
key: XteaKey,
key: SymmetricKey,
keyId: Long,
containerId: Long
): ValidatedKey? {

@ -1,10 +1,10 @@
package org.openrs2.archive.key
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
public abstract class KeyDownloader(
public val source: KeySource
) {
public abstract suspend fun getMissingUrls(seenUrls: Set<String>): Set<String>
public abstract suspend fun download(url: String): Sequence<XteaKey>
public abstract suspend fun download(url: String): Sequence<SymmetricKey>
}

@ -2,7 +2,7 @@ package org.openrs2.archive.key
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.db.Database
import java.io.BufferedOutputStream
import java.io.DataOutputStream
@ -82,11 +82,11 @@ public class KeyExporter @Inject constructor(
}
}
public suspend fun exportAll(): List<XteaKey> {
public suspend fun exportAll(): List<SymmetricKey> {
return export(validOnly = false)
}
public suspend fun exportValid(): List<XteaKey> {
public suspend fun exportValid(): List<SymmetricKey> {
return export(validOnly = true)
}
@ -116,7 +116,7 @@ public class KeyExporter @Inject constructor(
return analysis
}
private suspend fun export(validOnly: Boolean): List<XteaKey> {
private suspend fun export(validOnly: Boolean): List<SymmetricKey> {
return database.execute { connection ->
val query = if (validOnly) {
EXPORT_VALID_QUERY
@ -126,14 +126,14 @@ public class KeyExporter @Inject constructor(
connection.prepareStatement(query).use { stmt ->
stmt.executeQuery().use { rows ->
val keys = mutableListOf<XteaKey>()
val keys = mutableListOf<SymmetricKey>()
while (rows.next()) {
val k0 = rows.getInt(1)
val k1 = rows.getInt(2)
val k2 = rows.getInt(3)
val k3 = rows.getInt(4)
keys += XteaKey(k0, k1, k2, k3)
keys += SymmetricKey(k0, k1, k2, k3)
}
keys

@ -3,7 +3,7 @@ package org.openrs2.archive.key
import com.github.michaelbull.logging.InlineLogger
import jakarta.inject.Inject
import jakarta.inject.Singleton
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.db.Database
import java.io.IOException
import java.nio.file.Files
@ -19,10 +19,10 @@ public class KeyImporter @Inject constructor(
private val jsonKeyReader: JsonKeyReader,
private val downloaders: Set<KeyDownloader>
) {
private data class Key(val key: XteaKey, val source: KeySource)
private data class Key(val key: SymmetricKey, val source: KeySource)
public suspend fun import(path: Path) {
val keys = mutableSetOf<XteaKey>()
val keys = mutableSetOf<SymmetricKey>()
for (file in Files.walk(path)) {
if (!Files.isRegularFile(file)) {
@ -45,7 +45,7 @@ public class KeyImporter @Inject constructor(
}
}
keys -= XteaKey.ZERO
keys -= SymmetricKey.ZERO
logger.info { "Importing ${keys.size} keys" }
@ -108,7 +108,7 @@ public class KeyImporter @Inject constructor(
}
}
public suspend fun import(keys: Iterable<XteaKey>, source: KeySource) {
public suspend fun import(keys: Iterable<SymmetricKey>, source: KeySource) {
val now = Instant.now()
database.execute { connection ->

@ -1,8 +1,8 @@
package org.openrs2.archive.key
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import java.io.InputStream
public interface KeyReader {
public fun read(input: InputStream): Sequence<XteaKey>
public fun read(input: InputStream): Sequence<SymmetricKey>
}

@ -1,10 +1,10 @@
package org.openrs2.archive.key
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import java.io.InputStream
public object TextKeyReader : KeyReader {
override fun read(input: InputStream): Sequence<XteaKey> {
override fun read(input: InputStream): Sequence<SymmetricKey> {
val reader = input.bufferedReader()
val k0 = reader.readLine()?.toIntOrNull() ?: return emptySequence()
@ -12,6 +12,6 @@ public object TextKeyReader : KeyReader {
val k2 = reader.readLine()?.toIntOrNull() ?: return emptySequence()
val k3 = reader.readLine()?.toIntOrNull() ?: return emptySequence()
return sequenceOf(XteaKey(k0, k1, k2, k3))
return sequenceOf(SymmetricKey(k0, k1, k2, k3))
}
}

@ -10,7 +10,7 @@ import jakarta.inject.Singleton
import org.openrs2.archive.key.KeyExporter
import org.openrs2.archive.key.KeyImporter
import org.openrs2.archive.key.KeySource
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
@Singleton
public class KeysController @Inject constructor(
@ -24,7 +24,7 @@ public class KeysController @Inject constructor(
}
public suspend fun import(call: ApplicationCall) {
val keys = call.receive<Array<IntArray>>().mapTo(mutableSetOf(), XteaKey::fromIntArray)
val keys = call.receive<Array<IntArray>>().mapTo(mutableSetOf(), SymmetricKey::fromIntArray)
if (keys.isNotEmpty()) {
importer.import(keys, KeySource.API)

@ -7,7 +7,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap
import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMaps
import org.openrs2.buffer.crc32
import org.openrs2.buffer.use
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.crypto.whirlpool
import org.openrs2.util.krHashCode
import java.io.FileNotFoundException
@ -23,7 +23,7 @@ public abstract class Archive internal constructor(
internal inner class Unpacked(
private val entry: Js5Index.MutableGroup,
val key: XteaKey,
val key: SymmetricKey,
private var files: Int2ObjectSortedMap<ByteBuf>
) {
private var dirty = false
@ -193,7 +193,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun read(group: Int, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(group: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
require(group >= 0 && file >= 0)
val entry = index[group] ?: throw FileNotFoundException()
@ -202,19 +202,19 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun readNamed(groupNameHash: Int, fileNameHash: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun readNamed(groupNameHash: Int, fileNameHash: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
val entry = index.getNamed(groupNameHash) ?: throw FileNotFoundException()
val unpacked = getUnpacked(entry, key)
return unpacked.readNamed(fileNameHash)
}
@JvmOverloads
public fun read(group: String, file: String, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(group: String, file: String, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
return readNamed(group.krHashCode(), file.krHashCode(), key)
}
@JvmOverloads
public fun readNamedGroup(groupNameHash: Int, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun readNamedGroup(groupNameHash: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
require(file >= 0)
val entry = index.getNamed(groupNameHash) ?: throw FileNotFoundException()
@ -223,12 +223,12 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun read(group: String, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(group: String, file: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
return readNamedGroup(group.krHashCode(), file, key)
}
@JvmOverloads
public fun write(group: Int, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(group: Int, file: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
require(group >= 0 && file >= 0)
val entry = index.createOrGet(group)
@ -239,7 +239,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun writeNamed(groupNameHash: Int, fileNameHash: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun writeNamed(groupNameHash: Int, fileNameHash: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
val entry = index.createOrGetNamed(groupNameHash)
val unpacked = createOrGetUnpacked(entry, key, isOverwritingNamed(entry, fileNameHash))
unpacked.writeNamed(fileNameHash, buf)
@ -249,12 +249,12 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun write(group: String, file: String, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(group: String, file: String, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
return writeNamed(group.krHashCode(), file.krHashCode(), buf, key)
}
@JvmOverloads
public fun writeNamedGroup(groupNameHash: Int, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun writeNamedGroup(groupNameHash: Int, file: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
require(file >= 0)
val entry = index.createOrGetNamed(groupNameHash)
@ -266,7 +266,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun write(group: String, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(group: String, file: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
return writeNamedGroup(group.krHashCode(), file, buf, key)
}
@ -293,7 +293,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun remove(group: Int, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun remove(group: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
require(group >= 0 && file >= 0)
val entry = index[group] ?: return
@ -310,7 +310,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun removeNamed(groupNameHash: Int, fileNameHash: Int, key: XteaKey = XteaKey.ZERO) {
public fun removeNamed(groupNameHash: Int, fileNameHash: Int, key: SymmetricKey = SymmetricKey.ZERO) {
val entry = index.getNamed(groupNameHash) ?: return
if (isOverwritingNamed(entry, fileNameHash)) {
@ -325,12 +325,12 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun remove(group: String, file: String, key: XteaKey = XteaKey.ZERO) {
public fun remove(group: String, file: String, key: SymmetricKey = SymmetricKey.ZERO) {
return removeNamed(group.krHashCode(), file.krHashCode(), key)
}
@JvmOverloads
public fun removeNamedGroup(groupNameHash: Int, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun removeNamedGroup(groupNameHash: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
require(file >= 0)
val entry = index.getNamed(groupNameHash) ?: return
@ -347,7 +347,7 @@ public abstract class Archive internal constructor(
}
@JvmOverloads
public fun remove(group: String, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun remove(group: String, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
removeNamedGroup(group.krHashCode(), file, key)
}
@ -388,7 +388,7 @@ public abstract class Archive internal constructor(
return fileEntry.nameHash == fileNameHash
}
private fun createOrGetUnpacked(entry: Js5Index.MutableGroup, key: XteaKey, overwrite: Boolean): Unpacked {
private fun createOrGetUnpacked(entry: Js5Index.MutableGroup, key: SymmetricKey, overwrite: Boolean): Unpacked {
return if (entry.size == 0 || overwrite) {
val unpacked = Unpacked(entry, key, Int2ObjectAVLTreeMap())
unpackedCache.put(archive, entry.id, unpacked)
@ -398,7 +398,7 @@ public abstract class Archive internal constructor(
}
}
private fun getUnpacked(entry: Js5Index.MutableGroup, key: XteaKey): Unpacked {
private fun getUnpacked(entry: Js5Index.MutableGroup, key: SymmetricKey): Unpacked {
var unpacked = unpackedCache.get(archive, entry.id)
if (unpacked != null) {
/*

@ -3,7 +3,7 @@ package org.openrs2.cache
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufAllocator
import org.openrs2.buffer.use
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.util.krHashCode
import java.io.Closeable
import java.io.FileNotFoundException
@ -142,35 +142,45 @@ public class Cache private constructor(
}
@JvmOverloads
public fun read(archive: Int, group: Int, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(archive: Int, group: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
checkArchive(archive)
return archives[archive]?.read(group, file, key) ?: throw FileNotFoundException()
}
@JvmOverloads
public fun readNamed(archive: Int, groupNameHash: Int, fileNameHash: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun readNamed(
archive: Int,
groupNameHash: Int,
fileNameHash: Int,
key: SymmetricKey = SymmetricKey.ZERO
): ByteBuf {
checkArchive(archive)
return archives[archive]?.readNamed(groupNameHash, fileNameHash, key) ?: throw FileNotFoundException()
}
@JvmOverloads
public fun read(archive: Int, group: String, file: String, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(archive: Int, group: String, file: String, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
return readNamed(archive, group.krHashCode(), file.krHashCode(), key)
}
@JvmOverloads
public fun readNamedGroup(archive: Int, groupNameHash: Int, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun readNamedGroup(
archive: Int,
groupNameHash: Int,
file: Int,
key: SymmetricKey = SymmetricKey.ZERO
): ByteBuf {
checkArchive(archive)
return archives[archive]?.readNamedGroup(groupNameHash, file, key) ?: throw FileNotFoundException()
}
@JvmOverloads
public fun read(archive: Int, group: String, file: Int, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun read(archive: Int, group: String, file: Int, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
return readNamedGroup(archive, group.krHashCode(), file, key)
}
@JvmOverloads
public fun write(archive: Int, group: Int, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(archive: Int, group: Int, file: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
checkArchive(archive)
createOrGetArchive(archive).write(group, file, buf, key)
}
@ -181,25 +191,31 @@ public class Cache private constructor(
groupNameHash: Int,
fileNameHash: Int,
buf: ByteBuf,
key: XteaKey = XteaKey.ZERO
key: SymmetricKey = SymmetricKey.ZERO
) {
checkArchive(archive)
createOrGetArchive(archive).writeNamed(groupNameHash, fileNameHash, buf, key)
}
@JvmOverloads
public fun write(archive: Int, group: String, file: String, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(archive: Int, group: String, file: String, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
writeNamed(archive, group.krHashCode(), file.krHashCode(), buf, key)
}
@JvmOverloads
public fun writeNamedGroup(archive: Int, groupNameHash: Int, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun writeNamedGroup(
archive: Int,
groupNameHash: Int,
file: Int,
buf: ByteBuf,
key: SymmetricKey = SymmetricKey.ZERO
) {
checkArchive(archive)
createOrGetArchive(archive).writeNamedGroup(groupNameHash, file, buf, key)
}
@JvmOverloads
public fun write(archive: Int, group: String, file: Int, buf: ByteBuf, key: XteaKey = XteaKey.ZERO) {
public fun write(archive: Int, group: String, file: Int, buf: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO) {
writeNamedGroup(archive, group.krHashCode(), file, buf, key)
}
@ -233,30 +249,30 @@ public class Cache private constructor(
}
@JvmOverloads
public fun remove(archive: Int, group: Int, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun remove(archive: Int, group: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
checkArchive(archive)
archives[archive]?.remove(group, file, key)
}
@JvmOverloads
public fun removeNamed(archive: Int, groupNameHash: Int, fileNameHash: Int, key: XteaKey = XteaKey.ZERO) {
public fun removeNamed(archive: Int, groupNameHash: Int, fileNameHash: Int, key: SymmetricKey = SymmetricKey.ZERO) {
checkArchive(archive)
archives[archive]?.removeNamed(groupNameHash, fileNameHash, key)
}
@JvmOverloads
public fun remove(archive: Int, group: String, file: String, key: XteaKey = XteaKey.ZERO) {
public fun remove(archive: Int, group: String, file: String, key: SymmetricKey = SymmetricKey.ZERO) {
return removeNamed(archive, group.krHashCode(), file.krHashCode(), key)
}
@JvmOverloads
public fun removeNamedGroup(archive: Int, groupNameHash: Int, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun removeNamedGroup(archive: Int, groupNameHash: Int, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
checkArchive(archive)
archives[archive]?.removeNamedGroup(groupNameHash, file, key)
}
@JvmOverloads
public fun remove(archive: Int, group: String, file: Int, key: XteaKey = XteaKey.ZERO) {
public fun remove(archive: Int, group: String, file: Int, key: SymmetricKey = SymmetricKey.ZERO) {
removeNamedGroup(archive, group.krHashCode(), file, key)
}

@ -4,7 +4,7 @@ import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufInputStream
import io.netty.buffer.ByteBufOutputStream
import org.openrs2.buffer.use
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import org.openrs2.crypto.xteaDecrypt
import org.openrs2.crypto.xteaEncrypt
import java.io.IOException
@ -19,7 +19,7 @@ public object Js5Compression {
private const val LZMA_PRESET_DICT_SIZE_MAX = 1 shl 26
@JvmOverloads
public fun compress(input: ByteBuf, type: Js5CompressionType, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun compress(input: ByteBuf, type: Js5CompressionType, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
input.alloc().buffer().use { output ->
output.writeByte(type.ordinal)
@ -62,7 +62,7 @@ public object Js5Compression {
input: ByteBuf,
enableLzma: Boolean = false,
enableUncompressedEncryption: Boolean = false,
key: XteaKey = XteaKey.ZERO
key: SymmetricKey = SymmetricKey.ZERO
): ByteBuf {
val types = mutableListOf(Js5CompressionType.BZIP2, Js5CompressionType.GZIP)
if (enableLzma) {
@ -109,7 +109,7 @@ public object Js5Compression {
}
@JvmOverloads
public fun uncompress(input: ByteBuf, key: XteaKey = XteaKey.ZERO): ByteBuf {
public fun uncompress(input: ByteBuf, key: SymmetricKey = SymmetricKey.ZERO): ByteBuf {
if (input.readableBytes() < 5) {
throw IOException("Missing header")
}
@ -169,10 +169,10 @@ public object Js5Compression {
}
public fun uncompressUnlessEncrypted(input: ByteBuf): ByteBuf? {
return uncompressIfKeyValid(input, XteaKey.ZERO)
return uncompressIfKeyValid(input, SymmetricKey.ZERO)
}
public fun uncompressIfKeyValid(input: ByteBuf, key: XteaKey): ByteBuf? {
public fun uncompressIfKeyValid(input: ByteBuf, key: SymmetricKey): ByteBuf? {
if (input.readableBytes() < 5) {
throw IOException("Missing header")
}
@ -360,7 +360,7 @@ public object Js5Compression {
}
}
private fun decrypt(buf: ByteBuf, len: Int, key: XteaKey): ByteBuf {
private fun decrypt(buf: ByteBuf, len: Int, key: SymmetricKey): ByteBuf {
if (key.isZero) {
return buf.readRetainedSlice(len)
}

@ -4,7 +4,7 @@ import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import org.openrs2.buffer.copiedBuffer
import org.openrs2.buffer.use
import org.openrs2.crypto.XteaKey
import org.openrs2.crypto.SymmetricKey
import java.io.IOException
import kotlin.test.Test
import kotlin.test.assertEquals
@ -276,7 +276,7 @@ class Js5CompressionTest {
}
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO)?.release()
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO)?.release()
}
}
}
@ -289,7 +289,7 @@ class Js5CompressionTest {
}
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO)?.release()
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO)?.release()
}
}
}
@ -301,7 +301,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -315,7 +315,7 @@ class Js5CompressionTest {
}
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO)?.release()
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO)?.release()
}
}
}
@ -327,7 +327,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -340,7 +340,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -353,7 +353,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -366,7 +366,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -379,7 +379,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -392,7 +392,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { uncompressed ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { uncompressed ->
assertNull(uncompressed)
}
}
@ -406,7 +406,7 @@ class Js5CompressionTest {
assertEquals(expected, actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertEquals(expected, actual)
}
@ -429,7 +429,7 @@ class Js5CompressionTest {
assertEquals(expected, actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertEquals(expected, actual)
}
@ -447,7 +447,7 @@ class Js5CompressionTest {
assertNull(actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
@ -462,7 +462,7 @@ class Js5CompressionTest {
}
read("bzip2-invalid-magic.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
@ -476,7 +476,7 @@ class Js5CompressionTest {
assertEquals(expected, actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertEquals(expected, actual)
}
@ -494,7 +494,7 @@ class Js5CompressionTest {
assertNull(actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
@ -509,13 +509,13 @@ class Js5CompressionTest {
}
read("gzip-invalid-magic.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
read("gzip-invalid-method.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
@ -529,7 +529,7 @@ class Js5CompressionTest {
assertEquals(expected, actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertEquals(expected, actual)
}
@ -547,7 +547,7 @@ class Js5CompressionTest {
assertNull(actual)
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
@ -562,19 +562,19 @@ class Js5CompressionTest {
}
read("lzma-dict-size-negative.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
read("lzma-dict-size-larger-than-preset.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
read("lzma-invalid-pb.dat").use { compressed ->
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
@ -584,7 +584,7 @@ class Js5CompressionTest {
fun testKeyValidShorterThanTwoBlocks() {
read("shorter-than-two-blocks.dat").use { compressed ->
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO)?.release()
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO)?.release()
}
}
}
@ -597,7 +597,7 @@ class Js5CompressionTest {
}
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO)?.release()
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO)?.release()
}
}
}
@ -609,7 +609,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
@ -622,7 +622,7 @@ class Js5CompressionTest {
Js5Compression.uncompress(compressed.slice()).release()
}
Js5Compression.uncompressIfKeyValid(compressed.slice(), XteaKey.ZERO).use { actual ->
Js5Compression.uncompressIfKeyValid(compressed.slice(), SymmetricKey.ZERO).use { actual ->
assertNull(actual)
}
}
@ -719,7 +719,7 @@ class Js5CompressionTest {
read("missing-header.dat").use { compressed ->
assertFailsWith<IOException> {
Js5Compression.uncompressIfKeyValid(compressed, XteaKey.ZERO)
Js5Compression.uncompressIfKeyValid(compressed, SymmetricKey.ZERO)
}
}
@ -737,7 +737,7 @@ class Js5CompressionTest {
}
private companion object {
private val KEY = XteaKey.fromHex("00112233445566778899AABBCCDDEEFF")
private val INVALID_KEY = XteaKey.fromHex("0123456789ABCDEF0123456789ABCDEF")
private val KEY = SymmetricKey.fromHex("00112233445566778899AABBCCDDEEFF")
private val INVALID_KEY = SymmetricKey.fromHex("0123456789ABCDEF0123456789ABCDEF")
}
}

@ -6,7 +6,7 @@ import jakarta.inject.Singleton
@Singleton
public class CryptoJacksonModule : SimpleModule() {
init {
addDeserializer(XteaKey::class.java, XteaKeyDeserializer)
addSerializer(XteaKey::class.java, XteaKeySerializer)
addDeserializer(SymmetricKey::class.java, SymmetricKeyDeserializer)
addSerializer(SymmetricKey::class.java, SymmetricKeySerializer)
}
}

@ -2,7 +2,7 @@ package org.openrs2.crypto
import java.security.SecureRandom
public data class XteaKey(
public data class SymmetricKey(
public val k0: Int,
public val k1: Int,
public val k2: Int,
@ -28,28 +28,28 @@ public data class XteaKey(
public companion object {
@JvmStatic
public val ZERO: XteaKey = XteaKey(0, 0, 0, 0)
public val ZERO: SymmetricKey = SymmetricKey(0, 0, 0, 0)
@JvmStatic
@JvmOverloads
public fun generate(r: SecureRandom = secureRandom): XteaKey {
return XteaKey(r.nextInt(), r.nextInt(), r.nextInt(), r.nextInt())
public fun generate(r: SecureRandom = secureRandom): SymmetricKey {
return SymmetricKey(r.nextInt(), r.nextInt(), r.nextInt(), r.nextInt())
}
@JvmStatic
public fun fromIntArray(a: IntArray): XteaKey {
public fun fromIntArray(a: IntArray): SymmetricKey {
require(a.size == 4)
return XteaKey(a[0], a[1], a[2], a[3])
return SymmetricKey(a[0], a[1], a[2], a[3])
}
@JvmStatic
public fun fromHex(s: String): XteaKey {
public fun fromHex(s: String): SymmetricKey {
return fromHexOrNull(s) ?: throw IllegalArgumentException()
}
@JvmStatic
public fun fromHexOrNull(s: String): XteaKey? {
public fun fromHexOrNull(s: String): SymmetricKey? {
if (s.length != 32) {
return null
}
@ -60,7 +60,7 @@ public data class XteaKey(
val k2 = Integer.parseUnsignedInt(s, 16, 24, 16)
val k3 = Integer.parseUnsignedInt(s, 24, 32, 16)
XteaKey(k0, k1, k2, k3)
SymmetricKey(k0, k1, k2, k3)
} catch (ex: NumberFormatException) {
null
}

@ -4,8 +4,8 @@ import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
public object XteaKeyDeserializer : StdDeserializer<XteaKey>(XteaKey::class.java) {
override fun deserialize(parser: JsonParser, ctx: DeserializationContext): XteaKey {
return XteaKey.fromIntArray(ctx.readValue(parser, IntArray::class.java))
public object SymmetricKeyDeserializer : StdDeserializer<SymmetricKey>(SymmetricKey::class.java) {
override fun deserialize(parser: JsonParser, ctx: DeserializationContext): SymmetricKey {
return SymmetricKey.fromIntArray(ctx.readValue(parser, IntArray::class.java))
}
}