Repository navigation
Conversation
|
Thank you very much @kholia. I don't have time to look at this for real now - hopefully soon. Meanwhile, you could want to see why two CI jobs are failing here. |
4476c2c to
f0eb593
Compare
|
The CI infrastructure is running into problems: |
|
Why the name change for keypass2john.py? In general that is messy and can lead to problems in some setups. Did syntax/options change? |
|
Good point. I believe we can keep the same name as the script is mostly backwards compatible. |
f0eb593 to
59a7569
Compare
|
This is ready for another rounds of reviews - thanks! I believe that the CI failures were not related to this PR. |
When no dump/export action flag is given, the old script always emitted
the JtR password hash and exited cleanly. The rewrite introduced an
argparse default that caused check_args_no_action() to print "No action
specified." and exit(1) instead, breaking the typical JtR workflow:
keychain2john.py login.keychain | john --format=keychain ...
Fix check_args_no_action() to set dump_keychain_password_hash=True
(instead of aborting) when the user passes no explicit action flag.
Explicit flags like --dump-all, --dump-generic-passwords etc. continue
to work as before.
Also correct the misleading default=True on --dump-all's add_argument()
call, which was already overridden to False by set_defaults() and only
caused confusion.
Addresses magnumripper's review concern about syntax/options changes.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
811d789 to
c8640cf
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The extractor has broken default, output, and unlock paths, and the OpenCL backend does not perform v2 verification.
Review effort: Balanced
Findings: 1
Open (6)
Import DES3 for decryption and report missing dependency · New Support multiple keychain input files · New Restore default hash extraction for no-option invocation · New Honor console and disk output options without duplicate printing · New Remove unsafe debug print for missing SSGP data · New Reject v2 hashes in OpenCL backend without symkey verification · New
What changed in this PR
This PR aims to reduce false positives when cracking Apple Keychain passwords by checking an additional encrypted key blob.
Changes:
- Add a v2 hash format and symmetric-key verification while retaining the legacy format.
- Replace the keychain extractor with a broader Python parser and command-line options.
| File | Description |
|---|---|
src/keychain_fmt_plug.c |
Verifies v2 candidates against the encrypted key blob. |
src/keychain_common.h |
Defines the v2 tag and additional ciphertext fields. |
src/keychain_common_plug.c |
Parses and validates v2 hashes. |
run/keychain2john.py |
Extracts v2 hashes and adds dump and export options. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if len(data) % Chainbreaker.BLOCKSIZE != 0: | ||
| return b'' | ||
|
|
||
| cipher = DES3.new(key, DES3.MODE_CBC, IV=iv) |
| arguments = argparse.ArgumentParser(description='Dump items stored in an OSX Keychain') | ||
|
|
||
| # General Arguments | ||
| arguments.add_argument('keychain', help='Location of the keychain file to parse') |
| or args.export_x509_certificates): | ||
| logger.critical("No action specified.") | ||
| exit(1) |
| for record_collection in output: | ||
| if 'records' in record_collection: | ||
| for record in record_collection['records']: | ||
| if record_collection.get('write_to_console', False): | ||
| for line in str(record).split('\n'): | ||
| pass |
| ssgp, dbkey = self._extract_ssgp_and_dbkey(record_meta, buffer) | ||
| # print(ssgp, "XXX", ssgp.EncryptedPassword, ssgp.IV) | ||
| found_ssgps = True | ||
| print("[DEBUG]", ssgp, len(ssgp.EncryptedPassword), ssgp.IV, file=sys.stderr) |
| tag_len = keychain_tag_len(ciphertext); | ||
| if (!tag_len) | ||
| return 0; | ||
| is_v2 = (tag_len == FORMAT_TAG_V2_LEN); |


Closes #3408
This only took 14 years (after the initial format release in 2012)...
CC @magnumripper @solardiz