]> git.zerfleddert.de Git - proxmark3-svn/blame - client/mifare/mifare4.c
Update README.md
[proxmark3-svn] / client / mifare / mifare4.c
CommitLineData
fdd9395d
OM
1//-----------------------------------------------------------------------------
2// Copyright (C) 2018 Merlok
3// Copyright (C) 2018 drHatson
4//
5// This code is licensed to you under the terms of the GNU GPL, version 2 or,
6// at your option, any later version. See the LICENSE.txt file for the text of
7// the license.
8//-----------------------------------------------------------------------------
9// iso14443-4 mifare commands
10//-----------------------------------------------------------------------------
11
12#include "mifare4.h"
13#include <ctype.h>
14#include <string.h>
15#include "cmdhf14a.h"
16#include "util.h"
17#include "ui.h"
18#include "crypto/libpcrypto.h"
19
20static bool VerboseMode = false;
21void mfpSetVerboseMode(bool verbose) {
22 VerboseMode = verbose;
23}
24
25typedef struct {
26 uint8_t Code;
27 const char *Description;
28} PlusErrorsElm;
29
30static const PlusErrorsElm PlusErrors[] = {
31 {0xFF, ""},
32 {0x00, "Transfer cannot be granted within the current authentication."},
33 {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."},
34 {0x07, "Too many read or write commands in the session or in the transaction."},
35 {0x08, "Invalid MAC in command or response"},
36 {0x09, "Block Number is not valid"},
37 {0x0a, "Invalid block number, not existing block number"},
38 {0x0b, "The current command code not available at the current card state."},
39 {0x0c, "Length error"},
40 {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."},
41 {0x90, "OK"},
42};
43int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
44
45const char *mfpGetErrorDescription(uint8_t errorCode) {
46 for (int i = 0; i < PlusErrorsLen; i++)
47 if (errorCode == PlusErrors[i].Code)
48 return PlusErrors[i].Description;
49
50 return PlusErrors[0].Description;
51}
52
53AccessConditions_t MFAccessConditions[] = {
54 {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"},
55 {0x01, "read AB; decrement transfer restore AB"},
56 {0x02, "read AB"},
57 {0x03, "read B; write B"},
58 {0x04, "read AB; writeB"},
59 {0x05, "read B"},
60 {0x06, "read AB; write B; increment B; decrement transfer restore AB"},
61 {0x07, "none"}
62};
63
64AccessConditions_t MFAccessConditionsTrailer[] = {
65 {0x00, "read A by A; read ACCESS by A; read B by A; write B by A"},
66 {0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"},
67 {0x02, "read ACCESS by A; read B by A"},
68 {0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"},
69 {0x04, "write A by B; read ACCESS by AB; write B by B"},
70 {0x05, "read ACCESS by AB; write ACCESS by B"},
71 {0x06, "read ACCESS by AB"},
72 {0x07, "read ACCESS by AB"}
73};
74
75char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) {
76 static char StaticNone[] = "none";
77
78 uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn;
79 uint8_t data2 = ((data[2]) & 0x0f) >> blockn;
80 uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn;
81
82 uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01);
83
84 if (blockn == 3) {
85 for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++)
86 if (MFAccessConditionsTrailer[i].cond == cond) {
87 return MFAccessConditionsTrailer[i].description;
88 }
89 } else {
90 for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++)
91 if (MFAccessConditions[i].cond == cond) {
92 return MFAccessConditions[i].description;
93 }
94 };
95
96 return StaticNone;
97};
98
99int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) {
100 memcpy(&iv[0], session->TI, 4);
101 memcpy(&iv[4], &session->R_Ctr, 2);
102 memcpy(&iv[6], &session->W_Ctr, 2);
103 memcpy(&iv[8], &session->R_Ctr, 2);
104 memcpy(&iv[10], &session->W_Ctr, 2);
105 memcpy(&iv[12], &session->R_Ctr, 2);
106 memcpy(&iv[14], &session->W_Ctr, 2);
107
108 return 0;
109}
110
111int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) {
112 memcpy(&iv[0], &session->R_Ctr, 2);
113 memcpy(&iv[2], &session->W_Ctr, 2);
114 memcpy(&iv[4], &session->R_Ctr, 2);
115 memcpy(&iv[6], &session->W_Ctr, 2);
116 memcpy(&iv[8], &session->R_Ctr, 2);
117 memcpy(&iv[10], &session->W_Ctr, 2);
118 memcpy(&iv[12], session->TI, 4);
119
120 return 0;
121}
122
123
124int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) {
125 if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1)
126 return 1;
127
128 memset(mac, 0x00, 8);
129
130 uint16_t ctr = session->R_Ctr;
131 switch (mtype) {
132 case mtypWriteCmd:
133 case mtypWriteResp:
134 ctr = session->W_Ctr;
135 break;
136 case mtypReadCmd:
137 case mtypReadResp:
138 break;
139 }
140
141 uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0};
142 int macdatalen = datalen;
143 memcpy(&macdata[3], session->TI, 4);
144
145 switch (mtype) {
146 case mtypReadCmd:
147 memcpy(&macdata[7], &data[1], datalen - 1);
148 macdatalen = datalen + 6;
149 break;
150 case mtypReadResp:
151 macdata[7] = blockNum;
152 macdata[8] = 0;
153 macdata[9] = blockCount;
154 memcpy(&macdata[10], &data[1], datalen - 1);
155 macdatalen = datalen + 9;
156 break;
157 case mtypWriteCmd:
158 memcpy(&macdata[7], &data[1], datalen - 1);
159 macdatalen = datalen + 6;
160 break;
161 case mtypWriteResp:
162 macdatalen = 1 + 6;
163 break;
164 }
165
166 if (verbose)
167 PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen));
168
169 return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen);
170}
171
172int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) {
173 uint8_t data[257] = {0};
174 int datalen = 0;
175
176 uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00};
177 uint8_t RndB[17] = {0};
178
179 if (session)
180 session->Authenticated = false;
181
182 uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00};
183 int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen);
184 if (res) {
185 PrintAndLogEx(ERR, "Exchande raw error: %d", res);
186 DropField();
187 return 2;
188 }
189
190 if (verbose)
191 PrintAndLogEx(INFO, "<phase1: %s", sprint_hex(data, datalen));
192
193 if (datalen < 1) {
194 PrintAndLogEx(ERR, "Card response wrong length: %d", datalen);
195 DropField();
196 return 3;
197 }
198
199 if (data[0] != 0x90) {
200 PrintAndLogEx(ERR, "Card response error: %02x", data[2]);
201 DropField();
202 return 3;
203 }
204
205 if (datalen != 19) { // code 1b + 16b + crc 2b
206 PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen);
207 DropField();
208 return 3;
209 }
210
211 aes_decode(NULL, key, &data[1], RndB, 16);
212 RndB[16] = RndB[0];
213 if (verbose)
214 PrintAndLogEx(INFO, "RndB: %s", sprint_hex(RndB, 16));
215
216 uint8_t cmd2[33] = {0};
217 cmd2[0] = 0x72;
218
219 uint8_t raw[32] = {0};
220 memmove(raw, RndA, 16);
221 memmove(&raw[16], &RndB[1], 16);
222
223 aes_encode(NULL, key, raw, &cmd2[1], 32);
224 if (verbose)
225 PrintAndLogEx(INFO, ">phase2: %s", sprint_hex(cmd2, 33));
226
227 res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen);
228 if (res) {
229 PrintAndLogEx(ERR, "Exchande raw error: %d", res);
230 DropField();
231 return 4;
232 }
233
234 if (verbose)
235 PrintAndLogEx(INFO, "<phase2: %s", sprint_hex(data, datalen));
236
237 aes_decode(NULL, key, &data[1], raw, 32);
238
239 if (verbose) {
240 PrintAndLogEx(INFO, "res: %s", sprint_hex(raw, 32));
241 PrintAndLogEx(INFO, "RndA`: %s", sprint_hex(&raw[4], 16));
242 }
243
244 if (memcmp(&raw[4], &RndA[1], 16)) {
245 PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal");
246 if (verbose) {
247 PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16));
248 PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16));
249 }
250 DropField();
251 return 5;
252 }
253
254 if (verbose) {
255 PrintAndLogEx(INFO, " TI: %s", sprint_hex(raw, 4));
256 PrintAndLogEx(INFO, "pic: %s", sprint_hex(&raw[20], 6));
257 PrintAndLogEx(INFO, "pcd: %s", sprint_hex(&raw[26], 6));
258 }
259
260 uint8_t kenc[16] = {0};
261 memcpy(&kenc[0], &RndA[11], 5);
262 memcpy(&kenc[5], &RndB[11], 5);
263 for (int i = 0; i < 5; i++)
264 kenc[10 + i] = RndA[4 + i] ^ RndB[4 + i];
265 kenc[15] = 0x11;
266
267 aes_encode(NULL, key, kenc, kenc, 16);
268 if (verbose) {
269 PrintAndLogEx(INFO, "kenc: %s", sprint_hex(kenc, 16));
270 }
271
272 uint8_t kmac[16] = {0};
273 memcpy(&kmac[0], &RndA[7], 5);
274 memcpy(&kmac[5], &RndB[7], 5);
275 for(int i = 0; i < 5; i++)
276 kmac[10 + i] = RndA[0 + i] ^ RndB[0 + i];
277 kmac[15] = 0x22;
278
279 aes_encode(NULL, key, kmac, kmac, 16);
280 if (verbose) {
281 PrintAndLog("kmac: %s", sprint_hex(kmac, 16));
282 }
283
284 if (!leaveSignalON)
285 DropField();
286
287 if (verbose)
288 PrintAndLog("");
289
290 if (session) {
291 session->Authenticated = true;
292 session->R_Ctr = 0;
293 session->W_Ctr = 0;
294 session->KeyNum = keyn[1] + (keyn[0] << 8);
295 memmove(session->RndA, RndA, 16);
296 memmove(session->RndB, RndB, 16);
297 memmove(session->Key, key, 16);
298 memmove(session->TI, raw, 4);
299 memmove(session->PICCap2, &raw[20], 6);
300 memmove(session->PCDCap2, &raw[26], 6);
301 memmove(session->Kenc, kenc, 16);
302 memmove(session->Kmac, kmac, 16);
303 }
304
305 if (verbose)
306 PrintAndLogEx(INFO, "Authentication OK");
307
308 return 0;
309}
310
311int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
312 if (VerboseMode)
313 PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
314
315 int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
316
317 if (VerboseMode)
318 PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
319
320 return res;
321}
322
323int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
324 uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
325 memmove(&rcmd[3], key, 16);
326
327 return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
328}
329
330int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
331 uint8_t rcmd[1] = {0xaa};
332
333 return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
334}
335
336int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
337 uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount};
338 if (!plain && session)
339 CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
340
341 int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
342 if (res)
343 return res;
344
345 if (session)
346 session->R_Ctr++;
347
348 if (session && mac && *dataoutlen > 11)
349 CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
350
351 return 0;
352}
353
354int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
355 uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
356 memmove(&rcmd[3], data, 16);
357 if (session)
358 CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
359
360 int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
361 if (res)
362 return res;
363
364 if (session)
365 session->W_Ctr++;
366
367 if (session && mac && *dataoutlen > 3)
368 CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
369
370 return 0;
371}
372
373int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose) {
374 uint8_t keyn[2] = {0};
375 bool plain = false;
376
377 uint16_t uKeyNum = 0x4000 + sectorNo * 2 + (keyType ? 1 : 0);
378 keyn[0] = uKeyNum >> 8;
379 keyn[1] = uKeyNum & 0xff;
380 if (verbose)
381 PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum);
382
383 mf4Session session;
384 int res = MifareAuth4(&session, keyn, key, true, true, verbose);
385 if (res) {
386 PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res);
387 return res;
388 }
389
390 uint8_t data[250] = {0};
391 int datalen = 0;
392 uint8_t mac[8] = {0};
393 uint8_t firstBlockNo = mfFirstBlockOfSector(sectorNo);
394 for (int n = firstBlockNo; n < firstBlockNo + mfNumBlocksPerSector(sectorNo); n++) {
395 res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
396 if (res) {
397 PrintAndLogEx(ERR, "Sector %d read error: %d", sectorNo, res);
398 DropField();
399 return res;
400 }
401
402 if (datalen && data[0] != 0x90) {
403 PrintAndLogEx(ERR, "Sector %d card read error: %02x %s", sectorNo, data[0], mfpGetErrorDescription(data[0]));
404 DropField();
405 return 5;
406 }
407 if (datalen != 1 + 16 + 8 + 2) {
408 PrintAndLogEx(ERR, "Sector %d error returned data length:%d", sectorNo, datalen);
409 DropField();
410 return 6;
411 }
412
413 memcpy(&dataout[(n - firstBlockNo) * 16], &data[1], 16);
414
415 if (verbose)
416 PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16));
417
418 if (memcmp(&data[1 + 16], mac, 8)) {
419 PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n);
420 PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8));
421 PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8));
422
423 if (!verbose)
424 return 7;
425 } else {
426 if (verbose)
427 PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8));
428 }
429 }
430 DropField();
431
432 return 0;
433}
434
435// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards),
436// plus evtl. 8 sectors with 16 blocks each (4k cards)
437uint8_t mfNumBlocksPerSector(uint8_t sectorNo) {
438 if (sectorNo < 32)
439 return 4;
440 else
441 return 16;
442}
443
444uint8_t mfFirstBlockOfSector(uint8_t sectorNo) {
445 if (sectorNo < 32)
446 return sectorNo * 4;
447 else
448 return 32 * 4 + (sectorNo - 32) * 16;
449}
450
451uint8_t mfSectorTrailer(uint8_t blockNo) {
452 if (blockNo < 32 * 4) {
453 return (blockNo | 0x03);
454 } else {
455 return (blockNo | 0x0f);
456 }
457}
458
459bool mfIsSectorTrailer(uint8_t blockNo) {
460 return (blockNo == mfSectorTrailer(blockNo));
461}
462
463uint8_t mfSectorNum(uint8_t blockNo) {
464 if (blockNo < 32 * 4)
465 return blockNo / 4;
466 else
467 return 32 + (blockNo - 32 * 4) / 16;
468
469}
Impressum, Datenschutz