diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bbbe93a..786e675 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] infendro = "1.1.0" kotlin = "2.3.0" -bytes = "1.4.0" -hash = "1.6.0" +bytes = "1.4.1" +hash = "1.7.0" [plugins] infendro = { id = "com.infendro.plugin", version.ref = "infendro" } diff --git a/src/commonMain/kotlin/com/infendro/mac/HMAC.kt b/src/commonMain/kotlin/com/infendro/mac/HMAC.kt index 3e42e7d..dd9b10b 100644 --- a/src/commonMain/kotlin/com/infendro/mac/HMAC.kt +++ b/src/commonMain/kotlin/com/infendro/mac/HMAC.kt @@ -5,29 +5,59 @@ import com.infendro.hash.HashFunction class HMAC( val function: HashFunction, -) : MAC { - override val bytes: Int - get() = function.bytes +) : MAC(function.bytes) { + private var initialized = false + private val innerPadding: ByteArray = ByteArray(function.block) + private val outerPadding: ByteArray = ByteArray(function.block) + private val inner: ByteArray = ByteArray(function.bytes) - override fun hashInto(key: ByteArray, value: ByteArray, destination: ByteArray, destinationOffset: Int) { - val paddedKey = pad(key) - val inner = ByteArray(function.block + value.size).also { - paddedKey.xorInto(0x36, it) - value.copyInto(it, function.block) - } - val outer = ByteArray(function.block + function.bytes).also { - paddedKey.xorInto(0x5C, it) - function.hashInto(inner, it, function.block) - } - function.hashInto(outer, destination, destinationOffset) + override fun reset() { + function.reset() + initialized = false + innerPadding.fill(0x00) + outerPadding.fill(0x00) + } + + override fun init(key: ByteArray) { + val padded = pad(key) + padded.xorInto(0x36, innerPadding) + padded.xorInto(0x5C, outerPadding) + + function.reset() + function.update(innerPadding) + + initialized = true + } + + override fun update(byte: Byte) { + require(initialized) + + function.update(byte) + } + + override fun update(bytes: ByteArray) { + require(initialized) + + function.update(bytes) + } + + override fun digestInto(destination: ByteArray, destinationOffset: Int) { + require(initialized) + + function.digestInto(inner) + function.update(outerPadding) + function.update(inner) + function.digestInto(destination, destinationOffset) + + function.update(innerPadding) } private fun pad(key: ByteArray): ByteArray { - return ByteArray(function.block).also { - when { - key.size > function.block -> function.hashInto(key, it) - else -> key.copyInto(it) - } + val padded = ByteArray(function.block) + when { + key.size > function.block -> function.hashInto(key, padded) + else -> key.copyInto(padded) } + return padded } } diff --git a/src/commonMain/kotlin/com/infendro/mac/MAC.kt b/src/commonMain/kotlin/com/infendro/mac/MAC.kt index 7d90d41..289799a 100644 --- a/src/commonMain/kotlin/com/infendro/mac/MAC.kt +++ b/src/commonMain/kotlin/com/infendro/mac/MAC.kt @@ -1,15 +1,38 @@ package com.infendro.mac -interface MAC { - val bytes: Int +abstract class MAC( + val bytes: Int, +) { val bits: Int get() = bytes * 8 - fun hashInto(key: ByteArray, value: ByteArray, destination: ByteArray, destinationOffset: Int = 0) + abstract fun reset() + + abstract fun init(key: ByteArray) + + abstract fun update(byte: Byte) + abstract fun update(bytes: ByteArray) + + abstract fun digestInto(destination: ByteArray, destinationOffset: Int = 0) + + fun digest(): ByteArray { + val result = ByteArray(bytes) + digestInto(result) + return result + } + + fun hashInto(key: ByteArray, value: ByteArray, destination: ByteArray, destinationOffset: Int = 0) { + init(key) + update(value) + digestInto(destination, destinationOffset) + reset() + } fun hash(key: ByteArray, value: ByteArray): ByteArray { - val result = ByteArray(bytes) - hashInto(key, value, result) + init(key) + update(value) + val result = digest() + reset() return result } } diff --git a/src/commonTest/kotlin/com/infendro/mac/HMAC.kt b/src/commonTest/kotlin/com/infendro/mac/HMAC.kt index dec7dda..0c7edb7 100644 --- a/src/commonTest/kotlin/com/infendro/mac/HMAC.kt +++ b/src/commonTest/kotlin/com/infendro/mac/HMAC.kt @@ -6,7 +6,7 @@ import kotlin.test.assertContentEquals import kotlin.test.assertEquals class `HMAC Test` { - val hmac = HMAC(`SHA-256`) + val hmac = HMAC(`SHA-256`()) @Test fun bytes() {