fix(marmot): use GCMParameterSpec for decrypt + stop auto-deleting groups on restore failure

Logs from the real device showed that with the previous fixes save and
listGroups now work correctly (878 → 1162 bytes written, file found
after restart), but decrypt was throwing:

    InvalidAlgorithmParameterException: Only GCMParameterSpec supported
        at AndroidKeyStoreAuthenticatedAESCipherSpi$GCM.initAlgorithmSpecificParameters

AndroidKeyStore's authenticated AES/GCM cipher rejects plain
IvParameterSpec and requires an explicit GCMParameterSpec with the
auth tag length. Switched decrypt() to use GCMParameterSpec(128, iv).

While chasing this I also noticed that MlsGroupManager.restoreAll
was **deleting** the stored group on any exception from load(), on
the assumption that it must be corrupted. This turned a transient
decrypt bug into permanent data loss — the user's group file was
wiped during the first broken restart. Change the catch block to
log and skip instead of delete, so after a fix the next restart
can still recover the data.

https://claude.ai/code/session_014EKS8JBwSpap34aM6FnYLm
This commit is contained in:
Claude
2026-04-15 19:27:36 +00:00
parent 4d5861e581
commit c04d3d0bf0
2 changed files with 12 additions and 8 deletions
@@ -127,13 +127,16 @@ class MlsGroupManager(
Log.d(TAG) { "restoreAll(): restored ${retained.size} retained epochs for $nostrGroupId" }
}
} catch (e: Exception) {
// Corrupted state — log and remove it so it doesn't block future joins
// Could be genuinely corrupted state, or a transient bug
// (e.g. wrong cipher param spec). Skip but DO NOT delete —
// a future restart after a fix should still be able to
// recover the group. If it really is corrupted the user
// can explicitly leave/delete the group from the UI.
Log.e(
TAG,
"restoreAll(): Corrupted state for group $nostrGroupId, DELETING: ${e.message}",
"restoreAll(): failed to restore group $nostrGroupId, skipping (file preserved): ${e.message}",
e,
)
store.delete(nostrGroupId)
}
}
Log.d(TAG) { "restoreAll(): finished with ${groups.size} active groups in memory" }