Skip to content

Commit 1ac1dca

Browse files
authored
Fix Mac.doFinal not calling engine.reset for nonJvm (#27)
1 parent 94b2d6f commit 1ac1dca

File tree

2 files changed

+70
-14
lines changed
  • library/mac/src

2 files changed

+70
-14
lines changed

library/mac/src/commonTest/kotlin/org/kotlincrypto/core/MacUnitTest.kt

+49-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.kotlincrypto.core
1717

1818
import kotlin.test.Test
19+
import kotlin.test.assertEquals
1920
import kotlin.test.assertNotEquals
2021
import kotlin.test.fail
2122

@@ -25,30 +26,48 @@ class MacUnitTest {
2526
@OptIn(InternalKotlinCryptoApi::class)
2627
private class TestMac : Mac {
2728

28-
constructor(key: ByteArray, algorithm: String): super(algorithm, TestEngine(key))
29+
constructor(
30+
key: ByteArray,
31+
algorithm: String,
32+
reset: () -> Unit = {},
33+
doFinal: () -> ByteArray = { ByteArray(0) },
34+
): super(algorithm, TestEngine(key, reset, doFinal))
35+
2936
private constructor(algorithm: String, engine: TestEngine): super(algorithm, engine)
3037

3138
override fun copy(engineCopy: Engine): Mac = TestMac(algorithm(), engineCopy as TestEngine)
3239

3340
private class TestEngine: Engine {
3441

35-
constructor(key: ByteArray): super(key)
36-
private constructor(state: State): super(state)
42+
private val reset: () -> Unit
43+
private val doFinal: () -> ByteArray
44+
45+
constructor(
46+
key: ByteArray,
47+
reset: () -> Unit,
48+
doFinal: () -> ByteArray,
49+
): super(key) {
50+
this.reset = reset
51+
this.doFinal = doFinal
52+
}
53+
54+
private constructor(state: State, engine: TestEngine): super(state) {
55+
this.reset = engine.reset
56+
this.doFinal = engine.doFinal
57+
}
3758

3859
// To ensure that Java implementation initializes javax.crypto.Mac
3960
// on instantiation so that it does not throw IllegalStateException
4061
// whenever updating.
4162
override fun update(input: Byte) { throw ConcurrentModificationException() }
4263

43-
override fun reset() {}
64+
override fun reset() { reset.invoke() }
4465
override fun update(input: ByteArray) {}
4566
override fun update(input: ByteArray, offset: Int, len: Int) {}
4667
override fun macLength(): Int = 0
47-
override fun doFinal(): ByteArray = ByteArray(0)
48-
49-
override fun copy(): Engine = TestEngine(TestState())
68+
override fun doFinal(): ByteArray = doFinal.invoke()
5069

51-
private inner class TestState: Engine.State()
70+
override fun copy(): Engine = TestEngine(object : State() {}, this)
5271
}
5372
}
5473

@@ -89,4 +108,26 @@ class MacUnitTest {
89108

90109
assertNotEquals(mac, copy)
91110
}
111+
112+
@Test
113+
fun givenMac_whenDoFinal_thenEngineResetIsCalled() {
114+
var resetCount = 0
115+
var doFinalCount = 0
116+
val finalExpected = ByteArray(20)
117+
118+
val mac = TestMac(
119+
ByteArray(5),
120+
"not blank",
121+
reset = { resetCount++ },
122+
doFinal = { doFinalCount++; finalExpected },
123+
)
124+
mac.update(ByteArray(20))
125+
assertEquals(finalExpected, mac.doFinal())
126+
assertEquals(1, doFinalCount)
127+
assertEquals(1, resetCount)
128+
129+
assertEquals(finalExpected, mac.doFinal(ByteArray(20)))
130+
assertEquals(2, doFinalCount)
131+
assertEquals(2, resetCount)
132+
}
92133
}

library/mac/src/nonJvmMain/kotlin/org/kotlincrypto/core/Mac.kt

+21-6
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,29 @@ protected actual constructor(
5454
public actual final override fun algorithm(): String = algorithm
5555
public actual fun macLength(): Int = engine.macLength()
5656

57-
public actual final override fun update(input: Byte) { engine.update(input) }
58-
public actual final override fun update(input: ByteArray) { engine.update(input) }
59-
public actual final override fun update(input: ByteArray, offset: Int, len: Int) { engine.update(input, offset, len) }
57+
public actual final override fun update(input: Byte) {
58+
engine.update(input)
59+
}
60+
public actual final override fun update(input: ByteArray) {
61+
engine.update(input)
62+
}
63+
public actual final override fun update(input: ByteArray, offset: Int, len: Int) {
64+
engine.update(input, offset, len)
65+
}
6066

61-
public actual final override fun reset() { engine.reset() }
67+
public actual fun doFinal(): ByteArray {
68+
val final = engine.doFinal()
69+
engine.reset()
70+
return final
71+
}
72+
public actual fun doFinal(input: ByteArray): ByteArray {
73+
engine.update(input)
74+
return doFinal()
75+
}
6276

63-
public actual fun doFinal(): ByteArray = engine.doFinal()
64-
public actual fun doFinal(input: ByteArray): ByteArray { engine.update(input); return doFinal() }
77+
public actual final override fun reset() {
78+
engine.reset()
79+
}
6580

6681
public actual final override fun copy(): Mac = copy(engine.copy())
6782
protected actual abstract fun copy(engineCopy: Engine): Mac

0 commit comments

Comments
 (0)