Merge expanding and checking Hmac functions to avoid re-creating the Mac instance.

This commit is contained in:
Vitor Pamplona
2025-09-15 17:25:36 -04:00
parent e329b096ba
commit cd0b1b65fb
3 changed files with 36 additions and 6 deletions

View File

@@ -46,7 +46,15 @@ class HkdfBenchmark {
}
@Test
fun hkdfExpand() {
fun hkdfExpandWithCheck() {
val hkdf = Hkdf()
benchmarkRule.measureRepeated {
hkdf.fastExpand(sharedKey, encrypted.nonce, encrypted.ciphertext, encrypted.mac)
}
}
@Test
fun hkdfFastExpand() {
val hkdf = Hkdf()
benchmarkRule.measureRepeated {
hkdf.fastExpand(sharedKey, encrypted.nonce)

View File

@@ -113,12 +113,14 @@ class Nip44v2 {
decoded: EncryptedInfo,
conversationKey: ByteArray,
): String {
val messageKey = getMessageKeys(conversationKey, decoded.nonce)
checkHMacAad(messageKey, decoded)
val messageKey = checkMessageKeys(conversationKey, decoded)
return unpad(
chaCha.decrypt(decoded.ciphertext, messageKey.chachaNonce, messageKey.chachaKey),
chaCha.decrypt(
decoded.ciphertext,
messageKey.chachaNonce,
messageKey.chachaKey,
),
)
}
@@ -210,6 +212,11 @@ class Nip44v2 {
nonce: ByteArray,
): Hkdf.MessageKey = hkdf.fastExpand(conversationKey, nonce)
fun checkMessageKeys(
conversationKey: ByteArray,
decoded: EncryptedInfo,
): Hkdf.MessageKey = hkdf.fastExpand(conversationKey, decoded.nonce, decoded.ciphertext, decoded.mac)
/** @return 32B shared secret */
fun computeConversationKey(
privateKey: ByteArray,

View File

@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.quartz.nip44Encryption.crypto
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
import java.nio.ByteBuffer
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
@@ -88,6 +89,8 @@ class Hkdf(
fun fastExpand(
key: ByteArray,
nonce: ByteArray,
ciphertext: ByteArray? = null,
ciphertextMac: ByteArray? = null,
): MessageKey {
check(key.size == hashLen)
check(nonce.size == hashLen)
@@ -112,10 +115,22 @@ class Hkdf(
mac.update(3)
val round3 = mac.doFinal()
val hmacKey = ByteArray(32)
val hmacKey = ByteArray(hashLen)
System.arraycopy(round2, 12, hmacKey, 0, 20)
System.arraycopy(round3, 0, hmacKey, 20, 12)
// checks the mac here to avoid building a new Mac.getInstance(algorithm)
if (ciphertext != null && ciphertextMac != null) {
mac.init(FixedKey(hmacKey, algorithm))
mac.update(nonce)
mac.update(ciphertext)
val calculatedMac = mac.doFinal()
check(calculatedMac.contentEquals(ciphertextMac)) {
"Invalid Mac: Calculated ${calculatedMac.toHexKey()}, decoded: ${ciphertextMac.toHexKey()}"
}
}
return MessageKey(
chachaKey = round1,
chachaNonce = round2.copyOfRange(0, 12),