fix: use 12-byte GCM IV length in KeyStoreEncryption.decrypt

Marmot MLS groups were being wiped on every app restart. The encrypted
state was written with a 12-byte GCM IV (from cipher.iv after ENCRYPT_MODE
init), but decrypt was reading cipher.blockSize (= 16, the AES block size)
bytes as the IV. Every decrypt therefore failed, MlsGroupManager.restoreAll
caught the exception and deleted the "corrupt" group directory, and the
Marmot group list came up empty after each restart.

Use a 12-byte IV constant in both encrypt and decrypt so the round-trip
works. This matches the sibling KeyStoreEncryption in commons/androidMain
(which already hardcodes 12).
This commit is contained in:
Claude
2026-04-15 01:53:57 +00:00
parent ed245ada57
commit 8a7afdf794
@@ -38,6 +38,7 @@ class KeyStoreEncryption {
private const val TRANSFORMATION = "$ALGORITHM/$BLOCK_MODE/$PADDING"
private const val PURPOSE = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
private const val KEY_ALIAS = "AMETHYST_AES_KEY"
private const val GCM_IV_LENGTH = 12
}
private val cipher = Cipher.getInstance(TRANSFORMATION)
@@ -93,9 +94,11 @@ class KeyStoreEncryption {
}
fun decrypt(bytes: ByteArray): ByteArray? {
// Extracts IV and decrypts the data
val iv = bytes.copyOfRange(0, cipher.blockSize)
val data = bytes.copyOfRange(cipher.blockSize, bytes.size)
// Extracts IV and decrypts the data. GCM mode uses a 12-byte IV,
// which is what cipher.iv returns in encrypt() — not the AES block
// size (16), which is what cipher.blockSize would return.
val iv = bytes.copyOfRange(0, GCM_IV_LENGTH)
val data = bytes.copyOfRange(GCM_IV_LENGTH, bytes.size)
cipher.init(Cipher.DECRYPT_MODE, getKey(), IvParameterSpec(iv))
return cipher.doFinal(data)
}