Skip to content

Commit 5a57e4b

Browse files
committed
Add helper function for clearing Mac key
1 parent bde12bc commit 5a57e4b

File tree

7 files changed

+91
-16
lines changed

7 files changed

+91
-16
lines changed

library/mac/api/mac.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ public abstract class org/kotlincrypto/core/mac/Mac : javax/crypto/Mac, org/kotl
22
protected fun <init> (Ljava/lang/String;Lorg/kotlincrypto/core/mac/Mac$Engine;)V
33
protected fun <init> (Lorg/kotlincrypto/core/mac/Mac;)V
44
public final fun algorithm ()Ljava/lang/String;
5+
public final fun clearKey ()V
56
public final fun equals (Ljava/lang/Object;)Z
67
public final fun hashCode ()I
78
public final fun macLength ()I

library/mac/api/mac.klib.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ abstract class org.kotlincrypto.core.mac/Mac : org.kotlincrypto.core/Algorithm,
1111
constructor <init>(org.kotlincrypto.core.mac/Mac) // org.kotlincrypto.core.mac/Mac.<init>|<init>(org.kotlincrypto.core.mac.Mac){}[0]
1212

1313
final fun algorithm(): kotlin/String // org.kotlincrypto.core.mac/Mac.algorithm|algorithm(){}[0]
14+
final fun clearKey() // org.kotlincrypto.core.mac/Mac.clearKey|clearKey(){}[0]
1415
final fun doFinal(): kotlin/ByteArray // org.kotlincrypto.core.mac/Mac.doFinal|doFinal(){}[0]
1516
final fun doFinal(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.core.mac/Mac.doFinal|doFinal(kotlin.ByteArray){}[0]
1617
final fun equals(kotlin/Any?): kotlin/Boolean // org.kotlincrypto.core.mac/Mac.equals|equals(kotlin.Any?){}[0]

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,19 @@ public expect abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
106106
/**
107107
* Resets the [Mac] and will reinitialize it with the provided key.
108108
*
109-
* This is useful if wanting to clear the key before de-referencing.
109+
* This is useful if wanting to zero out the key before de-referencing.
110110
*
111-
* @throws [IllegalArgumentException] if [newKey] is empty.
111+
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
112+
* inappropriate for the [Mac] implementation.
112113
* */
113114
public fun reset(newKey: ByteArray)
114115

116+
/**
117+
* Helper function that will call [reset] with a blank key in order
118+
* to zero it out.
119+
* */
120+
public fun clearKey()
121+
115122
/**
116123
* Core abstraction for powering a [Mac] implementation.
117124
*
@@ -147,6 +154,17 @@ public expect abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
147154
// See Updatable interface documentation
148155
public override fun update(input: ByteArray)
149156

157+
/**
158+
* Resets the [Engine] and will reinitialize it with the provided key.
159+
*
160+
* **NOTE:** [newKey] is checked to be non-empty by the [Mac] abstraction
161+
* before passing it here. Implementations should ensure any old key material
162+
* is zeroed out.
163+
*
164+
* @throws [IllegalArgumentException] if [newKey] is a length inappropriate
165+
* for the [Mac] implementation.
166+
* */
167+
@Throws(IllegalArgumentException::class)
150168
public abstract fun reset(newKey: ByteArray)
151169

152170
/** @suppress */

library/mac/src/commonMain/kotlin/org/kotlincrypto/core/mac/internal/-CommonPlatform.kt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,33 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
**/
16-
@file:Suppress("KotlinRedundantDiagnosticSuppress")
16+
@file:Suppress("KotlinRedundantDiagnosticSuppress", "NOTHING_TO_INLINE")
1717

1818
package org.kotlincrypto.core.mac.internal
1919

2020
import org.kotlincrypto.core.mac.Mac
2121

22+
private val SINGLE_0BYTE_KEY = ByteArray(1) { 0 }
23+
24+
@Suppress("UnusedReceiverParameter")
2225
@Throws(IllegalArgumentException::class)
23-
@Suppress("NOTHING_TO_INLINE", "UnusedReceiverParameter")
2426
internal inline fun Mac.commonInit(algorithm: String) {
2527
require(algorithm.isNotBlank()) { "algorithm cannot be blank" }
2628
}
2729

28-
@Suppress("NOTHING_TO_INLINE")
2930
internal inline fun Mac.commonToString(): String {
3031
return "Mac[${algorithm()}]@${hashCode()}"
3132
}
33+
34+
internal inline fun Mac.commonClearKey(engineReset: (ByteArray) -> Unit) {
35+
try {
36+
engineReset(SINGLE_0BYTE_KEY)
37+
} catch (e1: IllegalArgumentException) {
38+
try {
39+
engineReset(ByteArray(macLength()))
40+
} catch (e2: IllegalArgumentException) {
41+
e2.addSuppressed(e1)
42+
throw e2
43+
}
44+
}
45+
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,18 @@ class MacUnitTest {
8080
assertEquals(2, doFinalCount)
8181
assertEquals(2, resetCount)
8282
}
83+
84+
@Test
85+
fun givenMac_whenClearKey_thenSingle0ByteKeyPassedToEngine() {
86+
var zeroKey: ByteArray? = null
87+
88+
TestMac(
89+
ByteArray(5),
90+
"test rekey",
91+
rekey = { zeroKey = it }
92+
).clearKey()
93+
94+
assertNotNull(zeroKey)
95+
assertContentEquals(ByteArray(1) { 0 }, zeroKey)
96+
}
8397
}

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
package org.kotlincrypto.core.mac
1919

2020
import org.kotlincrypto.core.*
21-
import org.kotlincrypto.core.mac.internal.AndroidApi21to23MacSpiProvider
22-
import org.kotlincrypto.core.mac.internal.commonInit
23-
import org.kotlincrypto.core.mac.internal.commonToString
21+
import org.kotlincrypto.core.mac.internal.*
2422
import java.nio.ByteBuffer
2523
import java.security.InvalidKeyException
2624
import java.security.Key
@@ -109,15 +107,22 @@ public actual abstract class Mac: javax.crypto.Mac, Algorithm, Copyable<Mac>, Re
109107
/**
110108
* Resets the [Mac] and will reinitialize it with the provided key.
111109
*
112-
* This is useful if wanting to clear the key before de-referencing.
110+
* This is useful if wanting to zero out the key before de-referencing.
113111
*
114-
* @throws [IllegalArgumentException] if [newKey] is empty.
112+
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
113+
* inappropriate for the [Mac] implementation.
115114
* */
116115
public actual fun reset(newKey: ByteArray) {
117116
require(newKey.isNotEmpty()) { "newKey cannot be empty" }
118117
engine.reset(newKey)
119118
}
120119

120+
/**
121+
* Helper function that will call [reset] with a blank key in order
122+
* to zero it out.
123+
* */
124+
public actual fun clearKey() { commonClearKey(engine::reset) }
125+
121126
/**
122127
* Core abstraction for powering a [Mac] implementation. Extends
123128
* Java's [MacSpi] for compatibility.
@@ -157,8 +162,16 @@ public actual abstract class Mac: javax.crypto.Mac, Algorithm, Copyable<Mac>, Re
157162
public actual override fun update(input: ByteArray) { update(input, 0, input.size) }
158163

159164
/**
160-
* Resets the [Engine] and will reinitialize it with the newly provided key.
165+
* Resets the [Engine] and will reinitialize it with the provided key.
166+
*
167+
* **NOTE:** [newKey] is checked to be non-empty by the [Mac] abstraction
168+
* before passing it here. Implementations should ensure any old key material
169+
* is zeroed out.
170+
*
171+
* @throws [IllegalArgumentException] if [newKey] is a length inappropriate
172+
* for the [Mac] implementation.
161173
* */
174+
@Throws(IllegalArgumentException::class)
162175
public actual abstract fun reset(newKey: ByteArray)
163176

164177
// MacSpi

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
package org.kotlincrypto.core.mac
1919

2020
import org.kotlincrypto.core.*
21-
import org.kotlincrypto.core.mac.internal.commonInit
22-
import org.kotlincrypto.core.mac.internal.commonToString
21+
import org.kotlincrypto.core.mac.internal.*
2322

2423
/**
2524
* Core abstraction for Message Authentication Code implementations.
@@ -132,15 +131,22 @@ public actual abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
132131
/**
133132
* Resets the [Mac] and will reinitialize it with the provided key.
134133
*
135-
* This is useful if wanting to clear the key before de-referencing.
134+
* This is useful if wanting to zero out the key before de-referencing.
136135
*
137-
* @throws [IllegalArgumentException] if [newKey] is empty.
136+
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
137+
* inappropriate for the [Mac] implementation.
138138
* */
139139
public actual fun reset(newKey: ByteArray) {
140140
require(newKey.isNotEmpty()) { "newKey cannot be empty" }
141141
engine.reset(newKey)
142142
}
143143

144+
/**
145+
* Helper function that will call [reset] with a blank key in order
146+
* to zero it out.
147+
* */
148+
public actual fun clearKey() { commonClearKey(engine::reset) }
149+
144150
/**
145151
* Core abstraction for powering a [Mac] implementation.
146152
*
@@ -179,8 +185,16 @@ public actual abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
179185
public actual override fun update(input: ByteArray) { update(input, 0, input.size) }
180186

181187
/**
182-
* Resets the [Engine] and will reinitialize it with the newly provided key.
188+
* Resets the [Engine] and will reinitialize it with the provided key.
189+
*
190+
* **NOTE:** [newKey] is checked to be non-empty by the [Mac] abstraction
191+
* before passing it here. Implementations should ensure any old key material
192+
* is zeroed out.
193+
*
194+
* @throws [IllegalArgumentException] if [newKey] is a length inappropriate
195+
* for the [Mac] implementation.
183196
* */
197+
@Throws(IllegalArgumentException::class)
184198
public actual abstract fun reset(newKey: ByteArray)
185199

186200
private val code = Any()

0 commit comments

Comments
 (0)