Skip to content

fix(mifare): handle readable Key B fields correctly - #973

Merged
GameTec-live merged 4 commits into
GameTec-live:mainfrom
oSPANNERo:fix-readable-mfc-keyb
Aug 20, 2026
Merged

fix(mifare): handle readable Key B fields correctly#973
GameTec-live merged 4 commits into
GameTec-live:mainfrom
oSPANNERo:fix-readable-mfc-keyb

Conversation

@oSPANNERo

@oSPANNERo oSPANNERo commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

## Summary

Fix MIFARE Classic recovery handling for sector trailers where Key B is configured as readable data.

Previously, these Key B fields could remain displayed as failed/unresolved keys even though the sector trailer was successfully readable with Key A.

This change:

- adds a distinct readable state for Key B
- checks the sector trailer access conditions after finding Key A
- marks readable Key B fields as resolved without treating them as authentication keys
- displays readable Key B fields with a separate visibility icon
- keeps readable Key B data out of validKeys
- allows the card-returned Key B bytes to remain intact in dumps
- prevents readable Key B data from being exported as recovered authentication keys

## Testing

Tested against a physical MIFARE Classic 1K card with readable Key B fields.

Verified:

- readable Key B fields are displayed distinctly instead of as failed keys
- recovered Key A authentication keys remain displayed normally
- card-returned Key B field bytes are preserved in the resulting dump
- readable Key B data is not exported by "Export found keys"
- flutter analyze --no-pub reports no issues related to this change
~~ - one unrelated existing deprecation remains in lib/helpers/font.dart~~
- flutter test --no-pub: 18 tests passed
- Windows release build completed successfully

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

The PR distinguishes readable MIFARE Classic Key B trailer data from recovered authentication keys.

  • Adds a dedicated readable checkmark state and tooltip.
  • Verifies Key B through a memory-read operation before storing it in validKeys.
  • Tracks readable Key B bytes separately and treats those sectors as resolved.
  • Updates the MIFARE Classic UI and widget test for the new data field.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
chameleonultragui/lib/helpers/mifare_classic/recovery.dart Adds separate readable-Key-B state management, access-condition decoding, and authentication-key validation.
chameleonultragui/lib/gui/component/key_check_marks.dart Adds the readable-data input and renders readable Key B fields with a distinct tooltip and icon.
chameleonultragui/lib/gui/component/mifare/classic.dart Supplies recovery-readable data to the key-checkmark widget.
chameleonultragui/test/key_check_marks_test.dart Updates the widget test setup for the new required readable-data input.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Recover Key A] --> B[Read sector trailer]
  B --> C{Key B field readable?}
  C -- No --> D[Continue Key B recovery]
  C -- Yes --> E[Extract returned Key B bytes]
  E --> F{Usable for memory access?}
  F -- Yes --> G[Store in validKeys as found]
  F -- No --> H[Store in readableData as readable]
Loading

Reviews (2): Last reviewed commit: "feat(mifare): show readable Key B data i..." | Re-trigger Greptile

@oSPANNERo

oSPANNERo commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

### Additional validation

I performed another round of targeted testing using a purpose-built MIFARE Classic 1K emulator image to exercise mixed Key B access states within the same card.

The test image alternated sector trailer configurations:

- Even sectors: FF 07 80 69
~~ - Key B is readable as trailer data~~
~~ - Key B is not usable for authentication~~
- Odd sectors: F7 8F 00 69
~~ - Key B is protected~~
~~ - Key B is usable as an authentication key~~

With all relevant authentication keys supplied, the patched GUI produced the expected mixed result:

- all Key A values resolved normally
- readable Key B fields were shown with the new readable/visibility state
- protected Key B authentication keys were shown as normal recovered keys

I then created a second test case with two deliberately missing authentication keys:

1. Sector 2
~~ - trailer ACL: FF 07 80 69~~
~~ - Key A deliberately omitted~~
~~ - expected result: Key A unresolved, Key B unresolved~~
~~ - observed result: A = unresolved, B = unresolved~~

~~ This confirms the GUI does not assume that B is readable merely from expected/test metadata. It only marks B as readable after successfully authenticating to the sector and reading/validating the trailer ACL.~~

2. Sector 10
~~ - trailer ACL: FF 07 80 69~~
~~ - Key A known~~
~~ - expected result: A = recovered, B = readable~~
~~ - observed result: A = recovered, B = readable/visibility state~~

3. Sector 11
~~ - trailer ACL: F7 8F 00 69~~
~~ - Key A known~~
~~ - protected Key B deliberately omitted~~
~~ - expected result: A = recovered, B = unresolved~~
~~ - observed result: A = recovered, B = unresolved~~

This gives three useful control cases in the same image:

| Case | Key A | Key B configuration | Expected | Observed |
|---|---|---|---|---|
| A unavailable, B would be readable | Unknown | Readable (FF078069) | A unresolved, B unresolved | Pass |
| A available, B readable | Known | Readable (FF078069) | A recovered, B readable | Pass |
| A available, protected B unknown | Known | Protected (F78F0069) | A recovered, B unresolved | Pass |

The test also confirms that the new readable state is only assigned after an authenticated trailer read and ACL evaluation, rather than being inferred or treated as an authentication-key success.

Combined with the earlier physical-card testing, dump verification, dictionary-export verification, unit tests, analyzer run, and successful Windows release build, the behavior appears consistent across both readable and protected Key B configurations.

GameTec-live
GameTec-live previously approved these changes Aug 19, 2026
@oSPANNERo
oSPANNERo marked this pull request as draft August 19, 2026 17:16
@oSPANNERo

Copy link
Copy Markdown
Contributor Author

Summary

Fix MIFARE Classic recovery handling for sector trailers where Key B is configured as readable data.

