peach-android
A free, open source, local-first password manager for Android.
timeline
atlas503 files
app/
src/
androidTest/
java/
com/
peachpasswords/
codex/
qa/
adb input text).vault/
debug/
res/
values/
main/
java/
com/
peachpasswords/
autofill/
hiltViewModel() without reaching for an EntryPoint accessor.AutofillOrigin.ktOrigin resolution for autofill matching.AutofillResponseBuilder.ktTurns parsed form fields + vault entries into autofill [Dataset]s — the menu RemoteViews row, the inline keyboard chip, and the actual field values.AutofillSave.ktChipMonogramIcon.ktMonogram chip icons for inline autofill suggestions — the same initials and deterministic background as the vault list (titleInitials/titleBackground), rendered once per source and cached.Identities.ktSignup identities for the autofill picker (parity gap A4).PasswordPolicy.ktSite password constraints detected from a password field's HTML attributes (exposed by [android.app.assist.AssistStructure.ViewNode.getHtmlInfo]).PeachAutofillService.ktSystem autofill provider.codex/
popup/codex/pdf-layout.ts, which is the canonical Codex page format.CodexPdf.ktRenders the Aztec codes onto an A4 PDF in a 6×6 grid — the printed Codex.CodexRestore.ktRestore side: render a Codex PDF back to bitmaps, crop the 6×6 grid using the same geometry [CodexPdf] laid down, decode each Aztec, then Reed-Solomon reconstruct the payload — surviving missing or unreadable codes up to the parity budget.CodexTypes.ktCodex on-paper format constants and shapes — port of the browser shared/codex-types.ts.ReedSolomon.ktSystematic Reed-Solomon erasure codec over GF(2⁸), Backblaze/JavaReedSolomon construction (Vandermonde matrix made systematic).credentials/
di/
feedback/
haptics/
license/
passkeys/
shared/
sync/
new WebSocket(...).PendingVouchedDeviceStore.ktRelayAdoptionHost.ktRelayAdoptionReceiver.ktReceiver half of relay-first vault adoption.RelaySettingsStore.ktSync is exactly three named choices (docs/sync-lan-retirement.md, mirroring the browser's sync-settings.ts):Rendezvous.ktRustNoiseNative.ktThin JNI boundary over the canonical Rust snow state machine.SASDerivation.ktSyncAlert.ktSyncAlertStore.ktSyncCoordinator.ktSync — Phase 2 manifest-diff coordinator.SyncFrameTransport.ktE7b: split a too-large padded sync frame across multiple Noise transport messages and reassemble it on the other side.SyncFreshStartResetter.ktClears every piece of state that can make a destroyed vault still look paired.SyncGeneration.ktThe durable Sync-generation state machine (protocol §11).SyncGenerationStore.ktStorage adapter for the Sync-generation state machine.SyncIdentity.ktSyncLimits.ktCloudflare Workers caps one WebSocket message at 32 MiB.SyncMessage.ktSync wire protocol — exact port of the browser SyncMessage union (shared/sync-types.ts).SyncNotificationPermission.ktA foreground service can keep running after Android notification permission is denied, but its status notification disappears from the drawer.SyncOutcomeReason.ktWhy a sync attempt ended, in the same vocabulary the browser uses (src/shared/sync-outcome.ts).SyncOutcomeStore.ktThe single place a sync attempt is allowed to end.SyncPadding.ktE7: frame padding at the relay boundary.SyncPeerRole.ktWho speaks first in a relay room.SyncSession.ktTransport-neutral session consumed by the sync coordinator.VaultAdopt.ktVault adoption frame protocol — exact port of the browser shared/vault-adopt.ts.VaultSyncAdapter.ktProduction [SyncVaultAdapter] backing the coordinator with the live [VaultRepository].ui/
codex/
components/
PairDeviceFlow.tsx (a finch and a swallow) rather than redrawn by eye.PeachEmptyOrEndState.ktPeachExpandableCard.ktPeachField.ktPeachMark.ktThe Peach brand mark — a peach fruit with a single leaf.PeachSectionHeader.ktQuiet branded section identity used instead of the retired contained top bar.PeachSegmentedControl.ktPeachTopBar.ktQaFlags.ktDebug-only, opt-in escape hatch so automated visual QA (screenshot-based Gate 2 comparisons) can capture screens that are normally FLAG_SECURE-protected.RuneGridBackground.ktSecureFlagEffect.ktAcquires a reference-counted secure-window lease while this composable is in the composition — blocking screenshots, screen recording, and the recents thumbnail of screens that display secrets (MN-3: recovery words, export blob, codex generation).SecureWindowPolicy.ktThe only owner of [WindowManager.LayoutParams.FLAG_SECURE] transitions.SyncIndicatorDot.ktThe sync indicator light, shared by the vault list and the Sync settings card so the two can never disagree.TOTPRing.ktA small ring that sweeps once per TOTP period and turns breach-red in the final 5 seconds.lock/
onboarding/
pairing/
recovery/
security/
settings/
theme/
vault/
animating).TagChipEditor.ktMax tags per entry.TagListWidgets.ktHorizontally scrollable tag filter strip for VaultListScreen, placed between the search bar and the sort bar.TotpInlineEdit.ktE6 — TOTP double-tap to edit the 2FA secret, inline in EntryDetailScreen.TrashScreen.ktVaultHealthScreen.ktWarm amber used for the "reused" and "weak" advisory buckets.VaultListScreen.ktVaultListViewModel.ktupdates/
GET https://kepr.uk/api/<repo>/releases/latest, flattened to the single platform this app can install.UpdateRepository.ktThe Kepr side of in-app updates: what the newest release is, fetching its APK, and proving that APK is the one Kepr published before it is ever handed to the package installer.vault/
privateKeyJwk whether it arrives as a JSON object or a string, and writes it back as an object.LastViewedEntryStore.ktRemembers the id of the entry the user last opened so a fresh unlock can land straight back on it (matching the extension, which opens the last entry rather than the list).PasskeyData.ktPasswordGenerator.ktCryptographically random password generator.PasswordHistoryItem.ktOne past password kept in [VaultEntry.passwordHistory].PeachPayloadCodec.ktPeachScript binary payload (PCHS) — a byte-for-byte port of the browser's peachPayload.ts (MF-2).PeachScript.ktPeachScript outer codec — maps each payload byte to one Private-Use-Area code point in U+E000..U+E0FF, and back.PinUnlockStore.ktRecoveryWordList.ktRecovery word list — byte-identical to the browser's src/shared/recovery-word-list.ts: the canonical 2048-word BIP39 English list, 0-indexed, no duplicates.RecoveryWords.ktSavedIdentity.ktSyncEntrySanitizer.ktMN-3 (2026-06-09 audit, reopened 2026-08-03): content sanitization for entries arriving from a sync peer.TOTPGenerator.ktRFC 6238 TOTP / RFC 4226 HOTP.VaultCrypto.ktVaultEntry.ktVaultHealth.ktVaultLockTimer.ktIdle auto-lock timer.VaultRepository.ktLenient parser for the Codex vault-blob wrapper only.VaultSettings.ktVaultSlotRollback.ktRestores the durable slot set after a partially committed vault transaction.VaultSnapshot.ktVaultStore.ktOne encrypted slot at rest.res/xml/shortcuts.xml and the credential-provider unlock entry point in [com.peachpasswords.passkeys.PasskeyUnlockIntent].jniLibs/
arm64-v8a/
x86_64/
res/
drawable/
font/
layout/
mipmap-anydpi-v26/
values/
test/
java/
com/
peachpasswords/
autofill/
codex/
credentials/
feedback/
license/
passkeys/
security/
shared/
sync/
if (enabled && vault.isUnlocked.value) was wrong: the user almost always enables background sync from Settings while the vault is locked, so the service never started and the device stayed invisible to paired peers.BackgroundSyncPreferenceTest.ktC7TransportTest.ktC7 transport tests.CloudRelayDialerTest.ktPhone-to-phone: the case that had no initiator at all.CloudRelayReconnectListenerTest.ktEnough of a vault to send SYNC_HELLO; the peer stalls before anything else.CrossClientSyncProcessTest.ktProcess endpoint for scripts/check-cross-client-sync.mjs.DeviceManifestSupportTest.ktBounds tests for [verifyDeviceManifest].FakeSyncGeneration.ktIn-memory [SyncGenerationPort] for the JVM tests.ForegroundSyncCoordinatorTest.ktLegacyIdentityDerivation.ktRoot→device key derivation, retained for tests only — campaign task 2.4.LocalIdentityRecordTest.ktFrozen local-identity schema (campaign task 2.1): round trip, legacy completion, and every malformed-shape rejection.LockedSyncSpoolModelTest.ktNoiseKKTest.ktPairedDeviceAliasTest.ktPairedDeviceRevocationTest.ktPairedDeviceStoreConcurrencyTest.ktPairIdentityFramesTest.ktRegression coverage for M-08: the hand-rolled PAIR_IDENTITY encoder escaped ", \, and control bytes; the parser stopped at the next unescaped quote and never unescaped.PairingInvitationTest.ktPairingRelayLimitsTest.ktPB-26-205 (Android mirror): the pairing/adoption relay inbox is bounded before any allocate/copy of attacker-controlled frame data, with the same ceilings as the browser (src/shared/pairing-dial.ts).PeachWebSocketTest.ktExercises the server against OkHttp's RFC 6455 client rather than a hand-rolled one.RegistryTransactionTest.ktPure failure-injection coverage for the real SharedPreferences transaction helper.RelayAdoptionHostTest.ktRelayAdoptionInitiatorSourceTest.ktSource-initiator counterpart to [RelayAdoptionHostTest]: the phone dials the relay room, runs Noise as initiator, and sends the grant to the (empty) responder.RelayAdoptionReceiverTest.ktItem 2 (REVIEW_DEFERRED_ITEMS_BRIEF.md): receiver inline-snapshot happy-path.RelayGateTest.ktThe fail-closed relay gate, mirroring the browser's sync-settings.test.ts.RelaySettingsPropagationTest.ktWhat a relay change does to the existing mesh, mirroring the browser's setSyncMode / setRelayUrl.RendezvousTest.ktRustNoiseNativeCoverageTest.ktSourceConsentGateTest.ktPB-26-116: the vault-owning device must approve a pairing before the root key is read.SyncAlertTest.ktSyncCoordinatorTest.ktTwo in-memory [SyncSession]s wired back to back.SyncEntryEnvelopeKatTest.ktSyncFrameTransportTest.ktE7b end-to-end chunking — the deliverable for the wire shape.SyncFreshStartResetterTest.ktSyncGenerationTest.ktThe §11 secure-reset contract: the durable generation record, the six states, create-on-miss refusal, archival by generation, crash recovery at every step, and the sync gate.SyncNotificationPersistenceTest.ktSyncOutcomeTest.ktThe indicator light is the whole point of this vocabulary, so the mapping is swept exhaustively rather than sampled: a reason added later has to be given a place here or the sweep fails.SyncPaddingTest.ktSyncServiceStartTest.ktThe service start is the first step of every sync path, and it was the one step that could throw straight out of a button press: Android 12+ refuses a foreground service started from the background, and startForegroundService was called bare.SyncSuiteTest.ktSync suite (brief Suite 13): length-prefixed pairing frames, SAS derivation KAT, and cross-device entry sync through the [VaultSyncAdapter] (two repositories made to share a sync root key via the Codex blob).TrustDataCorruptedTest.kt§18.4: a corrupt persisted ledger must not be read as empty — that would silently un-revoke every device.VaultAdoptSnapshotTest.ktInline vault snapshot protocol parity with the browser vault-adopt-snapshot.test.ts.VaultAdoptTest.ktAdoption frame protocol parity with the browser vault-adopt.test.ts.VaultSyncAdapterTest.ktVaultSyncManifestEpochRaceTest.ktRegression for a stale signed manifest mutating only a prefix before relock.ui/
components/
lock/
onboarding/
pairing/
settings/
vault/
updates/
vault/
privateKeyJwk is a JSON OBJECT in the browser (JsonWebKey in shared/types.ts); Android holds it as a compact string.BrowserSlotTest.ktPins the browser→Android slot-A translation that Codex restore depends on.CardSerializationTest.ktIn-memory [VaultStorage] for exercising last4 derivation on save (MF-3).CodexRestoreAtomicityTest.ktC-01: a Codex restore must not touch the device's vault until the candidate has been decrypted and decoded in memory, and must roll back if any write in the commit fails.CrossPlatformRecoveryWordsTest.ktRecovery words are only a human-readable encoding of the root key's first 16 bytes, so the two platforms MUST agree on the word list byte for byte.CxfImportTest.ktCXF (FIDO Alliance Credential Exchange Format) passkey import.DecoySettingsIsolationTest.ktPB-26-120: the duress design promises that a decoy session looks like an ordinary installation and that everything it writes stays in the decoy.DuressCodexRoundTripTest.ktEnd-to-end Codex round-trip tests for the duress (slot B / decoy) slot.DuressPolicyRecordTest.ktPB-26-127: duress configuration and its action must not be readable from the stored record alone.DuressSlotBTest.ktIn-memory [VaultStorage] including a decoy (slot B) slot, for the MF-6 duress model.HiddenSessionStateTest.ktM-04: no operation may leave in-memory session state that disagrees with what is on disk, and the sync-key accessors must fail closed whenever the session is not a fully-unlocked real vault.ImportSettingsClassificationTest.ktPB-26-118: a PeachScript backup carries a settings record, and importing one used to apply the whole record — including the screen-capture control and the favicon consent flag, which the app elsewhere obtains only from the user.LockRaceAtomicityTest.ktH-03: lock() and requireUnlocked() must serialize with in-flight state mutations in suspend operations.OfficialCryptoVectorsTest.ktPasskeyConsolidationTest.ktPasskeyEntryTest.ktPasswordGeneratorTest.ktPasswordRotationAtomicityTest.ktH-01: a wrapping-key rotation (changePassword / resetPasswordWithRecoveryWords) must either fully commit slot A + size-matched noise slot B + version stamp or leave the at-rest state untouched.PeachScriptHardeningTest.ktM-02 regression tests: PeachScript parser must reject attacker-controlled lengths/counts before any unbounded allocation.PeachScriptRoundTripTest.ktPeachScript + CSV round-trip suite (brief Suite 7): large-vault fidelity, ciphertext tamper detection, size-bucket padding, and CSV column/injection behavior.PeachScriptTest.ktPinUnlockStoreTest.ktRecoveryEscrowIntegrationTest.ktIntegration coverage for the full create → confirm → seal → unlock recovery chain (brief Fix 1).RecoveryEscrowSuiteTest.ktRecoveryEscrow suite (brief Suite 3): word validation/autocomplete, partial and wrong-word failures, missing-escrow handling, recovery-driven password reset, and the duress-mode guard that recovery escrows are never sealed for the decoy.RecoveryEscrowTest.ktReplaceEntriesAtomicityTest.ktM-01: import's REPLACE mode must be one all-or-nothing write.SessionEpochRaceTest.ktDeterministic H-03 races.SlotAUnlockTest.ktIn-memory [VaultStorage] for the non-committing dual-derivation path (MF-5).SlotPaddingTest.ktExposes the raw stored slots so the padding lengths (MN-1) can be inspected.SnapshotRestoreAtomicityTest.ktH-02: a snapshot restore must either fully commit slot A + slot B + version stamp or leave every byte of at-rest state (slot A, slot B, history) untouched.SyncEntrySanitizerTest.ktMN-3: sync-peer entries are sanitized before merge — mirrors the browser's sanitizeRestoredEntry, with the Android allowance for flat passkey fields.TOTPGeneratorTest.ktVaultCryptoKdfTest.ktMF-4: the Argon2id KDF must hash the password's explicit UTF-8 bytes (matching the browser's TextEncoder().encode), not its UTF-16 code units.VaultCryptoTest.ktVaultCrypto suite (brief Suite 2): Argon2id key derivation, AES-256-GCM round-trips, AAD enforcement, and KDF parameters.VaultHealthAdvancedTest.ktVaultHealthTest.ktVaultHealth suite (brief Suite 8): the pure [VaultHealth.buildReport] scoring — breach / reused / weak / aged / sensitivity detection, section counts, and the sensitivity-weighted vault score.VaultKeyRotationHooksTest.ktPB-26-126: the PIN and biometric escrows wrap a copy of the slot-A key, so every rotation site must fire the invalidation signal.VaultLockTimerTest.ktIn-memory [VaultStorage] so the timer can drive a real repository off-device.VaultRepositoryExtraTest.ktSecond VaultRepository suite (brief Suite 1 expansion).VaultRepositoryTest.ktIn-memory [VaultStorage] so the repository can be exercised without Android.VaultSettingsDefaultsTest.ktGate for the new-install default.VaultSlotRollbackTest.ktwidget/
resources/
fixtures/
gradle/
releases/
scripts/
tasks/
docs/peach-android-independent-security-assessment-2026-09-01.pdf against the current v2.14.89 tree.security-assessment-2026-09-01-todo.mdPriority supersedes the unfinished PIN hardware-validation queue; that queue remains preserved in tasks/plan.md and tasks/todo.md for follow-up.todo.mdhistory
details
Peach for Android
A free, open source, local-first password manager for Android.
No accounts. No subscription. Your passwords stay on the device, encrypted with AES-256-GCM and protected by Argon2id key derivation. Sync, backup, and autofill happen without trusting any cloud in the middle.
Features
- Zero-knowledge vault — AES-256-GCM encryption, Argon2id KDF, keys never leave your device
- End-to-end encrypted sync — pairs with your other Peach devices over a Noise channel; the relay only forwards ciphertext it cannot read
- Inline autofill — fills directly in apps, no copy-paste detour
- Passkeys — WebAuthn credentials alongside your passwords
- Quick Settings tile — copy a credential from anywhere with a single tap
- Biometric unlock — hardware-backed AndroidKeyStore escrow, invalidated on enrollment change
- Codex — prints your encrypted vault as Aztec codes on paper. Physical offline backup
Open Source
Peach is free and open source under the GPL v3 license. Both the browser extension and the Android app.
The source is hosted on Kepr — Asha Software's own version control platform.
Security
Peach has undergone two adversarial analysis sessions against this codebase. The most recent findings have been resolved.
Cryptographic primitives:
- Key derivation: Argon2id (m=64MiB, t=3, p=4)
- Encryption: AES-256-GCM with fresh random nonces
- Sync handshake: Noise NK / Noise KK (25519, ChaChaPoly, BLAKE2s)
- Backup codec: GF(2⁸) Reed-Solomon with zstd compression
- BLAKE3 checksums throughout
The canonical Noise core lives in a shared Rust crate with the browser extension — Android drives it via JNI. See docs/CRYPTOGRAPHIC-TEST-VECTORS.md for the byte-level vectors that pin each primitive.
Building
./gradlew assembleRelease
Outputs to app/build/outputs/apk/release/. The shared Noise core is built from ../peach-browser/crypto-core.
License
GPL v3 — see LICENSE.
Peach Pro
Pro features (end-to-end encrypted sync, Codex, Canary) are available for $39 one-time at peachpasswords.com. Purchasing Pro supports continued development.
Built by Asha Software · [email protected]