From 667fba9bdf63e39d1a8382c02a6672586ababe71 Mon Sep 17 00:00:00 2001 From: Infendro Date: Wed, 11 Mar 2026 22:57:43 +0100 Subject: [PATCH 1/2] Implement streaming API --- gradle/libs.versions.toml | 4 +- .../kotlin/com/infendro/mac/HMAC.kt | 68 +++++++++++++------ src/commonMain/kotlin/com/infendro/mac/MAC.kt | 33 +++++++-- .../kotlin/com/infendro/mac/HMAC.kt | 2 +- 4 files changed, 80 insertions(+), 27 deletions(-) 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() { -- 2.49.1 From 1f31ea95094cc30219cd4d9f02ef6228a671e16b Mon Sep 17 00:00:00 2001 From: Infendro Date: Wed, 11 Mar 2026 22:58:59 +0100 Subject: [PATCH 2/2] Bump version to 1.5.0 --- README.md | 4 ++-- build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2b1a4b3..f869a51 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ repositories { } dependencies { - implementation("com.infendro:mac:1.4.0") + implementation("com.infendro:mac:1.5.0") } ``` @@ -24,7 +24,7 @@ dependencies { ```kotlin fun main() { // create an HMAC instance using SHA1 - val hmac = HMAC(SHA1) + val hmac = HMAC(SHA1()) // generate MAC val key = "secret".encodeToByteArray() diff --git a/build.gradle.kts b/build.gradle.kts index eadff65..887093e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ import com.infendro.plugin.token import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl group = "com.infendro" -version = "1.4.0" +version = "1.5.0" plugins { alias(libs.plugins.infendro) -- 2.49.1