diff --git a/README.md b/README.md index 905c879..23e2d9b 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,10 @@ # mac-kt -`mac-kt` is a Kotlin Multiplatform library that provides common [Message Authentication Code](https://en.wikipedia.org/wiki/Message_authentication_code) algorithms. +`mac-kt` is a Kotlin Multiplatform library that provides common [Message Authentication Codes](https://en.wikipedia.org/wiki/Message_authentication_code). Supported algorithms: - HMAC -## Targets - -| Target | Status | -|------------------|---------------| -| JVM | Supported | -| JavaScript | Supported | -| Native (Linux) | Supported | -| Native (Windows) | Not Supported | - ## Installation Add the following to your `build.gradle.kts`. @@ -31,18 +22,13 @@ dependencies { ## Usage ```kotlin -import com.infendro.hash.sha1.SHA1 -import com.infendro.mac.HMAC - fun main() { // create an HMAC instance using SHA1 val hmac = HMAC(SHA1) // generate MAC - val key = "secret" - .encodeToByteArray().asUByteArray() - val value = "Hello World!" - .encodeToByteArray().asUByteArray() + val key = "secret".encodeToByteArray() + val value = "Hello World!".encodeToByteArray() val mac = hmac.hash(key, value) } ``` diff --git a/build.gradle.kts b/build.gradle.kts index 285c4cd..46874c8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.hash) - implementation(libs.bytearray) + implementation(libs.bytes) } commonTest.dependencies { implementation(libs.test) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4b5468d..627e5eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] -infendro = "1.0.0" -kotlin = "2.2.21" -hash = "1.3.2" -bytearray = "1.2.4" +infendro = "1.1.0" +kotlin = "2.3.0" +hash = "1.5.1" +bytes = "1.3.3" [plugins] infendro = { id = "com.infendro.plugin", version.ref = "infendro" } @@ -10,5 +10,5 @@ multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotl [libraries] hash = { module = "com.infendro:hash", version.ref = "hash" } -bytearray = { module = "com.infendro:bytearray", version.ref = "bytearray" } +bytes = { module = "com.infendro:bytes", version.ref = "bytes" } test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } diff --git a/src/commonMain/kotlin/com/infendro/mac/HMAC.kt b/src/commonMain/kotlin/com/infendro/mac/HMAC.kt index 6d28138..922eef1 100644 --- a/src/commonMain/kotlin/com/infendro/mac/HMAC.kt +++ b/src/commonMain/kotlin/com/infendro/mac/HMAC.kt @@ -1,6 +1,6 @@ package com.infendro.mac -import com.infendro.bytearray.padEnd +import com.infendro.bytes.bytearray.xorInto import com.infendro.hash.HashFunction class HMAC( @@ -9,25 +9,24 @@ class HMAC( override val bytes: Int get() = function.bytes - override fun hash( - key: UByteArray, - value: UByteArray, - ): UByteArray { + override fun hashInto(key: ByteArray, value: ByteArray, destination: ByteArray, destinationOffset: Int) { val paddedKey = pad(key) - - val innerKey = paddedKey.map { it xor 0x36U }.toUByteArray() - val outerKey = paddedKey.map { it xor 0x5CU }.toUByteArray() - - return function.hash(outerKey + function.hash(innerKey + value)) - } - - private fun pad( - key: UByteArray, - ): UByteArray { - return when { - key.size > function.block -> function.hash(key) - key.size < function.block -> key.padEnd(function.block, 0x00U) - else -> 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) } + + private fun pad(key: ByteArray): ByteArray = + ByteArray(function.block).also { + when { + key.size > function.block -> function.hashInto(key, it) + else -> key.copyInto(it) + } + } } diff --git a/src/commonMain/kotlin/com/infendro/mac/MAC.kt b/src/commonMain/kotlin/com/infendro/mac/MAC.kt index 686a46b..0069681 100644 --- a/src/commonMain/kotlin/com/infendro/mac/MAC.kt +++ b/src/commonMain/kotlin/com/infendro/mac/MAC.kt @@ -5,8 +5,20 @@ interface MAC { val bits: Int get() = bytes * 8 - fun hash( - key: UByteArray, - value: UByteArray, - ): UByteArray + fun hashInto(key: ByteArray, value: ByteArray, destination: ByteArray, destinationOffset: Int = 0) + + fun hashInto(key: ByteArray, value: ByteArray, destination: UByteArray, destinationOffset: Int = 0) = + hashInto(key, value, destination.asByteArray(), destinationOffset) + + fun hashInto(key: UByteArray, value: UByteArray, destination: ByteArray, destinationOffset: Int = 0) = + hashInto(key.asByteArray(), value.asByteArray(), destination, destinationOffset) + + fun hashInto(key: UByteArray, value: UByteArray, destination: UByteArray, destinationOffset: Int = 0) = + hashInto(key.asByteArray(), value.asByteArray(), destination.asByteArray(), destinationOffset) + + fun hash(key: ByteArray, value: ByteArray): ByteArray = + ByteArray(bytes).also { hashInto(key, value, it) } + + fun hash(key: UByteArray, value: UByteArray): UByteArray = + UByteArray(bytes).also { hashInto(key, value, it) } } diff --git a/src/commonTest/kotlin/com/infendro/mac/HMAC.kt b/src/commonTest/kotlin/com/infendro/mac/HMAC.kt index a88670a..2964ec3 100644 --- a/src/commonTest/kotlin/com/infendro/mac/HMAC.kt +++ b/src/commonTest/kotlin/com/infendro/mac/HMAC.kt @@ -1,6 +1,5 @@ package com.infendro.mac -import com.infendro.bytearray.encodeToUByteArray import com.infendro.hash.sha2.`SHA-256` import kotlin.test.Test import kotlin.test.assertContentEquals @@ -16,22 +15,21 @@ class `HMAC Test` { } @Test - fun `example`() { - assertContentEquals( - ubyteArrayOf( - 0xf7U, 0xbcU, 0x83U, 0xf4U, - 0x30U, 0x53U, 0x84U, 0x24U, - 0xb1U, 0x32U, 0x98U, 0xe6U, - 0xaaU, 0x6fU, 0xb1U, 0x43U, - 0xefU, 0x4dU, 0x59U, 0xa1U, - 0x49U, 0x46U, 0x17U, 0x59U, - 0x97U, 0x47U, 0x9dU, 0xbcU, - 0x2dU, 0x1aU, 0x3cU, 0xd8U, - ), - hmac.hash( - "key".encodeToUByteArray(), - "The quick brown fox jumps over the lazy dog".encodeToUByteArray() - ) + fun example() { + val expected = ubyteArrayOf( + 0xf7U, 0xbcU, 0x83U, 0xf4U, + 0x30U, 0x53U, 0x84U, 0x24U, + 0xb1U, 0x32U, 0x98U, 0xe6U, + 0xaaU, 0x6fU, 0xb1U, 0x43U, + 0xefU, 0x4dU, 0x59U, 0xa1U, + 0x49U, 0x46U, 0x17U, 0x59U, + 0x97U, 0x47U, 0x9dU, 0xbcU, + 0x2dU, 0x1aU, 0x3cU, 0xd8U, + ).asByteArray() + val actual = hmac.hash( + "key".encodeToByteArray(), + "The quick brown fox jumps over the lazy dog".encodeToByteArray(), ) + assertContentEquals(expected, actual) } }