mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-05 20:57:28 +00:00
679 lines
24 KiB
Markdown
679 lines
24 KiB
Markdown
# MIFARE DESFire dump file format
|
|
|
|
<a id="top"></a>
|
|
|
|
The `mfdes v1` json format is the on-disk image of a DESFire PICC: the card level
|
|
details, every application, every file's settings, and the file contents that
|
|
could actually be read. It is what `hf mfdes dump` writes and `hf mfdes view`
|
|
reads, and it is the format an emulator-memory loader (`hf mfdes eload`) will be
|
|
built on.
|
|
|
|
# Table of Contents
|
|
|
|
- [MIFARE DESFire dump file format](#mifare-desfire-dump-file-format)
|
|
- [Table of Contents](#table-of-contents)
|
|
- [Commands](#commands)
|
|
- [File identity](#file-identity)
|
|
- [Card level](#card-level)
|
|
- [Applications](#applications)
|
|
- [Files](#files)
|
|
- [Common fields](#common-fields)
|
|
- [Standard and backup data files](#standard-and-backup-data-files)
|
|
- [Value files](#value-files)
|
|
- [Record files](#record-files)
|
|
- [Transaction MAC files](#transaction-mac-files)
|
|
- [Keys](#keys)
|
|
- [The Read flag](#the-read-flag)
|
|
- [Token spellings](#token-spellings)
|
|
- [A complete example](#a-complete-example)
|
|
- [The card](#the-card)
|
|
- [The key file](#the-key-file)
|
|
- [The dump file](#the-dump-file)
|
|
- [What `hf mfdes view` makes of it](#what-hf-mfdes-view-makes-of-it)
|
|
- [In-memory representation](#in-memory-representation)
|
|
- [Not in v1](#not-in-v1)
|
|
|
|
## Commands
|
|
^[Top](#top)
|
|
|
|
```
|
|
hf mfdes dump walk the whole PICC, save hf-mfdes-<UID>-dump.json
|
|
hf mfdes dump --aid 123456 dump only that application
|
|
hf mfdes dump --keys <fn> take per-application keys from a `hf mfdes chk` key file
|
|
hf mfdes dump --ns collect and print, save nothing
|
|
hf mfdes dump -f myfile save under a name of your choosing
|
|
hf mfdes view -f <fn> print a dump file, no device needed
|
|
```
|
|
|
|
With no `--keys`, the dump looks for `hf-mfdes-<UID>-keys.json` by itself, so a
|
|
`hf mfdes chk -j hf-mfdes-<UID>-keys` run is picked up on the next dump without
|
|
naming the file again.
|
|
|
|
With no `--aid` / `--isoid` / `--dfname` the command walks every application the
|
|
PICC lists. The default filename is `hf-mfdes-<UID>-dump.json`; only json is
|
|
written, there is no `.bin` companion.
|
|
|
|
## File identity
|
|
^[Top](#top)
|
|
|
|
```json
|
|
{
|
|
"Created": "proxmark3",
|
|
"FileType": "mfdes v1",
|
|
"Version": 1
|
|
}
|
|
```
|
|
|
|
`FileType` is what the loader dispatches on. `Version` is the same number in
|
|
machine-readable form. A reader that does not understand a `FileType` must
|
|
refuse the file rather than guess -- `mfdes v2` is already taken by the key
|
|
recovery output of `hf mfdes chk`, which is a different, much smaller format.
|
|
|
|
## Card level
|
|
^[Top](#top)
|
|
|
|
Everything under `$.Card` describes the PICC itself.
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `UID` | hex | 4 or 7 byte UID from the 14a select |
|
|
| `ATQA` | hex, 2 bytes | wire order, the same way every other pm3 dump format stores it. `hf 14a info` prints the two bytes the other way round |
|
|
| `SAK` | hex, 1 byte | |
|
|
| `ATS` | hex | answer to RATS, absent when the card gave none |
|
|
| `VersionHW` | hex, 7 bytes | first `GetVersion` frame: vendor, type, subtype, major, minor, storage, protocol |
|
|
| `VersionSW` | hex, 7 bytes | second `GetVersion` frame, same field order |
|
|
| `VersionProd` | hex, 14 bytes | third `GetVersion` frame: UID and production details |
|
|
| `Signature` | hex, 56 bytes | NXP originality signature, absent when the card refused it |
|
|
| `FreeMem` | int | bytes reported by `GetFreeMem`, absent when the card refused it |
|
|
|
|
Absent means the field is not written at all. Do not read a missing field as a
|
|
zero.
|
|
|
|
`GetVersion` answers over three chained frames and they are stored as three
|
|
fields rather than one blob, because the third frame is not the same shape
|
|
across generations: D40 and EV1 close it with `UID || BatchNo[5] || CW || Year`
|
|
while EV3 re-cuts it as `UID || BatchNo[3] || TypeID[2] || CW || Year`. Each
|
|
frame is kept raw, so any generation round-trips without the format having to
|
|
know which one it is holding.
|
|
|
|
`VersionHW` bytes 3 and 4 -- major and minor -- are what identify the
|
|
generation. `client/src/mifare/prime.c` maps them: EV1 is `01 00`, EV2 is
|
|
`12 00` or `42 00`, EV2 XL `22 00`, EV3 `33 00`, DuoX `A0 00`. Byte 5 is the
|
|
storage size code, `2^(n>>1)` bytes.
|
|
|
|
Nothing key related lives here. The PICC master key settings and keys belong to
|
|
application `000000` -- see [Applications](#applications) -- so every key in the
|
|
file states which AID it opens.
|
|
|
|
## Applications
|
|
^[Top](#top)
|
|
|
|
`$.Applications` is an object keyed by the 3-byte AID as 6 uppercase hex digits.
|
|
|
|
**The PICC level is application `000000`.** It carries the PICC master key
|
|
settings and keys and has no files. Giving it an AID of its own is the point: a
|
|
key in this file always says which application it opens.
|
|
|
|
```json
|
|
"Applications": {
|
|
"000000": {
|
|
"KeySettings": "0F",
|
|
"NumKeysRaw": "01",
|
|
"NumKeys": 1,
|
|
"KeyType": "2tdea",
|
|
"Authenticated": true,
|
|
"Keys": {
|
|
"0": { "Version": "00", "Key": "00000000000000000000000000000000" }
|
|
}
|
|
},
|
|
"F51800": {
|
|
"ISOFileID": "DF01",
|
|
"DFName": "D2760000850100",
|
|
"KeySettings": "0B",
|
|
"NumKeysRaw": "81",
|
|
"NumKeys": 1,
|
|
"KeyType": "aes",
|
|
"Authenticated": true,
|
|
"Keys": { },
|
|
"Files": { }
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `ISOFileID` | hex, 2 bytes | ISO DF ID, absent when the application has none |
|
|
| `DFName` | hex, 1-16 bytes | ISO DF name, absent when the application has none |
|
|
| `KeySettings` | hex, 1 byte | |
|
|
| `NumKeysRaw` | hex, 1 byte | raw key-count byte, carries the key type in the top bits and the ISO-file-id flag in bit 5 |
|
|
| `NumKeys` | int | key count decoded from `NumKeysRaw` |
|
|
| `KeyType` | token | `des`, `2tdea`, `3tdea` or `aes`. One per application -- every key in an application shares it |
|
|
| `Authenticated` | bool | whether the dump ran authenticated against this application |
|
|
| `Keys` | object | see [Keys](#keys) |
|
|
| `Files` | object | see [Files](#files) |
|
|
|
|
`Authenticated: false` is the flag that says how much to trust the rest of the
|
|
application: settings and contents may be whatever the card hands out to an
|
|
unauthenticated reader, which on many cards is nothing at all.
|
|
|
|
JSON objects are unordered. A reader must look applications and files up by
|
|
key, not by position.
|
|
|
|
## Files
|
|
^[Top](#top)
|
|
|
|
`Files` is an object keyed by the file number as 2 uppercase hex digits.
|
|
|
|
### Common fields
|
|
^[Top](#top)
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `Type` | token | see [Token spellings](#token-spellings) |
|
|
| `TypeRaw` | hex, 1 byte | the file type byte as the card reported it. This is the authoritative one, `Type` is for humans |
|
|
| `ISOFileID` | hex, 2 bytes | absent when the file has none |
|
|
| `CommMode` | token | `plain`, `mac`, `plain_rfu` or `encrypt`, from the raw 2-bit file comm mode |
|
|
| `AccessRights` | hex, 2 bytes | raw access rights word: read, write, read/write, change, 4 bits each |
|
|
| `AdditionalAccessRights` | object | index -> 2 byte rights word, absent when the file has none |
|
|
| `Read` | bool | see [The Read flag](#the-read-flag) |
|
|
|
|
### Standard and backup data files
|
|
^[Top](#top)
|
|
|
|
`TypeRaw` `00` and `01`.
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `FileSize` | int | size the card reports |
|
|
| `Data` | hex | contents. May be shorter than `FileSize` when `hf mfdes dump --length` capped the read |
|
|
|
|
### Value files
|
|
^[Top](#top)
|
|
|
|
`TypeRaw` `02`. A value file has no `Data`.
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `LowerLimit` | int | |
|
|
| `UpperLimit` | int | |
|
|
| `LimitedCredit` | hex, 1 byte | |
|
|
| `Value` | int | present only when `Read` is true |
|
|
|
|
### Record files
|
|
^[Top](#top)
|
|
|
|
`TypeRaw` `03` (linear) and `04` (cyclic).
|
|
|
|
| Field | Type | Meaning |
|
|
|---|---|---|
|
|
| `RecordSize` | int | bytes per record |
|
|
| `MaxRecords` | int | |
|
|
| `CurRecords` | int | |
|
|
| `Records` | object | record index -> hex string of exactly `RecordSize` bytes |
|
|
|
|
Records are numbered from `0` and must be contiguous. A record file whose
|
|
contents could not be split into whole records falls back to a single flat
|
|
`Data` string instead of `Records`.
|
|
|
|
### Transaction MAC files
|
|
^[Top](#top)
|
|
|
|
`TypeRaw` `05`. Stored like a data file: the 12 byte answer goes in `Data`
|
|
(4 byte counter, 8 byte MAC), and is not decoded further.
|
|
|
|
## Keys
|
|
^[Top](#top)
|
|
|
|
Keys are part of the image, not a side file. A simulator cannot answer an
|
|
authentication without them, and splitting them across two files means a card
|
|
image that silently cannot be used.
|
|
|
|
Every application, `000000` included, carries a `Keys` object keyed by key
|
|
number in decimal:
|
|
|
|
```json
|
|
"Keys": {
|
|
"0": { "Version": "00", "Key": "E757178E13516A4F3171BC6EA85E165A" },
|
|
"1": { "Version": "03" }
|
|
}
|
|
```
|
|
|
|
| Field | Meaning |
|
|
|---|---|
|
|
| `Version` | the key version, as read from the card. Present whenever we managed to read it |
|
|
| `Key` | the key itself. Present only when we actually have it |
|
|
|
|
A key version is readable without knowing the key, so the two are independent:
|
|
|
|
* **`Version` and `Key`** -- we read the version and we have the key.
|
|
* **`Version` only** -- the key exists, we know its version, we could not
|
|
recover it. This is the normal case for every key but the one we authenticated
|
|
with. A missing `Key` never means the key is all zeros.
|
|
* **entry absent entirely** -- we know nothing about that key number.
|
|
|
|
There is no per-key algorithm. Every key in an application uses the
|
|
application's `KeyType`, which fixes the length: `des` 8 bytes, `2tdea` 16,
|
|
`3tdea` 24, `aes` 16.
|
|
|
|
Note the difference from the `mfdes v2` key recovery format written by
|
|
`hf mfdes chk`, which nests keys under an algorithm name
|
|
(`Applications.112233.AES.0.Key`) because during recovery the key type is not
|
|
yet known. In a dump it is, so the algorithm is stated once per application.
|
|
|
|
`hf mfdes dump` reads a `mfdes v2` key file with `--keys <fn>`, and with no
|
|
`--keys` it looks for `hf-mfdes-<UID>-keys.json` on its own -- the same filename
|
|
template it saves the dump under. Nothing is reported if that file does not
|
|
exist.
|
|
|
|
## The Read flag
|
|
^[Top](#top)
|
|
|
|
Every file carries `Read`. It is true only when the contents were actually
|
|
fetched from the card.
|
|
|
|
* `Read: true` with `Data` -- these are the card's bytes.
|
|
* `Read: true` without `Data` (or with an empty one) -- the card answered, with nothing in it.
|
|
* `Read: false` -- we never got the contents. Access was denied, the key was
|
|
wrong, or the session died. There is no `Data` key at all.
|
|
|
|
A reader must never turn a missing `Data` into zeros. The whole point of the
|
|
flag is that "8 bytes of 00" and "we could not read 8 bytes" are different
|
|
facts, and a simulator that confuses them will confidently answer a reader with
|
|
contents the card never had.
|
|
|
|
## Token spellings
|
|
^[Top](#top)
|
|
|
|
String tokens match what the `hf mfdes` CLI already accepts, so a value read out
|
|
of a dump file can be handed straight back to a command.
|
|
|
|
| `Type` | `TypeRaw` |
|
|
|---|---|
|
|
| `standard` | `00` |
|
|
| `backup` | `01` |
|
|
| `value` | `02` |
|
|
| `linear_record` | `03` |
|
|
| `cyclic_record` | `04` |
|
|
| `transaction_mac` | `05` |
|
|
|
|
| `CommMode` | raw |
|
|
|---|---|
|
|
| `plain` | `0` |
|
|
| `mac` | `1` |
|
|
| `plain_rfu` | `2` |
|
|
| `encrypt` | `3` |
|
|
|
|
`plain_rfu` is the card's second encoding for plain. It is kept distinct from
|
|
`plain` so the file records what the card actually said.
|
|
|
|
| `KeyType` | key length |
|
|
|---|---|
|
|
| `des` | 8 |
|
|
| `2tdea` | 16 |
|
|
| `3tdea` | 24 |
|
|
| `aes` | 16 |
|
|
|
|
Hex strings are uppercase with no separators. Byte order is as the bytes travel
|
|
on the wire, except `AccessRights` and the ISO file IDs, which are written big
|
|
endian the way they are printed.
|
|
|
|
## A complete example
|
|
^[Top](#top)
|
|
|
|
A real dump of a MIFARE DESFire EV2 2K, set up from blank with the commands
|
|
below. Every construct in this document appears in it: the PICC as application
|
|
`000000`, an AES application and a 2TDEA one, a standard data file, a value
|
|
file, a record file, and keys that are known by version but not by value.
|
|
|
|
### The card
|
|
^[Top](#top)
|
|
|
|
```
|
|
# two applications, one AES with 3 keys, one 2TDEA with 2
|
|
hf mfdes createapp -t 2tdea -k 00000000000000000000000000000000 --aid 112233 --fid 1122 --dfname pm3test1 --ks1 0F --ks2 A3
|
|
hf mfdes createapp -t 2tdea -k 00000000000000000000000000000000 --aid 445566 --fid 4455 --dfname pm3test2 --ks1 0F --ks2 22
|
|
|
|
# ks2 carries the key type in the top two bits (0 = 2TDEA, 1 = 3TDEA, 2 = AES),
|
|
# the ISO-file-id flag in bit 5 and the key count in the low five. It overrides
|
|
# --dstalgo and --numkeys, so A3 is "AES, ISO file ids, 3 keys"
|
|
|
|
# files in the AES application
|
|
hf mfdes createfile --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 01 --isofid 0001 --size 000020 --amode encrypt --rrights key0 --wrights key0 --rwrights key0 --chrights key0
|
|
hf mfdes createvaluefile --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 02 --amode mac --lower 00000000 --upper 000003E8 --value 0000002A --lcredit 1 --rrights key0 --wrights key0 --rwrights key0 --chrights key0
|
|
hf mfdes createrecordfile --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 03 --isofid 0003 --size 000008 --maxrecord 000005 --amode plain --rrights free --wrights key0 --rwrights key0 --chrights key0
|
|
|
|
# and one in the 2TDEA application
|
|
hf mfdes createfile --aid 445566 -t 2tdea -k 00000000000000000000000000000000 --fid 00 --isofid 0010 --size 000010 --amode plain --rrights free --wrights key0 --rwrights key0 --chrights key0
|
|
|
|
# contents
|
|
hf mfdes write --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 01 -d 50726F786D61726B33204445534669726520746573742064617461212121
|
|
hf mfdes write --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 03 --type record -d 5245434F52443031
|
|
hf mfdes write --aid 112233 -t aes -k 00000000000000000000000000000000 --fid 03 --type record -d 5245434F52443032
|
|
hf mfdes write --aid 445566 -t 2tdea -k 00000000000000000000000000000000 --fid 00 -d 48454C4C4F2050524F584D41524B2133
|
|
|
|
# recover the application keys, saved under the name the dump will look for
|
|
hf mfdes chk -k 00000000000000000000000000000000 -j hf-mfdes-043240CAE45380-keys
|
|
|
|
# and dump it
|
|
hf mfdes dump -t 2tdea -k 00000000000000000000000000000000
|
|
|
|
# to put the card back the way it was
|
|
hf mfdes formatpicc -t 2tdea -k 00000000000000000000000000000000
|
|
```
|
|
|
|
Without that `chk` run, application `112233` cannot be opened with the 2TDEA
|
|
PICC key. The dump does not pretend otherwise: it records the application with
|
|
`"Authenticated": false` and no files, rather than inventing empty ones.
|
|
|
|
### The key file
|
|
^[Top](#top)
|
|
|
|
`hf-mfdes-043240CAE45380-keys.json`, written by `hf mfdes chk -j`. This is the
|
|
separate `mfdes v2` format, not part of the card image -- `hf mfdes dump` reads
|
|
it and folds the keys it contains into the dump.
|
|
|
|
```json
|
|
{
|
|
"Created": "proxmark3",
|
|
"FileType": "mfdes v2",
|
|
"Card": {
|
|
"UID": "043240CAE45380",
|
|
"SAK": "20",
|
|
"ATQA": "4403",
|
|
"ATS": "06757781028002F0"
|
|
},
|
|
"Applications": {
|
|
"112233": {
|
|
"AES": {
|
|
"0": {
|
|
"Key": "00000000000000000000000000000000"
|
|
}
|
|
}
|
|
},
|
|
"445566": {
|
|
"2TDEA": {
|
|
"0": {
|
|
"Key": "00000000000000000000000000000000"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Two differences from the way the dump stores keys:
|
|
|
|
* Keys are nested under an **algorithm name** (`Applications.112233.AES.0.Key`)
|
|
because during key recovery the application's key type is not yet known. A
|
|
dump knows it, so it states `KeyType` once per application instead.
|
|
* PICC keys are not in this file at all. `hf mfdes chk` only walks the
|
|
application list; the PICC master key is the one you hand it with `-k`.
|
|
|
|
The dump picks this file up without `--keys` because its name follows the same
|
|
`hf-mfdes-<UID>-` template the dump itself is saved under:
|
|
|
|
```
|
|
[=] Loaded keys for 2 application(s) from `hf-mfdes-043240CAE45380-keys`
|
|
```
|
|
|
|
### The dump file
|
|
^[Top](#top)
|
|
|
|
```json
|
|
{
|
|
"Created": "proxmark3",
|
|
"FileType": "mfdes v1",
|
|
"Version": 1,
|
|
"Card": {
|
|
"UID": "043240CAE45380",
|
|
"ATQA": "4403",
|
|
"SAK": "20",
|
|
"ATS": "06757781028002F0",
|
|
"VersionHW": "04010112001605",
|
|
"VersionSW": "04010102001605",
|
|
"VersionProd": "043240CAE45380CD651745414216",
|
|
"Signature": "035766BD56631ED57B614CE01A24372BDC29028A310937BC42EE998C66E56E6251083B723099D80EB77291B1A8BDB055C614EC944A11E38E",
|
|
"FreeMem": 1984
|
|
},
|
|
"Applications": {
|
|
"000000": {
|
|
"KeySettings": "0F",
|
|
"NumKeysRaw": "01",
|
|
"NumKeys": 1,
|
|
"KeyType": "2tdea",
|
|
"Authenticated": true,
|
|
"Keys": {
|
|
"0": {
|
|
"Version": "00",
|
|
"Key": "00000000000000000000000000000000"
|
|
}
|
|
}
|
|
},
|
|
"112233": {
|
|
"ISOFileID": "1122",
|
|
"DFName": "706D337465737431",
|
|
"KeySettings": "0F",
|
|
"NumKeysRaw": "83",
|
|
"NumKeys": 3,
|
|
"KeyType": "aes",
|
|
"Authenticated": true,
|
|
"Keys": {
|
|
"0": {
|
|
"Version": "00",
|
|
"Key": "00000000000000000000000000000000"
|
|
},
|
|
"1": {
|
|
"Version": "00"
|
|
},
|
|
"2": {
|
|
"Version": "00"
|
|
}
|
|
},
|
|
"Files": {
|
|
"01": {
|
|
"Type": "standard",
|
|
"TypeRaw": "00",
|
|
"CommMode": "encrypt",
|
|
"AccessRights": "0000",
|
|
"ISOFileID": "0001",
|
|
"FileSize": 32,
|
|
"Read": true,
|
|
"Data": "50726F786D61726B332044455346697265207465737420646174612121210000"
|
|
},
|
|
"02": {
|
|
"Type": "value",
|
|
"TypeRaw": "02",
|
|
"CommMode": "mac",
|
|
"AccessRights": "0000",
|
|
"LowerLimit": 0,
|
|
"UpperLimit": 1000,
|
|
"LimitedCredit": "01",
|
|
"Value": 42,
|
|
"Read": true
|
|
},
|
|
"03": {
|
|
"Type": "linear_record",
|
|
"TypeRaw": "03",
|
|
"CommMode": "plain",
|
|
"AccessRights": "E000",
|
|
"ISOFileID": "0003",
|
|
"RecordSize": 8,
|
|
"MaxRecords": 5,
|
|
"CurRecords": 2,
|
|
"Read": true,
|
|
"Records": {
|
|
"0": "5245434F52443031",
|
|
"1": "5245434F52443032"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"445566": {
|
|
"ISOFileID": "4455",
|
|
"DFName": "706D337465737432",
|
|
"KeySettings": "0F",
|
|
"NumKeysRaw": "02",
|
|
"NumKeys": 2,
|
|
"KeyType": "2tdea",
|
|
"Authenticated": true,
|
|
"Keys": {
|
|
"0": {
|
|
"Version": "00",
|
|
"Key": "00000000000000000000000000000000"
|
|
},
|
|
"1": {
|
|
"Version": "00"
|
|
}
|
|
},
|
|
"Files": {
|
|
"00": {
|
|
"Type": "standard",
|
|
"TypeRaw": "00",
|
|
"CommMode": "plain",
|
|
"AccessRights": "E000",
|
|
"ISOFileID": "0010",
|
|
"FileSize": 16,
|
|
"Read": true,
|
|
"Data": "48454C4C4F2050524F584D41524B2133"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Things to read out of it:
|
|
|
|
* **`FreeMem` is 1984** with the two applications in place. Measured on this same
|
|
card: 2080 free before the example was built, 1984 with it, and 2560 after
|
|
`hf mfdes formatpicc`. A format therefore reclaims space that creating and
|
|
deleting applications leaves behind -- 0 applications on its own does not mean
|
|
a fully free card.
|
|
* **`NumKeysRaw` `83`** decodes to `KeyType: aes` (top bits 10), ISO file ids
|
|
enabled (bit 5) and `NumKeys: 3`.
|
|
* **Keys 1 and 2 of `112233` have a `Version` but no `Key`.** They exist, we
|
|
read their version, we never recovered them. Key 0 is the one `hf mfdes chk`
|
|
found.
|
|
* **The value file has no `Data`**, only `Value`, `LowerLimit`, `UpperLimit`
|
|
and `LimitedCredit`.
|
|
* **The record file has `Records`, not `Data`** -- two records of 8 bytes in a
|
|
file with room for five.
|
|
* **File `01` reads 32 bytes** where only 30 were written; the card zero-pads to
|
|
the file size, and the dump stores what the card returned.
|
|
|
|
### What `hf mfdes view` makes of it
|
|
^[Top](#top)
|
|
|
|
```
|
|
|
|
[=] --- Tag Information ---------------------------
|
|
[+] UID.............. 043240CAE45380
|
|
[+] ATQA............. 03 44
|
|
[+] SAK.............. 20
|
|
[+] ATS.............. 06757781028002F0
|
|
[+] Version HW....... 04010112001605
|
|
[+] 12.0 ( DESFire EV2 )
|
|
[+] Storage size... 0x16 ( 2048 bytes )
|
|
[+] Version SW....... 04010102001605
|
|
[+] Production....... 043240CAE45380CD651745414216
|
|
[+] Signature........ 035766BD56631ED57B614CE01A24372BDC29028A310937BC42EE998C66E56E6251083B723099D80EB77291B1A8BDB055C614EC944A11E38E
|
|
[+] Free memory...... 1984 bytes
|
|
|
|
[=] --- Applications ------------------------------
|
|
[+] 2 application(s) plus the PICC level
|
|
|
|
[=] --- AID 000000 ( PICC level ) ---------------------
|
|
[+] Key settings. 0F, 1 2tdea key(s)
|
|
[+] Authenticated yes
|
|
[+] Key 00 (ver 00). 00000000000000000000000000000000
|
|
[+] Files........ 0
|
|
|
|
[=] --- AID 112233 --------------------------------
|
|
[+] ISO DF ID.... 1122
|
|
[+] DF name...... pm3test1 ( 706D337465737431 )
|
|
[+] Key settings. 0F, 3 aes key(s)
|
|
[+] Authenticated yes
|
|
[+] Key 00 (ver 00). 00000000000000000000000000000000
|
|
[+] Key 01 (ver 00). not recovered
|
|
[+] Key 02 (ver 00). not recovered
|
|
[+] Files........ 3
|
|
|
|
[+] File 01 - Standard data
|
|
[+] ISO file ID.. 0001
|
|
[+] Comm mode.... encrypt
|
|
[+] Access rights 0000
|
|
[+] File size.... 32
|
|
|
|
[=] Offset | Data | Ascii
|
|
[=] ----------------------------------------------------------------------------
|
|
[=] 0/0x00 | 50 72 6F 78 6D 61 72 6B 33 20 44 45 53 46 69 72 | Proxmark3 DESFir
|
|
[=] 16/0x10 | 65 20 74 65 73 74 20 64 61 74 61 21 21 21 00 00 | e test data!!!..
|
|
|
|
[+] File 02 - Value
|
|
[+] Comm mode.... mac
|
|
[+] Access rights 0000
|
|
[+] Limits....... 0 ... 1000
|
|
[+] Value........ 42 (0x0000002A)
|
|
|
|
[+] File 03 - Linear Record
|
|
[+] ISO file ID.. 0003
|
|
[+] Comm mode.... plain
|
|
[+] Access rights E000
|
|
[+] Records...... 2 of 5, 8 bytes each
|
|
|
|
[+] Record 0
|
|
[=] Offset | Data | Ascii
|
|
[=] ----------------------------------------------------------------------------
|
|
[=] 0/0x00 | 52 45 43 4F 52 44 30 31 | RECORD01
|
|
[+] Record 1
|
|
[=] 0/0x00 | 52 45 43 4F 52 44 30 32 | RECORD02
|
|
|
|
[=] --- AID 445566 --------------------------------
|
|
[+] ISO DF ID.... 4455
|
|
[+] DF name...... pm3test2 ( 706D337465737432 )
|
|
[+] Key settings. 0F, 2 2tdea key(s)
|
|
[+] Authenticated yes
|
|
[+] Key 00 (ver 00). 00000000000000000000000000000000
|
|
[+] Key 01 (ver 00). not recovered
|
|
[+] Files........ 1
|
|
|
|
[+] File 00 - Standard data
|
|
[+] ISO file ID.. 0010
|
|
[+] Comm mode.... plain
|
|
[+] Access rights E000
|
|
[+] File size.... 16
|
|
|
|
[=] Offset | Data | Ascii
|
|
[=] ----------------------------------------------------------------------------
|
|
[=] 0/0x00 | 48 45 4C 4C 4F 20 50 52 4F 58 4D 41 52 4B 21 33 | HELLO PROXMARK!3
|
|
```
|
|
|
|
## In-memory representation
|
|
^[Top](#top)
|
|
|
|
`desfire_dump_t` in `client/src/fileutils.h`, written by `prepareJSON()` and read
|
|
by `loadFileJSONex()` in `client/src/fileutils.c`.
|
|
|
|
File contents hang off `desfire_dump_file_t` as heap pointers, so an image can
|
|
hold real file sizes without the struct itself being enormous. Whoever fills or
|
|
loads one owns those buffers and must call `desfire_dump_free()` before dropping
|
|
the image.
|
|
|
|
The struct is bounded by `DESFIRE_MAX_APP_COUNT` (64) applications and
|
|
`DESFIRE_MAX_FILE_COUNT` (32) files per application, both in `include/desfire.h`.
|
|
Reading a file with more than that logs a warning and keeps the first N.
|
|
|
|
## Not in v1
|
|
^[Top](#top)
|
|
|
|
Deliberately absent, listed so the next version does not have to rediscover them:
|
|
|
|
* **No emulator memory layout.** This format is a card image, not a memory map.
|
|
How a PICC image is packed into the 4096 bytes of `CARD_MEMORY_SIZE` is a
|
|
separate problem, and the answer will not fit a large card.
|
|
* **No delegated application / DAM slot details.**
|
|
* **No key derivation state.** If a key in the file came out of AN10922 or the
|
|
Gallagher KDF, only the derived key is stored, not the diversification input.
|
|
* **No LRP / EV2 secure channel state**, no transaction counter, no `TI`.
|
|
* **No ISO 7816 file structure** beyond the ISO file IDs.
|