17 Commits

Author SHA1 Message Date
Roger 0fe35542f2 feat(keys): add cross-host master key export (#599) 2026-05-16 20:24:19 +08:00
Roger ecf8ba0585 refactor(browser): simplify credential storage config (#593) 2026-05-14 16:29:35 +08:00
Roger 15680c1512 refactor(keyretriever): reduce duplicate master-key WARN logs (#589) 2026-04-25 22:00:33 +08:00
Roger 7b9a973c9c fix: per-tier master-key retrievers for mixed-cipher profiles (#579)
* fix: per-tier master-key retrievers for mixed-cipher profiles
2026-04-20 17:33:38 +08:00
Roger e50c623db0 fix: retrieve correct ABE master key when browser is running (#577)
* fix(windows): retrieve correct ABE master key when browser is running
2026-04-19 20:07:51 +08:00
Roger ae1ec66ccb refactor(windows): split Windows code into winapi (#575) 2026-04-19 18:12:37 +08:00
Roger 76e2615db2 refactor(windows): clean up Chrome ABE module (#574)
* refactor(abe): remove --abe-key flag and its global state
* refactor(abe): rework scratch protocol and Go/C structure
2026-04-19 15:20:51 +08:00
slimwang c3d30b9e8a feat(windows): Chrome App-Bound Encryption implementation (#573)
* build(abe): add zig-cc payload build system + C reflective loader
* feat(abe): add reflective injector and Go ABE key-retriever primitives
* feat(abe): wire ABERetriever into DefaultRetriever chain + --abe-key CLI
* feat(abe): route Chromium v20 ciphertext through AES-GCM with ABE key
2026-04-18 23:25:59 +08:00
Roger eb58ebbbf4 fix: support Linux v11 cipher prefix for Chromium decryption (#571) 2026-04-13 22:12:40 +08:00
Roger 370c5882c4 feat: add Safari password extraction from macOS Keychain (#568) 2026-04-13 21:34:40 +08:00
Roger a0b4412bf2 fix: share key retriever across all browsers to avoid repeated prompts (#560)
* fix: share key retriever across all browsers to avoid repeated password prompts
2026-04-06 21:57:52 +08:00
Roger ccc8643d86 feat: add interactive terminal password prompt for keychain unlock (#558)
* feat(darwin): add interactive terminal password prompt for keychain unlock (#556)
* test: add unit tests for keyretriever and address review feedback

- Add errStorageNotFound sentinel error for precise error matching
- Non-TTY TerminalPasswordRetriever returns nil silently (review #558)
- Add darwin tests: findStorageKey, empty password, non-TTY skip
- Add linux tests: FallbackRetriever peanuts key, DefaultRetriever chain

* fix: add nolint:unused for errStorageNotFound on Windows, clean up error message

errStorageNotFound is only used on darwin/linux; Windows lint flagged it
as unused. Also simplify error format to avoid "storage" duplication.

* fix: add nolint:unused for errStorageNotFound, simplify error message

errStorageNotFound is only referenced on darwin and linux; Windows lint
flags it as unused. Also remove redundant "storage" prefix from the
error format string.
2026-04-06 01:27:13 +08:00
Roger 410bffe643 refactor: naming cleanup and crypto package improvements (#551)
* refactor: naming cleanup across all packages
2026-04-05 16:51:56 +08:00
Roger a58d432688 fix: cache keychain retriever across browser profiles on macOS (#545)
Share a single KeyRetriever instance across all profiles of the same
browser, and add sync.Once caching to GcoredumpRetriever and
SecurityCmdRetriever. This avoids repeated keychain password prompts
(or securityd memory dumps) when extracting multiple profiles.

Closes #544
2026-04-04 18:36:49 +08:00
Roger 92053b85b0 chore: update golangci-lint config and fix lint issues (#542)
* chore: update golangci-lint config and fix lint issues
2026-04-04 16:26:07 +08:00
Roger 2c4e871e59 fix: strip host_key prefix from Chrome 130+ cookie values (#526)
* fix: strip SHA256(host_key) prefix from Chrome 130+ cookie values

Chrome 130 (Cookie DB schema v24) prepends SHA256(domain) to cookie
values before encryption to prevent cross-domain replay attacks.
After decryption, this 32-byte hash must be verified and stripped.

Changes:
- Add stripCookieHash() that verifies SHA256(host_key) and strips
  the prefix only when it matches (auto-compatible with older Chrome)
- Fix edge case: cookies with empty values (exactly 32 bytes = hash only)
- Add decrypt_test.go with v10 round-trip encryption/decryption test
- Add stripCookieHash test cases for v24+, older Chrome, empty values,
  short values, and host mismatch scenarios

Closes #524

* fix: strip SHA256(host_key) prefix from Chrome 130+ cookie values

Chrome 130 (Cookie DB schema v24) prepends SHA256(domain) to cookie
values before encryption to prevent cross-domain replay attacks.
After decryption, this 32-byte hash must be verified and stripped.

Changes:
- Add stripCookieHash() that verifies SHA256(host_key) and strips
  the prefix only when it matches (auto-compatible with older Chrome)
- Fix edge case: cookies with empty values (exactly 32 bytes = hash only)
- Add table-driven decrypt tests for v10/v20/DPAPI per platform
- Add Windows-specific DPAPI round-trip test using CryptProtectData
- Add shared testAESKey constant in testutil_test.go
- Add stripCookieHash tests for v24+, older Chrome, empty values,
  short values, and host mismatch scenarios
- Extend lint CI to run on ubuntu, windows, and macos

Closes #524

* fix: remove DPAPI test from darwin/linux (returns nil on Linux)

DecryptWithDPAPI returns nil error on Linux (silent no-op) but error
on macOS, causing the test to fail on Ubuntu CI. DPAPI round-trip
testing is properly covered in decrypt_windows_test.go.

* fix: resolve Windows CI lint errors exposed by multi-platform lint

- Add _ = before windows.CloseHandle calls to satisfy errcheck
- Add build tag to params.go (only used on macOS/Linux, not Windows)

* fix: add .gitattributes to force LF and refactor cookie tests

- Add .gitattributes with `* text=auto eol=lf` to prevent CRLF
  conversion on Windows CI causing gofumpt false positives
- Add .gitattributes to .gitignore whitelist
- Refactor stripCookieHash tests into table-driven style

* fix: address Copilot review on decrypt tests

- Assert error on wrong key instead of ignoring it (AES-CBC returns
  padding error, not silent empty result)
- Guard empty plaintext in encryptWithDPAPI to prevent nil pointer panic
- Convert uint32 to int for make/copy slice bounds in Windows test

* fix: assert specific error message in wrong key decrypt test
2026-04-04 01:41:01 +08:00
Roger 9fb5165fcb feat: add crypto/keyretriever with keychainbreaker integration (#518)
* feat: add crypto/keyretriever package for Chromium master key retrieval

* feat: complete keyretriever with gcoredump, chainbreaker, and tests

* refactor: replace internal chainbreaker with keychainbreaker v0.1.0

Replace the incomplete internal chainbreaker implementation (~1400 lines
of duplicated code) with the external keychainbreaker package, which
provides a complete, well-tested keychain parsing library.

Changes:
- Add github.com/moond4rk/keychainbreaker v0.1.0 dependency
- Update gcoredump_darwin.go to use keychainbreaker API (Open/Unlock/GenericPasswords)
- Add KeychainPasswordRetriever for password-based keychain unlocking
  with sync.Once caching across multiple browser queries
- Unify DefaultRetriever(keychainPassword string) signature across all platforms
- Delete utils/chainbreaker/ (696 lines + test + testdata)
- Delete crypto/keyretriever/chainbreaker_darwin.go (696 lines duplicate)
- Delete browser/exploit/gcoredump/ (duplicate of keyretriever version)
- Update chromium_darwin.go to use keyretriever.DecryptKeychain
- Clean up .golangci.yml lint exceptions and .gitignore entries
- Use errors.Is() instead of == for context.DeadlineExceeded check

* refactor: improve gcoredump exploit code quality and add comments
* fix: address Copilot review feedback on keyretriever
2026-04-04 01:41:01 +08:00