Skip to content

Commit 96f1ccc

Browse files
committed
Return reset for hash/signature functions
1 parent b1856dc commit 96f1ccc

File tree

18 files changed

+236
-109
lines changed

18 files changed

+236
-109
lines changed

cryptography-core/api/cryptography-core.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ public abstract interface class dev/whyoleg/cryptography/operations/SignatureVer
866866
}
867867

868868
public abstract interface class dev/whyoleg/cryptography/operations/UpdateFunction : java/lang/AutoCloseable {
869+
public abstract fun reset ()V
869870
public fun update (Lkotlinx/io/RawSource;)V
870871
public fun update (Lkotlinx/io/bytestring/ByteString;II)V
871872
public abstract fun update ([BII)V

cryptography-core/api/cryptography-core.klib.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ abstract interface dev.whyoleg.cryptography.operations/SignatureVerifier { // de
685685
}
686686

687687
abstract interface dev.whyoleg.cryptography.operations/UpdateFunction : kotlin/AutoCloseable { // dev.whyoleg.cryptography.operations/UpdateFunction|null[0]
688+
abstract fun reset() // dev.whyoleg.cryptography.operations/UpdateFunction.reset|reset(){}[0]
688689
abstract fun update(kotlin/ByteArray, kotlin/Int = ..., kotlin/Int = ...) // dev.whyoleg.cryptography.operations/UpdateFunction.update|update(kotlin.ByteArray;kotlin.Int;kotlin.Int){}[0]
689690
open fun update(kotlinx.io.bytestring/ByteString, kotlin/Int = ..., kotlin/Int = ...) // dev.whyoleg.cryptography.operations/UpdateFunction.update|update(kotlinx.io.bytestring.ByteString;kotlin.Int;kotlin.Int){}[0]
690691
open fun update(kotlinx.io/RawSource) // dev.whyoleg.cryptography.operations/UpdateFunction.update|update(kotlinx.io.RawSource){}[0]

cryptography-core/src/commonMain/kotlin/operations/UpdateFunction.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import kotlinx.io.unsafe.*
1111

1212
@SubclassOptInRequired(CryptographyProviderApi::class)
1313
public interface UpdateFunction : AutoCloseable {
14+
public fun reset()
15+
1416
public fun update(source: ByteArray, startIndex: Int = 0, endIndex: Int = source.size)
1517
public fun update(source: ByteString, startIndex: Int = 0, endIndex: Int = source.size) {
1618
update(source.asByteArray(), startIndex, endIndex)

cryptography-providers-tests/src/commonMain/kotlin/default/DigestTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,33 @@ abstract class DigestTest(provider: CryptographyProvider) : ProviderTest(provide
9191
}
9292
}
9393

94+
@Test
95+
fun testFunctionReuse() = testAlgorithm(SHA256) {
96+
if (!supportsFunctions()) return@testAlgorithm
97+
98+
val hasher = algorithm.hasher()
99+
val bytes1 = ByteString(CryptographyRandom.nextBytes(10000))
100+
val bytes2 = ByteString(CryptographyRandom.nextBytes(10000))
101+
102+
val digest1 = hasher.hash(bytes1)
103+
val digest2 = hasher.hash(bytes2)
104+
hasher.createHashFunction().use { function ->
105+
function.update(bytes1)
106+
assertContentEquals(digest1, function.hash())
107+
108+
function.update(bytes2)
109+
assertContentEquals(digest2, function.hash())
110+
111+
// update and then discard
112+
function.update(bytes1)
113+
function.update(bytes1)
114+
function.reset()
115+
// update after reset
116+
function.update(bytes1)
117+
assertContentEquals(digest1, function.hash())
118+
}
119+
}
120+
94121
@Test
95122
fun testFunctionSource() = testAlgorithm(SHA256) {
96123
val hasher = algorithm.hasher()

cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCDigest.kt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,20 @@ internal class CCDigest<CTX : CPointed>(
1616
override val id: CryptographyAlgorithmId<Digest>,
1717
) : Hasher, Digest {
1818
override fun hasher(): Hasher = this
19-
override fun createHashFunction(): HashFunction {
20-
val context = hashAlgorithm.alloc()
21-
// TODO: error handle
22-
hashAlgorithm.ccInit(context)
23-
return CCHashFunction(
24-
algorithm = hashAlgorithm,
25-
context = Resource(context, nativeHeap::free)
26-
)
27-
}
19+
override fun createHashFunction(): HashFunction = CCHashFunction(
20+
algorithm = hashAlgorithm,
21+
context = Resource(hashAlgorithm.alloc(), nativeHeap::free)
22+
)
2823
}
2924

3025
private class CCHashFunction<CTX : CPointed>(
3126
private val algorithm: CCHashAlgorithm<CTX>,
3227
private val context: Resource<CPointer<CTX>>,
3328
) : HashFunction, SafeCloseable(SafeCloseAction(context, AutoCloseable::close)) {
29+
init {
30+
reset()
31+
}
32+
3433
override fun update(source: ByteArray, startIndex: Int, endIndex: Int) {
3534
checkBounds(source.size, startIndex, endIndex)
3635

@@ -47,7 +46,7 @@ private class CCHashFunction<CTX : CPointed>(
4746
destination.usePinned {
4847
check(algorithm.ccFinal(context, it.safeAddressOf(destinationOffset).reinterpret()) > 0)
4948
}
50-
close()
49+
reset()
5150
return algorithm.digestSize
5251
}
5352

@@ -56,4 +55,9 @@ private class CCHashFunction<CTX : CPointed>(
5655
hashIntoByteArray(output)
5756
return output
5857
}
58+
59+
override fun reset() {
60+
val context = context.access()
61+
check(algorithm.ccInit(context) > 0)
62+
}
5963
}

cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCHmac.kt

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,25 +83,26 @@ private class HmacSignature(
8383
private val key: ByteArray,
8484
private val digestSize: Int,
8585
) : SignatureGenerator, SignatureVerifier {
86-
87-
@OptIn(UnsafeNumber::class)
88-
private fun createFunction(): HmacFunction {
89-
val context = nativeHeap.alloc<CCHmacContext>().ptr
90-
// TODO: error handle?
91-
key.usePinned {
92-
CCHmacInit(context, hmacAlgorithm, it.safeAddressOf(0), key.size.convert())
93-
}
94-
return HmacFunction(digestSize, Resource(context, nativeHeap::free))
95-
}
86+
private fun createFunction() = HmacFunction(
87+
hmacAlgorithm = hmacAlgorithm,
88+
key = key,
89+
digestSize = digestSize,
90+
context = Resource(nativeHeap.alloc<CCHmacContext>().ptr, nativeHeap::free)
91+
)
9692

9793
override fun createSignFunction(): SignFunction = createFunction()
9894
override fun createVerifyFunction(): VerifyFunction = createFunction()
9995
}
10096

10197
private class HmacFunction(
98+
private val hmacAlgorithm: CCHmacAlgorithm,
99+
private val key: ByteArray,
102100
private val digestSize: Int,
103101
private val context: Resource<CPointer<CCHmacContext>>,
104102
) : SignFunction, VerifyFunction, SafeCloseable(SafeCloseAction(context, AutoCloseable::close)) {
103+
init {
104+
reset()
105+
}
105106

106107
@OptIn(UnsafeNumber::class)
107108
override fun update(source: ByteArray, startIndex: Int, endIndex: Int) {
@@ -120,7 +121,7 @@ private class HmacFunction(
120121
destination.usePinned {
121122
CCHmacFinal(context, it.safeAddressOf(destinationOffset))
122123
}
123-
close()
124+
reset()
124125
return digestSize
125126
}
126127

@@ -138,4 +139,12 @@ private class HmacFunction(
138139
override fun verify(signature: ByteArray, startIndex: Int, endIndex: Int) {
139140
check(tryVerify(signature, startIndex, endIndex)) { "Invalid signature" }
140141
}
142+
143+
@OptIn(UnsafeNumber::class)
144+
override fun reset() {
145+
val context = context.access()
146+
key.usePinned {
147+
CCHmacInit(context, hmacAlgorithm, it.safeAddressOf(0), key.size.convert())
148+
}
149+
}
141150
}

cryptography-providers/apple/src/commonMain/kotlin/algorithms/SecEcdsa.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ private class EcdsaRawSignatureGenerator(
278278
return rawSignature
279279
}
280280

281+
override fun reset() {
282+
derSignFunction.reset()
283+
}
284+
281285
override fun close() {
282286
derSignFunction.close()
283287
}
@@ -322,6 +326,10 @@ private class EcdsaRawSignatureVerifier(
322326
check(tryVerify(signature, startIndex, endIndex)) { "Invalid signature" }
323327
}
324328

329+
override fun reset() {
330+
derVerifyFunction.reset()
331+
}
332+
325333
override fun close() {
326334
derVerifyFunction.close()
327335
}

cryptography-providers/apple/src/commonMain/kotlin/internal/SecSignature.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,14 @@ private class SecVerifyFunction(
7070
else -> error.value.releaseBridgeAs<NSError>()?.description ?: ""
7171
}
7272
}
73+
}.also {
74+
reset()
7375
}
74-
}.also {
75-
close()
76+
}
77+
78+
override fun reset() {
79+
ensureNotClosed()
80+
accumulator = EmptyByteArray
7681
}
7782

7883
override fun close() {
@@ -123,9 +128,14 @@ private class SecSignFunction(
123128
}
124129

125130
signature.toByteArray()
131+
}.also {
132+
reset()
126133
}
127-
}.also {
128-
close()
134+
}
135+
136+
override fun reset() {
137+
ensureNotClosed()
138+
accumulator = EmptyByteArray
129139
}
130140

131141
override fun close() {

cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkDigest.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ internal class JdkDigest(
1717
) : Hasher, Digest {
1818
private val messageDigest = state.messageDigest(algorithm)
1919
override fun hasher(): Hasher = this
20-
override fun createHashFunction(): HashFunction = JdkHashFunction(messageDigest.borrowResource().also {
21-
it.access().reset()
22-
})
20+
override fun createHashFunction(): HashFunction = JdkHashFunction(messageDigest.borrowResource { reset() })
2321
}
2422

2523
private class JdkHashFunction(private val messageDigest: Pooled.Resource<JMessageDigest>) : HashFunction {
@@ -35,12 +33,17 @@ private class JdkHashFunction(private val messageDigest: Pooled.Resource<JMessag
3533

3634
checkBounds(destination.size, destinationOffset, destinationOffset + messageDigest.digestLength)
3735

38-
return messageDigest.digest(destination, destinationOffset, messageDigest.digestLength).also { close() }
36+
return messageDigest.digest(destination, destinationOffset, messageDigest.digestLength)
3937
}
4038

4139
override fun hashToByteArray(): ByteArray {
4240
val messageDigest = messageDigest.access()
43-
return messageDigest.digest().also { close() }
41+
return messageDigest.digest()
42+
}
43+
44+
override fun reset() {
45+
val messageDigest = messageDigest.access()
46+
messageDigest.reset()
4447
}
4548

4649
override fun close() {

cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkEcdsa.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ private class EcdsaRawSignatureGenerator(
9090
return rawSignature
9191
}
9292

93+
override fun reset() {
94+
derSignFunction.reset()
95+
}
96+
9397
override fun close() {
9498
derSignFunction.close()
9599
}
@@ -134,6 +138,10 @@ private class EcdsaRawSignatureVerifier(
134138
check(tryVerify(signature, startIndex, endIndex)) { "Invalid signature" }
135139
}
136140

141+
override fun reset() {
142+
derVerifyFunction.reset()
143+
}
144+
137145
override fun close() {
138146
derVerifyFunction.close()
139147
}

0 commit comments

Comments
 (0)