From 7d470cf8300e90c6813e169052927a5c2edd4f9e Mon Sep 17 00:00:00 2001 From: Enginex0 Date: Thu, 26 Mar 2026 05:03:01 +0100 Subject: [PATCH] fix(operation): pass operation-time params through to CipherPrimitive createOperation was building effectiveParams from key-generation params but dropping operation-time fields (nonce, blockMode, padding, minMacLength). This caused GCM decrypt to fail with "IV must be specified in GCM mode" since the nonce from the begin call never reached CipherPrimitive. Also adds nonce field to KeyMintAttestation and handles GCM/CBC/CTR IV initialization in CipherPrimitive. --- .../TEESimulator/attestation/KeyMintAttestation.kt | 2 ++ .../interception/keystore/KeystoreInterceptor.kt | 1 + .../keystore/shim/KeyMintSecurityLevelInterceptor.kt | 5 +++++ .../interception/keystore/shim/SoftwareOperation.kt | 9 ++++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/matrix/TEESimulator/attestation/KeyMintAttestation.kt b/app/src/main/java/org/matrix/TEESimulator/attestation/KeyMintAttestation.kt index 0eaf31a..5496212 100644 --- a/app/src/main/java/org/matrix/TEESimulator/attestation/KeyMintAttestation.kt +++ b/app/src/main/java/org/matrix/TEESimulator/attestation/KeyMintAttestation.kt @@ -46,6 +46,7 @@ data class KeyMintAttestation( val usageExpireDateTime: Date?, val usageCountLimit: Int?, val callerNonce: Boolean?, + val nonce: ByteArray?, val unlockedDeviceRequired: Boolean?, val includeUniqueId: Boolean?, val rollbackResistance: Boolean?, @@ -121,6 +122,7 @@ data class KeyMintAttestation( usageExpireDateTime = params.findDate(Tag.USAGE_EXPIRE_DATETIME), usageCountLimit = params.findInteger(Tag.USAGE_COUNT_LIMIT), callerNonce = params.findBoolean(Tag.CALLER_NONCE), + nonce = params.findBlob(Tag.NONCE), unlockedDeviceRequired = params.findBoolean(Tag.UNLOCKED_DEVICE_REQUIRED), includeUniqueId = params.findBoolean(Tag.INCLUDE_UNIQUE_ID), rollbackResistance = params.findBoolean(Tag.ROLLBACK_RESISTANCE), diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/KeystoreInterceptor.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/KeystoreInterceptor.kt index 33bb559..9f7daf9 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/KeystoreInterceptor.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/KeystoreInterceptor.kt @@ -436,6 +436,7 @@ private data class LegacyKeygenParameters( usageExpireDateTime = null, usageCountLimit = null, callerNonce = null, + nonce = null, unlockedDeviceRequired = null, includeUniqueId = null, rollbackResistance = null, diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt index c65586f..bcc620c 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/KeyMintSecurityLevelInterceptor.kt @@ -360,6 +360,10 @@ class KeyMintSecurityLevelInterceptor( keyParams.copy( purpose = parsedParams.purpose, digest = parsedParams.digest.ifEmpty { keyParams.digest }, + blockMode = parsedParams.blockMode.ifEmpty { keyParams.blockMode }, + padding = parsedParams.padding.ifEmpty { keyParams.padding }, + nonce = parsedParams.nonce, + minMacLength = parsedParams.minMacLength ?: keyParams.minMacLength, ) } else parsedParams @@ -863,6 +867,7 @@ class KeyMintSecurityLevelInterceptor( usageExpireDateTime = null, usageCountLimit = null, callerNonce = null, + nonce = null, unlockedDeviceRequired = null, includeUniqueId = null, rollbackResistance = null, diff --git a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt index 59a78ff..cf5ea9e 100644 --- a/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt +++ b/app/src/main/java/org/matrix/TEESimulator/interception/keystore/shim/SoftwareOperation.kt @@ -137,7 +137,14 @@ private class CipherPrimitive( private val isAead = params.blockMode.firstOrNull() == BlockMode.GCM private val cipher: Cipher = Cipher.getInstance(JcaAlgorithmMapper.mapCipherAlgorithm(params)).apply { - init(opMode, cryptoKey) + val nonce = params.nonce + if (nonce != null && isAead) { + init(opMode, cryptoKey, javax.crypto.spec.GCMParameterSpec(128, nonce)) + } else if (nonce != null) { + init(opMode, cryptoKey, javax.crypto.spec.IvParameterSpec(nonce)) + } else { + init(opMode, cryptoKey) + } } override fun updateAad(aadInput: ByteArray?) {