]> git.zerfleddert.de Git - proxmark3-svn/blame - client/mifare/mad.c
'lf hitag writer': add Hitag2 password auth
[proxmark3-svn] / client / mifare / mad.c
CommitLineData
fdd9395d
OM
1//-----------------------------------------------------------------------------
2// Copyright (C) 2019 Merlok
3//
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
6// the license.
7//-----------------------------------------------------------------------------
8// MIFARE Application Directory (MAD) functions
9//-----------------------------------------------------------------------------
10
11#include "mad.h"
12#include "ui.h"
13#include "crc.h"
14#include "util.h"
15
16// https://www.nxp.com/docs/en/application-note/AN10787.pdf
17static madAIDDescr madKnownAIDs[] = {
18 {0x0000, "free"},
19 {0x0001, "defect, e.g. access keys are destroyed or unknown"},
20 {0x0002, "reserved"},
21 {0x0003, "contains additional directory info"},
22 {0x0004, "contains card holder information in ASCII format."},
23 {0x0005, "not applicable (above memory size)"},
24
25 {0x03e1, "NDEF"},
26};
27
28static 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"},
94};
95
96static const char unknownAID[] = "";
97
98static 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;
102
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;
106
107 return unknownAID;
108}
109
110int madCRCCheck(uint8_t *sector, bool verbose, int MADver) {
111 if (MADver == 1) {
112 uint8_t crc = CRC8Mad(&sector[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]);
115 return 3;
116 };
117 } else {
118 uint8_t crc = CRC8Mad(&sector[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]);
121 return 3;
122 };
123 }
124
125 return 0;
126}
127
128uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) {
129 if (MADver == 1)
130 return (sector[16 + 2 + (sectorNo - 1) * 2] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2 + 1]);
131 else
132 return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]);
133}
134
135int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) {
136 int res = 0;
137
138 if (!sector0)
139 return 1;
140
141 uint8_t GPB = sector0[3 * 16 + 9];
142 if (verbose)
143 PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB);
144
145 // DA (MAD available)
146 if (!(GPB & 0x80)) {
147 PrintAndLogEx(ERR, "DA=0! MAD not available.");
148 return 1;
149 }
150
151 // MA (multi-application card)
152 if (verbose) {
153 if (GPB & 0x40)
154 PrintAndLogEx(NORMAL, "Multi application card.");
155 else
156 PrintAndLogEx(NORMAL, "Single application card.");
157 }
158
159 uint8_t MADVer = GPB & 0x03;
160 if (verbose)
161 PrintAndLogEx(NORMAL, "MAD version: %d", MADVer);
162
163 // MAD version
164 if ((MADVer != 0x01) && (MADVer != 0x02)) {
165 PrintAndLogEx(ERR, "Wrong MAD version: 0x%02x", MADVer);
166 return 2;
167 };
168
169 if (haveMAD2)
170 *haveMAD2 = (MADVer == 2);
171
172 res = madCRCCheck(sector0, true, 1);
173
174 if (verbose && !res)
175 PrintAndLogEx(NORMAL, "CRC8-MAD1 OK.");
176
177 if (MADVer == 2 && sector10) {
178 int res2 = madCRCCheck(sector10, true, 2);
179 if (!res)
180 res = res2;
181
182 if (verbose & !res2)
183 PrintAndLogEx(NORMAL, "CRC8-MAD2 OK.");
184 }
185
186 return res;
187}
188
189int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen) {
190 *madlen = 0;
191 bool haveMAD2 = false;
192 MADCheck(sector0, sector10, false, &haveMAD2);
193
194 for (int i = 1; i < 16; i++) {
195 mad[*madlen] = madGetAID(sector0, 1, i);
196 (*madlen)++;
197 }
198
199 if (haveMAD2) {
200 // mad2 sector (0x10 == 16dec) here
201 mad[*madlen] = 0x0005;
202 (*madlen)++;
203
204 for (int i = 1; i < 24; i++) {
205 mad[*madlen] = madGetAID(sector10, 2, i);
206 (*madlen)++;
207 }
208 }
209
210 return 0;
211}
212
213
214int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) {
215
216 // check MAD1 only
217 MADCheck(sector, NULL, verbose, haveMAD2);
218
219 // info byte
220 uint8_t InfoByte = sector[16 + 1] & 0x3f;
221 if (InfoByte) {
222 PrintAndLogEx(NORMAL, "Card publisher sector: 0x%02x", InfoByte);
223 } else {
224 if (verbose)
225 PrintAndLogEx(NORMAL, "Card publisher sector not present.");
226 }
227 if (InfoByte == 0x10 || InfoByte >= 0x28)
228 PrintAndLogEx(WARNING, "Info byte error");
229
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));
234 };
235
236 return 0;
237};
238
239int MAD2DecodeAndPrint(uint8_t *sector, bool verbose) {
240 PrintAndLogEx(NORMAL, "16 MAD2");
241
242 int res = madCRCCheck(sector, true, 2);
243
244 if (verbose && !res)
245 PrintAndLogEx(NORMAL, "CRC8-MAD2 OK.");
246
247 uint8_t InfoByte = sector[1] & 0x3f;
248 PrintAndLogEx(NORMAL, "MAD2 Card publisher sector: 0x%02x", InfoByte);
249
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));
253 };
254
255 return 0;
256};
Impressum, Datenschutz