From 67e7ce3d496c34a30ff498eaff2074543350318a Mon Sep 17 00:00:00 2001 From: cirakg Date: Sun, 25 Oct 2026 13:13:39 +0100 Subject: docs: 4-digit PIN, the offline-guessing limit, Manage needs Apply Co-Authored-By: Claude Opus 5.5 --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index f9030ef..228bba5 100644 --- a/README.md +++ b/README.md @@ -249,7 +249,7 @@ flowchart TD ### 7.2 PIN and key derivation -- The PIN is 4 to 10 digits. The app warns below 6. +- The PIN is exactly 4 digits, entered like the watch's own lock screen: the 4th digit submits it, with no OK key (changed after the real-watch test, 0.9.0). A PIN set by 0.8.0 or earlier (4 to 10 digits) still unlocks; the watch then asks for a new 4-digit PIN. - `PIN key = PBKDF2-HMAC-SHA256(PIN digits as ASCII, 16-byte random salt, N iterations, 32 bytes)`. - N is calibrated on your watch when you create or change the PIN, so one derivation takes about 1 s. It runs as a resumable job and is stored next to the salt. The lower and upper bounds for N are set from the M2 measurements. - The PIN key unwraps the locked master key. A correct PIN is exactly "the wrap's MAC verifies". No PIN hash is stored anywhere. @@ -325,7 +325,7 @@ On the first start after an install or update, and then once a day, the app runs | Someone picks up your watch while the app is closed | Locked entries: yes. Unlocked entries: no, by design | Lock what matters. Turn on Garmin's system passcode if your watch has one | | Someone grabs the watch during an unlocked session | Until auto-lock (default: 60 s without input) | Choose a shorter timeout, or "Immediately" | | Lost or stolen watch, attacker uses the screen | Locked entries: yes | Lockout delays, optional erase | -| Lost or stolen watch, attacker extracts the storage | Unlocked entries: no. Locked entries: only as strong as the PIN | 6 digits means 1,000,000 guesses, each costing one ~1 s PBKDF2 run on the watch but far less on a GPU: minutes to hours. Longer PINs help. Garmin's object-store encryption for Store apps may stop this; it's undocumented, so it isn't relied on | +| Lost or stolen watch, attacker extracts the storage | Unlocked entries: no. Locked entries: only as strong as the PIN | 4 digits means 10,000 guesses. Each costs one ~1 s PBKDF2 run on the watch but microseconds on a PC, so a copied storage falls in seconds. The PIN protects against someone using the watch (delays after wrong PINs, optional erase), not against a storage copy. Garmin's object-store encryption for Store apps may stop the copy; it's undocumented, so it isn't relied on. The debug build's files were visible over USB on the Forerunner 70 (part 4 of docs/YOUR_STEPS.md) | | Garmin's servers and the Garmin Connect app | No, for anything typed or pasted into settings | A consequence of D2 and D3: secrets travel in the clear. The watch clears the fields after reading them, but Garmin may keep copies | | Malware on your phone (clipboard, accessibility services) | No | It can read what you paste. Clear the clipboard and delete the Aegis export after importing | | Someone controlling your phone or Garmin account changes settings | Partly | They can add, or delete unlocked, entries. Changes to locked entries need your PIN on the watch ([7.9](#79-integrity-of-changes-coming-from-the-phone)) | @@ -621,7 +621,7 @@ A symbology counts as implemented only when checks 1 to 3 pass. Otherwise it's l - **OTP detail**: issuer and account, the code in large digits (grouped 3+3, 3+4 or 4+4), and a countdown ring along the bezel (a bar on rectangular screens) with the seconds left. In the last 5 seconds, the next code is shown. HOTP shows "Next" and the counter. Steam shows 5 characters. The entry ID is in small print at the bottom. - **Code detail**: the code centred on white, the name in small print if there's room, or a "Too large" message. - **PIN**: a keypad on touch screens; a digit selector on button-only watches. Digits show as dots. A wrong PIN vibrates (where available) and shows any waiting time. -- **Create or change PIN**: enter it twice. Warns below 6 digits. +- **Create or change PIN**: enter 4 digits twice. - **Menu**: Lock now, Change PIN, Reset PIN (erases locked entries), Settings results, Entry IDs, Clock status, About (version, storage use, self-test result). - **Glance**: "OTP Wallet ยท 12 entries". If you turn it on, it shows the code of the first favourite TOTP or Steam entry without the PIN, with a progress bar, instead ([docs/SECURITY.md](docs/SECURITY.md#glance-code)). @@ -664,11 +664,11 @@ stateDiagram-v2 PIN, touch PIN, buttons only Glance .-----------------. .-----------------. +----------------------+ / Enter PIN \ / Enter PIN \ | OTP Wallet | - | * * * o o o | | * * [5] o o o | | 12 entries | + | * * * o | | * * [5] o | | 12 entries | | 1 2 3 | | ^ | +----------------------+ | 4 5 6 | | UP/DOWN digit | (opt-in: favourite code | 7 8 9 | | START next | and a progress bar) - \ < 0 OK / \ BACK delete / + \ < 0 / \ BACK delete / '-----------------' '-----------------' ``` @@ -682,7 +682,7 @@ stateDiagram-v2 | Next HOTP code | Tap the code | START | | Menu | Long-press the list, or MENU | MENU (hold UP on most watches) | | Enter a PIN digit | Tap the keypad; the delete key deletes | UP/DOWN choose a digit, START adds it, BACK deletes | -| Confirm the PIN | OK on the keypad, or START | UP/DOWN to "OK", then START | +| Confirm the PIN | Automatic at the 4th digit | Automatic at the 4th digit | ## 14. Target devices and API levels @@ -941,7 +941,7 @@ Tests are written alongside the code, never after. ### 17.4 Simulator UI tests -- **Setup**: the UI-test build (`uitest.jungle`, `source/util/TestMode.mc`) starts with fake entries, the PIN 123456 and a frozen clock. `tools/ui_flow.py` drives it through xdotool: it clicks the buttons from the device files, and taps and swipes on touch screens. It waits for each screen's `DIAG shown` line instead of sleeping. +- **Setup**: the UI-test build (`uitest.jungle`, `source/util/TestMode.mc`) starts with fake entries, the PIN 1234 and a frozen clock. `tools/ui_flow.py` drives it through xdotool: it clicks the buttons from the device files, and taps and swipes on touch screens. It waits for each screen's `DIAG shown` line instead of sleeping. - **Screenshots** of every screen on the 4 test devices and the 3 spot-check devices are compared with approved goldens in `test/golden//`. At most 0.01 % of pixels may differ. - **Barcode screens** must decode with zxing-cpp. - **TOTP screens** are checked against the expected codes, from the debug build's view-model log and the golden image. @@ -1017,7 +1017,7 @@ The simulator runs on your PC's CPU, so its timings don't represent a watch. In | Large codes don't fit small screens | Some cards can't be shown | Validation and warnings at entry time | | Developer key lost | No updates possible | Backup instructions; `make nuke` confirmation | | Garmin changes the beta process | Can't install | Documented manual steps; checked in M1 | -| Short PINs can be broken offline | Locked secrets exposed if storage is extracted | Documented; longer PIN option; Garmin's object-store encryption as a bonus | +| Short PINs can be broken offline | Locked secrets exposed if storage is extracted | Documented in the user guide's known limitations; the PIN is fixed at 4 digits by the owner's choice (easier entry on the watch); Garmin's object-store encryption as a bonus | | The ~1 s PIN derivation feels slow | UX | Calibrated, with progress; one PIN per session (D1) | | Strict typing friction or compiler bugs | Slower development | SDK version pinned; issues documented | -- cgit v1.2.3