1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2019 Merlok
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
7 //-----------------------------------------------------------------------------
8 // MIFARE Application Directory (MAD) functions
9 //-----------------------------------------------------------------------------
16 // https://www.nxp.com/docs/en/application-note/AN10787.pdf
17 static madAIDDescr madKnownAIDs
[] = {
19 {0x0001, "defect, e.g. access keys are destroyed or unknown"},
21 {0x0003, "contains additional directory info"},
22 {0x0004, "contains card holder information in ASCII format."},
23 {0x0005, "not applicable (above memory size)"},
28 static madAIDDescr madKnownClusterCodes
[] = {
29 {0x00, "cluster: card administration"},
30 {0x01, "cluster: miscellaneous applications"},
31 {0x02, "cluster: miscellaneous applications"},
32 {0x03, "cluster: miscellaneous applications"},
33 {0x04, "cluster: miscellaneous applications"},
34 {0x05, "cluster: miscellaneous applications"},
35 {0x06, "cluster: miscellaneous applications"},
36 {0x07, "cluster: miscellaneous applications"},
37 {0x08, "cluster: airlines"},
38 {0x09, "cluster: ferry traffic"},
39 {0x10, "cluster: railway services"},
40 {0x11, "cluster: miscellaneous applications"},
41 {0x12, "cluster: transport"},
42 {0x14, "cluster: security solutions"},
43 {0x18, "cluster: city traffic"},
44 {0x19, "cluster: Czech Railways"},
45 {0x20, "cluster: bus services"},
46 {0x21, "cluster: multi modal transit"},
47 {0x28, "cluster: taxi"},
48 {0x30, "cluster: road toll"},
49 {0x31, "cluster: generic transport"},
50 {0x38, "cluster: company services"},
51 {0x40, "cluster: city card services"},
52 {0x47, "cluster: access control & security"},
53 {0x48, "cluster: access control & security"},
54 {0x49, "cluster: VIGIK"},
55 {0x4A, "cluster: Ministry of Defence, Netherlands"},
56 {0x4B, "cluster: Bosch Telecom, Germany"},
57 {0x4C, "cluster: European Union Institutions"},
58 {0x50, "cluster: ski ticketing"},
59 {0x51, "cluster: access control & security"},
60 {0x52, "cluster: access control & security"},
61 {0x53, "cluster: access control & security"},
62 {0x54, "cluster: access control & security"},
63 {0x55, "cluster: SOAA standard for offline access standard"},
64 {0x56, "cluster: access control & security"},
65 {0x58, "cluster: academic services"},
66 {0x60, "cluster: food"},
67 {0x68, "cluster: non-food trade"},
68 {0x70, "cluster: hotel"},
69 {0x71, "cluster: loyalty"},
70 {0x75, "cluster: airport services"},
71 {0x78, "cluster: car rental"},
72 {0x79, "cluster: Dutch government"},
73 {0x80, "cluster: administration services"},
74 {0x88, "cluster: electronic purse"},
75 {0x90, "cluster: television"},
76 {0x91, "cluster: cruise ship"},
77 {0x95, "cluster: IOPTA"},
78 {0x97, "cluster: metering"},
79 {0x98, "cluster: telephone"},
80 {0xA0, "cluster: health services"},
81 {0xA8, "cluster: warehouse"},
82 {0xB0, "cluster: electronic trade"},
83 {0xB8, "cluster: banking"},
84 {0xC0, "cluster: entertainment & sports"},
85 {0xC8, "cluster: car parking"},
86 {0xC9, "cluster: fleet management"},
87 {0xD0, "cluster: fuel, gasoline"},
88 {0xD8, "cluster: info services"},
89 {0xE0, "cluster: press"},
90 {0xE1, "cluster: NFC Forum"},
91 {0xE8, "cluster: computer"},
92 {0xF0, "cluster: mail"},
93 {0xF8, "cluster: miscellaneous applications"},
96 static const char unknownAID
[] = "";
98 static const char *GetAIDDescription(uint16_t AID
) {
99 for (int i
= 0; i
< ARRAYLEN(madKnownAIDs
); i
++)
100 if (madKnownAIDs
[i
].AID
== AID
)
101 return madKnownAIDs
[i
].Description
;
103 for (int i
= 0; i
< ARRAYLEN(madKnownClusterCodes
); i
++)
104 if (madKnownClusterCodes
[i
].AID
== (AID
>> 8)) // high byte - cluster code
105 return madKnownClusterCodes
[i
].Description
;
110 int madCRCCheck(uint8_t *sector
, bool verbose
, int MADver
) {
112 uint8_t crc
= CRC8Mad(§or
[16 + 1], 15 + 16);
113 if (crc
!= sector
[16]) {
114 PrintAndLogEx(WARNING
, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver
, crc
, sector
[16]);
118 uint8_t crc
= CRC8Mad(§or
[1], 15 + 16 + 16);
119 if (crc
!= sector
[0]) {
120 PrintAndLogEx(WARNING
, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver
, crc
, sector
[16]);
128 uint16_t madGetAID(uint8_t *sector
, int MADver
, int sectorNo
) {
130 return (sector
[16 + 2 + (sectorNo
- 1) * 2] << 8) + (sector
[16 + 2 + (sectorNo
- 1) * 2 + 1]);
132 return (sector
[2 + (sectorNo
- 1) * 2] << 8) + (sector
[2 + (sectorNo
- 1) * 2 + 1]);
135 int MADCheck(uint8_t *sector0
, uint8_t *sector10
, bool verbose
, bool *haveMAD2
) {
141 uint8_t GPB
= sector0
[3 * 16 + 9];
143 PrintAndLogEx(NORMAL
, "GPB: 0x%02x", GPB
);
145 // DA (MAD available)
147 PrintAndLogEx(ERR
, "DA=0! MAD not available.");
151 // MA (multi-application card)
154 PrintAndLogEx(NORMAL
, "Multi application card.");
156 PrintAndLogEx(NORMAL
, "Single application card.");
159 uint8_t MADVer
= GPB
& 0x03;
161 PrintAndLogEx(NORMAL
, "MAD version: %d", MADVer
);
164 if ((MADVer
!= 0x01) && (MADVer
!= 0x02)) {
165 PrintAndLogEx(ERR
, "Wrong MAD version: 0x%02x", MADVer
);
170 *haveMAD2
= (MADVer
== 2);
172 res
= madCRCCheck(sector0
, true, 1);
175 PrintAndLogEx(NORMAL
, "CRC8-MAD1 OK.");
177 if (MADVer
== 2 && sector10
) {
178 int res2
= madCRCCheck(sector10
, true, 2);
183 PrintAndLogEx(NORMAL
, "CRC8-MAD2 OK.");
189 int MADDecode(uint8_t *sector0
, uint8_t *sector10
, uint16_t *mad
, size_t *madlen
) {
191 bool haveMAD2
= false;
192 MADCheck(sector0
, sector10
, false, &haveMAD2
);
194 for (int i
= 1; i
< 16; i
++) {
195 mad
[*madlen
] = madGetAID(sector0
, 1, i
);
200 // mad2 sector (0x10 == 16dec) here
201 mad
[*madlen
] = 0x0005;
204 for (int i
= 1; i
< 24; i
++) {
205 mad
[*madlen
] = madGetAID(sector10
, 2, i
);
214 int MAD1DecodeAndPrint(uint8_t *sector
, bool verbose
, bool *haveMAD2
) {
217 MADCheck(sector
, NULL
, verbose
, haveMAD2
);
220 uint8_t InfoByte
= sector
[16 + 1] & 0x3f;
222 PrintAndLogEx(NORMAL
, "Card publisher sector: 0x%02x", InfoByte
);
225 PrintAndLogEx(NORMAL
, "Card publisher sector not present.");
227 if (InfoByte
== 0x10 || InfoByte
>= 0x28)
228 PrintAndLogEx(WARNING
, "Info byte error");
230 PrintAndLogEx(NORMAL
, "00 MAD1");
231 for (int i
= 1; i
< 16; i
++) {
232 uint16_t AID
= madGetAID(sector
, 1, i
);
233 PrintAndLogEx(NORMAL
, "%02d [%04X] %s", i
, AID
, GetAIDDescription(AID
));
239 int MAD2DecodeAndPrint(uint8_t *sector
, bool verbose
) {
240 PrintAndLogEx(NORMAL
, "16 MAD2");
242 int res
= madCRCCheck(sector
, true, 2);
245 PrintAndLogEx(NORMAL
, "CRC8-MAD2 OK.");
247 uint8_t InfoByte
= sector
[1] & 0x3f;
248 PrintAndLogEx(NORMAL
, "MAD2 Card publisher sector: 0x%02x", InfoByte
);
250 for (int i
= 1; i
< 8 + 8 + 7 + 1; i
++) {
251 uint16_t AID
= madGetAID(sector
, 2, i
);
252 PrintAndLogEx(NORMAL
, "%02d [%04X] %s", i
+ 16, AID
, GetAIDDescription(AID
));