Add XteaKey inline class with ZERO "constant" and isZero method

Unfortunately we can't use the compiler to guarantee k isn't changed,
though making it internal will help. When the JVM (and Kotlin) get value
types, we might be able to improve on this (e.g. by making it an inline
class of four integers).

Signed-off-by: Graham <gpe@openrs2.dev>
pull/132/head
Graham 4 years ago
parent ce4de919b8
commit 95c97b8399
  1. 2
      build.gradle.kts
  2. 25
      crypto/src/main/java/dev/openrs2/crypto/Xtea.kt
  3. 4
      crypto/src/test/java/dev/openrs2/crypto/XteaTest.kt

@ -56,7 +56,7 @@ allprojects {
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {
kotlinOptions { kotlinOptions {
jvmTarget = "11" jvmTarget = "11"
freeCompilerArgs = listOf("-Xjsr305=strict") freeCompilerArgs = listOf("-Xinline-classes", "-Xjsr305=strict")
} }
} }

@ -7,8 +7,17 @@ private const val ROUNDS = 32
private const val BLOCK_SIZE = 8 private const val BLOCK_SIZE = 8
private const val BLOCK_SIZE_MASK = BLOCK_SIZE - 1 private const val BLOCK_SIZE_MASK = BLOCK_SIZE - 1
fun ByteBuf.xteaEncrypt(index: Int, length: Int, key: IntArray) { inline class XteaKey(internal val k: IntArray) {
require(key.size == 4) val isZero: Boolean
get() = k[0] == 0 && k[1] == 0 && k[2] == 0 && k[3] == 0
companion object {
val ZERO = XteaKey(IntArray(4))
}
}
fun ByteBuf.xteaEncrypt(index: Int, length: Int, key: XteaKey) {
require(key.k.size == 4)
val end = index + (length and BLOCK_SIZE_MASK.inv()) val end = index + (length and BLOCK_SIZE_MASK.inv())
for (i in index until end step BLOCK_SIZE) { for (i in index until end step BLOCK_SIZE) {
@ -17,9 +26,9 @@ fun ByteBuf.xteaEncrypt(index: Int, length: Int, key: IntArray) {
var v1 = getInt(i + 4) var v1 = getInt(i + 4)
for (j in 0 until ROUNDS) { for (j in 0 until ROUNDS) {
v0 += (((v1 shl 4) xor (v1 ushr 5)) + v1) xor (sum + key[sum and 3]) v0 += (((v1 shl 4) xor (v1 ushr 5)) + v1) xor (sum + key.k[sum and 3])
sum += GOLDEN_RATIO sum += GOLDEN_RATIO
v1 += (((v0 shl 4) xor (v0 ushr 5)) + v0) xor (sum + key[(sum ushr 11) and 3]) v1 += (((v0 shl 4) xor (v0 ushr 5)) + v0) xor (sum + key.k[(sum ushr 11) and 3])
} }
setInt(i, v0) setInt(i, v0)
@ -27,8 +36,8 @@ fun ByteBuf.xteaEncrypt(index: Int, length: Int, key: IntArray) {
} }
} }
fun ByteBuf.xteaDecrypt(index: Int, length: Int, key: IntArray) { fun ByteBuf.xteaDecrypt(index: Int, length: Int, key: XteaKey) {
require(key.size == 4) require(key.k.size == 4)
val end = index + (length and BLOCK_SIZE_MASK.inv()) val end = index + (length and BLOCK_SIZE_MASK.inv())
for (i in index until end step BLOCK_SIZE) { for (i in index until end step BLOCK_SIZE) {
@ -38,9 +47,9 @@ fun ByteBuf.xteaDecrypt(index: Int, length: Int, key: IntArray) {
var v1 = getInt(i + 4) var v1 = getInt(i + 4)
for (j in 0 until ROUNDS) { for (j in 0 until ROUNDS) {
v1 -= (((v0 shl 4) xor (v0 ushr 5)) + v0) xor (sum + key[(sum ushr 11) and 3]) v1 -= (((v0 shl 4) xor (v0 ushr 5)) + v0) xor (sum + key.k[(sum ushr 11) and 3])
sum -= GOLDEN_RATIO sum -= GOLDEN_RATIO
v0 -= (((v1 shl 4) xor (v1 ushr 5)) + v1) xor (sum + key[sum and 3]) v0 -= (((v1 shl 4) xor (v1 ushr 5)) + v1) xor (sum + key.k[sum and 3])
} }
setInt(i, v0) setInt(i, v0)

@ -8,9 +8,9 @@ import kotlin.test.assertEquals
object XteaTest { object XteaTest {
private class TestVector(key: String, plaintext: String, ciphertext: String) { private class TestVector(key: String, plaintext: String, ciphertext: String) {
val key = IntArray(4) { val key = XteaKey(IntArray(4) {
Integer.parseUnsignedInt(key, it * 8, it * 8 + 8, 16) Integer.parseUnsignedInt(key, it * 8, it * 8 + 8, 16)
} })
val plaintext: ByteArray = ByteBufUtil.decodeHexDump(plaintext) val plaintext: ByteArray = ByteBufUtil.decodeHexDump(plaintext)
val ciphertext: ByteArray = ByteBufUtil.decodeHexDump(ciphertext) val ciphertext: ByteArray = ByteBufUtil.decodeHexDump(ciphertext)
} }

Loading…
Cancel
Save