Skip to content

Add helper function for clearing Mac key #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/mac/api/mac.api
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ public abstract class org/kotlincrypto/core/mac/Mac : javax/crypto/Mac, org/kotl
protected fun <init> (Ljava/lang/String;Lorg/kotlincrypto/core/mac/Mac$Engine;)V
protected fun <init> (Lorg/kotlincrypto/core/mac/Mac;)V
public final fun algorithm ()Ljava/lang/String;
public final fun clearKey ()V
public final fun equals (Ljava/lang/Object;)Z
public final fun hashCode ()I
public final fun macLength ()I
Expand Down
1 change: 1 addition & 0 deletions library/mac/api/mac.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ abstract class org.kotlincrypto.core.mac/Mac : org.kotlincrypto.core/Algorithm,
constructor <init>(org.kotlincrypto.core.mac/Mac) // org.kotlincrypto.core.mac/Mac.<init>|<init>(org.kotlincrypto.core.mac.Mac){}[0]

final fun algorithm(): kotlin/String // org.kotlincrypto.core.mac/Mac.algorithm|algorithm(){}[0]
final fun clearKey() // org.kotlincrypto.core.mac/Mac.clearKey|clearKey(){}[0]
final fun doFinal(): kotlin/ByteArray // org.kotlincrypto.core.mac/Mac.doFinal|doFinal(){}[0]
final fun doFinal(kotlin/ByteArray): kotlin/ByteArray // org.kotlincrypto.core.mac/Mac.doFinal|doFinal(kotlin.ByteArray){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.kotlincrypto.core.mac/Mac.equals|equals(kotlin.Any?){}[0]
Expand Down
23 changes: 21 additions & 2 deletions library/mac/src/commonMain/kotlin/org/kotlincrypto/core/mac/Mac.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,20 @@ public expect abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
/**
* Resets the [Mac] and will reinitialize it with the provided key.
*
* This is useful if wanting to clear the key before de-referencing.
* This is useful if wanting to zero out the key before de-referencing.
*
* @throws [IllegalArgumentException] if [newKey] is empty.
* @see [clearKey]
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
* inappropriate for the [Mac] implementation.
* */
public fun reset(newKey: ByteArray)

/**
* Helper function that will call [reset] with a blank key in order
* to zero it out.
* */
public fun clearKey()

/**
* Core abstraction for powering a [Mac] implementation.
*
Expand Down Expand Up @@ -147,6 +155,17 @@ public expect abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
// See Updatable interface documentation
public override fun update(input: ByteArray)

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

/** @suppress */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("KotlinRedundantDiagnosticSuppress")
@file:Suppress("KotlinRedundantDiagnosticSuppress", "NOTHING_TO_INLINE")

package org.kotlincrypto.core.mac.internal

import org.kotlincrypto.core.mac.Mac

private val SINGLE_0BYTE_KEY = ByteArray(1) { 0 }

