1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 // Copyright (C) 2018 drHatson
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
8 //-----------------------------------------------------------------------------
9 // iso14443-4 mifare commands
10 //-----------------------------------------------------------------------------
18 #include "crypto/libpcrypto.h"
20 static bool VerboseMode
= false;
21 void mfpSetVerboseMode(bool verbose
) {
22 VerboseMode
= verbose
;
27 const char *Description
;
30 static const PlusErrorsElm PlusErrors
[] = {
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."},
43 int PlusErrorsLen
= sizeof(PlusErrors
) / sizeof(PlusErrorsElm
);
45 const char *mfpGetErrorDescription(uint8_t errorCode
) {
46 for (int i
= 0; i
< PlusErrorsLen
; i
++)
47 if (errorCode
== PlusErrors
[i
].Code
)
48 return PlusErrors
[i
].Description
;
50 return PlusErrors
[0].Description
;
53 AccessConditions_t MFAccessConditions
[] = {
54 {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"},
55 {0x01, "read AB; decrement transfer restore AB"},
57 {0x03, "read B; write B"},
58 {0x04, "read AB; writeB"},
60 {0x06, "read AB; write B; increment B; decrement transfer restore AB"},
64 AccessConditions_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"}
75 char *mfGetAccessConditionsDesc(uint8_t blockn
, uint8_t *data
) {
76 static char StaticNone
[] = "none";
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
;
82 uint8_t cond
= (data1
& 0x01) << 2 | (data2
& 0x01) << 1 | (data3
& 0x01);
85 for (int i
= 0; i
< ARRAYLEN(MFAccessConditionsTrailer
); i
++)
86 if (MFAccessConditionsTrailer
[i
].cond
== cond
) {
87 return MFAccessConditionsTrailer
[i
].description
;
90 for (int i
= 0; i
< ARRAYLEN(MFAccessConditions
); i
++)
91 if (MFAccessConditions
[i
].cond
== cond
) {
92 return MFAccessConditions
[i
].description
;
99 int 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);
111 int 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);
124 int 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)
128 memset(mac
, 0x00, 8);
130 uint16_t ctr
= session
->R_Ctr
;
134 ctr
= session
->W_Ctr
;
141 uint8_t macdata
[2049] = {data
[0], (ctr
& 0xFF), (ctr
>> 8), 0};
142 int macdatalen
= datalen
;
143 memcpy(&macdata
[3], session
->TI
, 4);
147 memcpy(&macdata
[7], &data
[1], datalen
- 1);
148 macdatalen
= datalen
+ 6;
151 macdata
[7] = blockNum
;
153 macdata
[9] = blockCount
;
154 memcpy(&macdata
[10], &data
[1], datalen
- 1);
155 macdatalen
= datalen
+ 9;
158 memcpy(&macdata
[7], &data
[1], datalen
- 1);
159 macdatalen
= datalen
+ 6;
167 PrintAndLog("MAC data[%d]: %s", macdatalen
, sprint_hex(macdata
, macdatalen
));
169 return aes_cmac8(NULL
, session
->Kmac
, macdata
, mac
, macdatalen
);
172 int MifareAuth4(mf4Session
*session
, uint8_t *keyn
, uint8_t *key
, bool activateField
, bool leaveSignalON
, bool verbose
) {
173 uint8_t data
[257] = {0};
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};
180 session
->Authenticated
= false;
182 uint8_t cmd1
[] = {0x70, keyn
[1], keyn
[0], 0x00};
183 int res
= ExchangeRAW14a(cmd1
, sizeof(cmd1
), activateField
, true, data
, sizeof(data
), &datalen
);
185 PrintAndLogEx(ERR
, "Exchande raw error: %d", res
);
191 PrintAndLogEx(INFO
, "<phase1: %s", sprint_hex(data
, datalen
));
194 PrintAndLogEx(ERR
, "Card response wrong length: %d", datalen
);
199 if (data
[0] != 0x90) {
200 PrintAndLogEx(ERR
, "Card response error: %02x", data
[2]);
205 if (datalen
!= 19) { // code 1b + 16b + crc 2b
206 PrintAndLogEx(ERR
, "Card response must be 19 bytes long instead of: %d", datalen
);
211 aes_decode(NULL
, key
, &data
[1], RndB
, 16);
214 PrintAndLogEx(INFO
, "RndB: %s", sprint_hex(RndB
, 16));
216 uint8_t cmd2
[33] = {0};
219 uint8_t raw
[32] = {0};
220 memmove(raw
, RndA
, 16);
221 memmove(&raw
[16], &RndB
[1], 16);
223 aes_encode(NULL
, key
, raw
, &cmd2
[1], 32);
225 PrintAndLogEx(INFO
, ">phase2: %s", sprint_hex(cmd2
, 33));
227 res
= ExchangeRAW14a(cmd2
, sizeof(cmd2
), false, true, data
, sizeof(data
), &datalen
);
229 PrintAndLogEx(ERR
, "Exchande raw error: %d", res
);
235 PrintAndLogEx(INFO
, "<phase2: %s", sprint_hex(data
, datalen
));
237 aes_decode(NULL
, key
, &data
[1], raw
, 32);
240 PrintAndLogEx(INFO
, "res: %s", sprint_hex(raw
, 32));
241 PrintAndLogEx(INFO
, "RndA`: %s", sprint_hex(&raw
[4], 16));
244 if (memcmp(&raw
[4], &RndA
[1], 16)) {
245 PrintAndLogEx(ERR
, "\nAuthentication FAILED. rnd not equal");
247 PrintAndLogEx(ERR
, "RndA reader: %s", sprint_hex(&RndA
[1], 16));
248 PrintAndLogEx(ERR
, "RndA card: %s", sprint_hex(&raw
[4], 16));
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));
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
];
267 aes_encode(NULL
, key
, kenc
, kenc
, 16);
269 PrintAndLogEx(INFO
, "kenc: %s", sprint_hex(kenc
, 16));
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
];
279 aes_encode(NULL
, key
, kmac
, kmac
, 16);
281 PrintAndLog("kmac: %s", sprint_hex(kmac
, 16));
291 session
->Authenticated
= true;
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);
306 PrintAndLogEx(INFO
, "Authentication OK");
311 int intExchangeRAW14aPlus(uint8_t *datain
, int datainlen
, bool activateField
, bool leaveSignalON
, uint8_t *dataout
, int maxdataoutlen
, int *dataoutlen
) {
313 PrintAndLogEx(INFO
, ">>> %s", sprint_hex(datain
, datainlen
));
315 int res
= ExchangeRAW14a(datain
, datainlen
, activateField
, leaveSignalON
, dataout
, maxdataoutlen
, dataoutlen
);
318 PrintAndLogEx(INFO
, "<<< %s", sprint_hex(dataout
, *dataoutlen
));
323 int 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);
327 return intExchangeRAW14aPlus(rcmd
, sizeof(rcmd
), activateField
, leaveSignalON
, dataout
, maxdataoutlen
, dataoutlen
);
330 int MFPCommitPerso(bool activateField
, bool leaveSignalON
, uint8_t *dataout
, int maxdataoutlen
, int *dataoutlen
) {
331 uint8_t rcmd
[1] = {0xaa};
333 return intExchangeRAW14aPlus(rcmd
, sizeof(rcmd
), activateField
, leaveSignalON
, dataout
, maxdataoutlen
, dataoutlen
);
336 int 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
);
341 int res
= intExchangeRAW14aPlus(rcmd
, plain
? 4 : sizeof(rcmd
), activateField
, leaveSignalON
, dataout
, maxdataoutlen
, dataoutlen
);
348 if (session
&& mac
&& *dataoutlen
> 11)
349 CalculateMAC(session
, mtypReadResp
, blockNum
, blockCount
, dataout
, *dataoutlen
- 8 - 2, mac
, VerboseMode
);
354 int 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);
358 CalculateMAC(session
, mtypWriteCmd
, blockNum
, 1, rcmd
, 19, &rcmd
[19], VerboseMode
);
360 int res
= intExchangeRAW14aPlus(rcmd
, sizeof(rcmd
), activateField
, leaveSignalON
, dataout
, maxdataoutlen
, dataoutlen
);
367 if (session
&& mac
&& *dataoutlen
> 3)
368 CalculateMAC(session
, mtypWriteResp
, blockNum
, 1, dataout
, *dataoutlen
, mac
, VerboseMode
);
373 int mfpReadSector(uint8_t sectorNo
, uint8_t keyType
, uint8_t *key
, uint8_t *dataout
, bool verbose
) {
374 uint8_t keyn
[2] = {0};
377 uint16_t uKeyNum
= 0x4000 + sectorNo
* 2 + (keyType
? 1 : 0);
378 keyn
[0] = uKeyNum
>> 8;
379 keyn
[1] = uKeyNum
& 0xff;
381 PrintAndLogEx(INFO
, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo
), sectorNo
, uKeyNum
);
384 int res
= MifareAuth4(&session
, keyn
, key
, true, true, verbose
);
386 PrintAndLogEx(ERR
, "Sector %d authentication error: %d", sectorNo
, res
);
390 uint8_t data
[250] = {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
);
397 PrintAndLogEx(ERR
, "Sector %d read error: %d", sectorNo
, res
);
402 if (datalen
&& data
[0] != 0x90) {
403 PrintAndLogEx(ERR
, "Sector %d card read error: %02x %s", sectorNo
, data
[0], mfpGetErrorDescription(data
[0]));
407 if (datalen
!= 1 + 16 + 8 + 2) {
408 PrintAndLogEx(ERR
, "Sector %d error returned data length:%d", sectorNo
, datalen
);
413 memcpy(&dataout
[(n
- firstBlockNo
) * 16], &data
[1], 16);
416 PrintAndLogEx(INFO
, "data[%03d]: %s", n
, sprint_hex(&data
[1], 16));
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));
427 PrintAndLogEx(INFO
, "MAC: %s", sprint_hex(&data
[1 + 16], 8));
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)
437 uint8_t mfNumBlocksPerSector(uint8_t sectorNo
) {
444 uint8_t mfFirstBlockOfSector(uint8_t sectorNo
) {
448 return 32 * 4 + (sectorNo
- 32) * 16;
451 uint8_t mfSectorTrailer(uint8_t blockNo
) {
452 if (blockNo
< 32 * 4) {
453 return (blockNo
| 0x03);
455 return (blockNo
| 0x0f);
459 bool mfIsSectorTrailer(uint8_t blockNo
) {
460 return (blockNo
== mfSectorTrailer(blockNo
));
463 uint8_t mfSectorNum(uint8_t blockNo
) {
464 if (blockNo
< 32 * 4)
467 return 32 + (blockNo
- 32 * 4) / 16;