From 0af6f24ab88f1e3afa937d874ea83f12b9da550c Mon Sep 17 00:00:00 2001 From: null Date: Wed, 8 Jul 2026 23:21:35 -0500 Subject: [PATCH] =?UTF-8?q?docs(manual):=20batch=203=20review=20=E2=80=94?= =?UTF-8?q?=20Argon2id=20memory=20was=2046080=20KiB=20but=20the=20code=20i?= =?UTF-8?q?s=2047104?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Argon2id parameter block said: - memory: 46 MiB (46080 KiB) - iterations: 3 - parallelism: 1 But the source constant in RecoveryKeyManager.kt is: private const val ARGON2_MEMORY_KB = 46 * 1024 46 * 1024 = 47104, not 46080 (a slipped digit). 46080 KiB would be 45 MiB. The iOS-side docstring in CoupleEncryptionManager.swift already says 46 MiB = 47104 KiB, so this is the Android-side drift. Replaced the parameter block with the source-of-truth constant names (ARGON2_MEMORY_KB, ARGON2_ITERATIONS, ARGON2_PARALLELISM) and the correct KiB value (47104) so the next reader can grep the code. Other Batch 3 claims verified clean: - Encryption version table: EncryptionVersion.STRICT=2, acceptInviteCallable hardcodes 2, throws if any of wrappedCoupleKey/kdfSalt/kdfParams is null. - Tink AEAD wire formats: enc:v1:base64, sealed:v1:urlsafe-base64-no-padding, keybox:v1:urlsafe-base64-no-padding, pub:v1:urlsafe-base64-no-padding, sha256:urlsafe-base64-no-padding (43 chars). All match the source constants. - AAD: FieldEncryptor uses coupleId; SealedAnswerEncryptor uses coupleId|questionId|userId; both match. - ECIES P-256: UserKeyManager uses HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM; ReleaseKeyEncryptor contextInfo is coupleId|questionId|senderUserId|recipientUserId. - All 5 firestore.rules regex helpers match the manual's reference table. - wrapReleaseKeyCallable reads the recipient public key from users/{uid}/devices/primary (verified in function source). - CoupleKeyStore persists Tink keyset handles in EncryptedSharedPreferences (Keystore-backed) via SecurePreferencesFactory. --- docs/Engineering_Reference_Manual.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Engineering_Reference_Manual.md b/docs/Engineering_Reference_Manual.md index cb99c593..66773ddf 100644 --- a/docs/Engineering_Reference_Manual.md +++ b/docs/Engineering_Reference_Manual.md @@ -396,9 +396,9 @@ The couple keyset is a Tink AES-256-GCM keyset generated once per couple. - `RecoveryKeyManager.newCoupleKeyset()` creates the keyset. - `RecoveryKeyManager.wrap(keyset, phrase)` derives a 32-byte key with Argon2id: - - **memory**: 46 MiB (`46080` KiB) - - **iterations**: 3 - - **parallelism**: 1 + - **memory**: 46 MiB (`46 * 1024 = 47104` KiB; constant `ARGON2_MEMORY_KB`) + - **iterations**: 3 (`ARGON2_ITERATIONS`) + - **parallelism**: 1 (`ARGON2_PARALLELISM`) - **salt**: 16 random bytes - The keyset plaintext is encrypted with AES-256-GCM using the derived key. AAD is the fixed string `"closer_couple_key"` so the blob is portable across invite-code reconciliation. - The wrapped result is stored on the couple document as `wrappedCoupleKey`, `kdfSalt`, `kdfParams`.