@Suppress("UnusedReceiverParameter")
@Throws(IllegalArgumentException::class)
@Suppress("NOTHING_TO_INLINE", "UnusedReceiverParameter")
internal inline fun Mac.commonInit(algorithm: String) {
require(algorithm.isNotBlank()) { "algorithm cannot be blank" }
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun Mac.commonToString(): String {
return "Mac[${algorithm()}]@${hashCode()}"
}

internal inline fun Mac.commonClearKey(engineReset: (ByteArray) -> Unit) {
try {
engineReset(SINGLE_0BYTE_KEY)
} catch (e1: IllegalArgumentException) {
try {
engineReset(ByteArray(macLength()))
} catch (e2: IllegalArgumentException) {
e2.addSuppressed(e1)
throw e2
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,18 @@ class MacUnitTest {
assertEquals(2, doFinalCount)
assertEquals(2, resetCount)
}

@Test
fun givenMac_whenClearKey_thenSingle0ByteKeyPassedToEngine() {
var zeroKey: ByteArray? = null

TestMac(
ByteArray(5),
"test rekey",
rekey = { zeroKey = it }
).clearKey()

assertNotNull(zeroKey)
assertContentEquals(ByteArray(1) { 0 }, zeroKey)
}
}
26 changes: 20 additions & 6 deletions library/mac/src/jvmMain/kotlin/org/kotlincrypto/core/mac/Mac.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@
package org.kotlincrypto.core.mac

import org.kotlincrypto.core.*
import org.kotlincrypto.core.mac.internal.AndroidApi21to23MacSpiProvider
import org.kotlincrypto.core.mac.internal.commonInit
import org.kotlincrypto.core.mac.internal.commonToString
import org.kotlincrypto.core.mac.internal.*
import java.nio.ByteBuffer
import java.security.InvalidKeyException
import java.security.Key
Expand Down Expand Up @@ -109,15 +107,23 @@ public actual abstract class Mac: javax.crypto.Mac, Algorithm, Copyable<Mac>, Re
/**
* Resets the [Mac] and will reinitialize it with the provided key.
*
* This is useful if wanting to clear the key before de-referencing.
* This is useful if wanting to zero out the key before de-referencing.
*
* @throws [IllegalArgumentException] if [newKey] is empty.
* @see [clearKey]
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
* inappropriate for the [Mac] implementation.
* */
public actual fun reset(newKey: ByteArray) {
require(newKey.isNotEmpty()) { "newKey cannot be empty" }
engine.reset(newKey)
}

/**
* Helper function that will call [reset] with a blank key in order
* to zero it out.
* */
public actual fun clearKey() { commonClearKey(engine::reset) }

/**
* Core abstraction for powering a [Mac] implementation. Extends
* Java's [MacSpi] for compatibility.
Expand Down Expand Up @@ -157,8 +163,16 @@ public actual abstract class Mac: javax.crypto.Mac, Algorithm, Copyable<Mac>, Re
public actual override fun update(input: ByteArray) { update(input, 0, input.size) }

/**
* Resets the [Engine] and will reinitialize it with the newly provided key.
* Resets the [Engine] and will reinitialize it with the provided key.
*
* **NOTE:** [newKey] is checked to be non-empty by the [Mac] abstraction
* before passing it here. Implementations should ensure any old key material
* is zeroed out.
*
* @throws [IllegalArgumentException] if [newKey] is a length inappropriate
* for the [Mac] implementation.
* */
@Throws(IllegalArgumentException::class)
public actual abstract fun reset(newKey: ByteArray)

// MacSpi
Expand Down
25 changes: 20 additions & 5 deletions library/mac/src/nonJvmMain/kotlin/org/kotlincrypto/core/mac/Mac.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
package org.kotlincrypto.core.mac

import org.kotlincrypto.core.*
import org.kotlincrypto.core.mac.internal.commonInit
import org.kotlincrypto.core.mac.internal.commonToString
import org.kotlincrypto.core.mac.internal.*

/**
* Core abstraction for Message Authentication Code implementations.
Expand Down Expand Up @@ -132,15 +131,23 @@ public actual abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
/**
* Resets the [Mac] and will reinitialize it with the provided key.
*
* This is useful if wanting to clear the key before de-referencing.
* This is useful if wanting to zero out the key before de-referencing.
*
* @throws [IllegalArgumentException] if [newKey] is empty.
* @see [clearKey]
* @throws [IllegalArgumentException] if [newKey] is empty, or of a length
* inappropriate for the [Mac] implementation.
* */
public actual fun reset(newKey: ByteArray) {
require(newKey.isNotEmpty()) { "newKey cannot be empty" }
engine.reset(newKey)
}

/**
* Helper function that will call [reset] with a blank key in order
* to zero it out.
* */
public actual fun clearKey() { commonClearKey(engine::reset) }

/**
* Core abstraction for powering a [Mac] implementation.
*
Expand Down Expand Up @@ -179,8 +186,16 @@ public actual abstract class Mac: Algorithm, Copyable<Mac>, Resettable, Updatabl
public actual override fun update(input: ByteArray) { update(input, 0, input.size) }

/**
* Resets the [Engine] and will reinitialize it with the newly provided key.
* Resets the [Engine] and will reinitialize it with the provided key.
*
* **NOTE:** [newKey] is checked to be non-empty by the [Mac] abstraction
* before passing it here. Implementations should ensure any old key material
* is zeroed out.
*
* @throws [IllegalArgumentException] if [newKey] is a length inappropriate
* for the [Mac] implementation.
* */
@Throws(IllegalArgumentException::class)
public actual abstract fun reset(newKey: ByteArray)

private val code = Any()
Expand Down
Loading