Previously, readable Key B fields could remain displayed as failed or unresolved keys even though the sector trailer was successfully readable with Key A. Successful Key B authentication was also not consistently followed by a real memory-access check before the value was accepted as a usable authentication key.

This change:

  • adds a distinct readable state for Key B
  • checks sector-trailer access conditions after finding Key A
  • extracts readable Key B field bytes from the card-returned trailer
  • verifies actual Key B memory access before promoting those bytes to a valid authentication key
  • applies the same Key B validation to dictionary candidates and rechecked/recovered keys
  • continues checking later candidates when an auth-only Key B candidate fails the memory-access test
  • displays readable-only Key B fields with a blue visibility icon
  • shows the returned bytes in the blue-eye tooltip as Data: <hex>
  • keeps readable-only Key B data separate from validKeys
  • prevents readable-only Key B data from being exported as recovered authentication keys

Testing

Tested against both a physical MIFARE Classic 1K card and a controlled Proxmark3 state-matrix emulator image.

Physical card validation

  • readable Key B bytes were recovered through Key A
  • the same Key B values successfully performed memory access on the tested card
  • those values were therefore promoted to normal green Key B entries
  • an A-only input dictionary produced all 16 A and all 16 B entries as valid
  • exported recovered keys matched the complete known A+B set exactly

State-matrix regression validation

  • readable Key B fields that could be read from the trailer but could not perform Key B memory access remained blue/readable-only
  • protected Key B values supplied by the dictionary remained green/valid
  • deliberately unresolved sector cases remained unresolved
  • blue-eye tooltips display the exact returned bytes, e.g. Data: E0E1E2E3E400
  • exported recovered-key dictionary contained exactly 22 usable authentication keys
  • no readable-only E0E1E2E3E4xx values were exported
  • pre- and post-tooltip export files had the same SHA-256: 5f55ca8ed56f14f365961aaaa31a04b7b70face1698cd8805640791ada279a2f

Build/test validation

  • flutter analyze --no-pub reports no issues related to this change
    • one unrelated existing deprecation remains in lib/helpers/font.dart
  • flutter test --no-pub: 18 tests passed
  • Windows release build completed successfully

@oSPANNERo

Copy link
Copy Markdown
Contributor Author

Current findings and regression testing

I completed additional regression testing around the revised Key B handling, including both a physical MIFARE Classic 1K card and a purpose-built Proxmark3 state-matrix image.

The current behavior is now:

  • If Key A is valid, the sector trailer is read and the ACL is evaluated.
  • If the ACL makes the Key B field readable, the actual 6 bytes returned by the card are extracted.
  • Those bytes are then tested as Key B for real memory access.
    • If memory access succeeds, Key B is treated as a valid authentication key, shown normally, stored in validKeys, and included in exports.
    • If memory access fails, the value remains classified as readable data only, shown with the blue visibility icon, and is kept out of validKeys and authentication-key exports.
  • Key B values discovered through the dictionary/recheck paths are also subjected to the same memory-access validation before being accepted.
  • If one candidate authenticates but fails the memory-access test, later candidates in the same set are still checked.

Physical card

The physical MIFARE Classic 1K card used for testing has sector trailers configured with FF 07 80 69, where the Key B field is readable through Key A.

Using an A-only dictionary:

  • all 16 Key A values resolved
  • all 16 Key B values were obtained from the readable trailer fields
  • all 16 Key B values also passed the subsequent memory-access test
  • all B entries were therefore correctly promoted to normal valid/green keys
  • the exported dictionary contained the complete known A+B key set

This is significant because those B values were not supplied by the dictionary. They were recovered from the card-returned trailer data and independently validated before being accepted.

State-matrix regression

A second test used a controlled MIFARE Classic 1K emulator image with mixed sector states:

  • even sectors: FF 07 80 69, readable Key B field
  • odd sectors: F7 8F 00 69, protected/authentication Key B

The emulator follows the expected behavior where the readable E0E1E2E3E4xx B-field values do not provide usable Key B memory access.

The patched GUI produced the expected distinction:

  • readable-but-not-usable B values remained blue/readable-only
  • protected B authentication keys supplied by the dictionary were green
  • Sector 2 remained A/B unresolved because its valid Key A was deliberately omitted
  • Sector 11 showed A valid and B unresolved because its protected Key B was deliberately omitted

This confirms that the readable state is not inferred simply from the test image or ACL pattern. The GUI must first authenticate with A, successfully read the trailer, and evaluate the returned ACL before classifying the B field.

The readable-only values are also now visible directly in the tooltip, for example:

Data: E0E1E2E3E400

Export regression

The state-matrix export contained exactly 22 usable authentication keys:

  • 15 valid Key A values
  • 7 valid protected Key B values
  • 0 readable-only E0E1E2E3E4xx values

The exported dictionary before and after adding the readable-data tooltip was byte-for-byte equivalent:

SHA-256: 5f55ca8ed56f14f365961aaaa31a04b7b70face1698cd8805640791ada279a2f

This confirms that storing the readable bytes separately for display does not contaminate validKeys or the recovered-key export.

Build/test regression

  • flutter analyze --no-pub
    • no issues related to this change
    • one unrelated pre-existing deprecation remains in lib/helpers/font.dart
  • flutter test --no-pub
    • 18/18 tests passed
  • Windows release build completed successfully
  • physical-card and emulator GUI testing completed successfully

At this point the two important cases are both represented correctly: a readable B field can remain data-only when it cannot actually be used as Key B, while a card that returns readable B bytes that also work for memory access can have those values promoted to valid authentication keys.

@GameTec-live
GameTec-live merged commit 04be0ad into GameTec-live:main Aug 20, 2026
12 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Chameleon Ultra GUI Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants