1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency CryptoRF commands (ISO14443B)
17 //-----------------------------------------------------------------------------
19 #include "cmdhfcryptorf.h"
22 #include "fileutils.h"
24 #include "cmdparser.h" // command_t
25 #include "comms.h" // clearCommandBuffer
28 #include "protocols.h" // definitions of ISO14B protocol
30 #include "cliparser.h" // cliparsing
34 #ifndef CRYPTORF_MEM_SIZE
35 # define CRYPTORF_MEM_SIZE 1024
38 static int CmdHelp(const char *Cmd
);
40 static iso14b_card_select_t last_known_card
;
41 static void set_last_known_card(iso14b_card_select_t card
) {
42 last_known_card
= card
;
45 static int switch_off_field_cryptorf(void) {
46 SetISODEPState(ISODEP_INACTIVE
);
47 iso14b_raw_cmd_t packet
= {
48 .flags
= ISO14B_DISCONNECT
,
53 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)&packet
, sizeof(iso14b_raw_cmd_t
));
57 static int CmdHFCryptoRFList(const char *Cmd
) {
58 return CmdTraceListAlias(Cmd
, "hf cryptorf", "cryptorf");
61 static int CmdHFCryptoRFSim(const char *Cmd
) {
62 CLIParserContext
*ctx
;
63 CLIParserInit(&ctx
, "hf cryptorf sim",
64 "Simulate a CryptoRF tag\n"
65 _RED_("not implemented"),
72 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
76 SendCommandNG(CMD_HF_CRYPTORF_SIM
, NULL
, 0);
80 static int CmdHFCryptoRFSniff(const char *Cmd
) {
81 CLIParserContext
*ctx
;
82 CLIParserInit(&ctx
, "hf cryptorf sniff",
83 "Sniff the communication between reader and tag",
91 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
95 SendCommandNG(CMD_HF_ISO14443B_SNIFF
, NULL
, 0);
96 PacketResponseNG resp
;
97 WaitForResponse(CMD_HF_ISO14443B_SNIFF
, &resp
);
99 PrintAndLogEx(HINT
, "Try `" _YELLOW_("hf cryptorf list") "` to view captured tracelog");
100 PrintAndLogEx(HINT
, "Try `" _YELLOW_("trace save -f hf_cryptorf_mytrace") "` to save tracelog for later analysing");
104 static bool get_14b_UID(iso14b_card_select_t
*card
) {
112 iso14b_raw_cmd_t packet
= {
113 .flags
= (ISO14B_CONNECT
| ISO14B_SELECT_STD
| ISO14B_DISCONNECT
),
117 clearCommandBuffer();
118 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)&packet
, sizeof(iso14b_raw_cmd_t
));
119 PacketResponseNG resp
;
120 if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND
, &resp
, TIMEOUT
)) {
121 if (resp
.status
== PM3_SUCCESS
) {
122 memcpy(card
, (iso14b_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14b_card_select_t
));
129 PrintAndLogEx(FAILED
, "command execution time out");
135 // Print extended information about tag.
136 static int infoHFCryptoRF(bool verbose
) {
137 iso14b_raw_cmd_t packet
= {
138 .flags
= (ISO14B_CONNECT
| ISO14B_SELECT_STD
| ISO14B_DISCONNECT
),
142 // 14b get and print UID only (general info)
143 clearCommandBuffer();
144 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)&packet
, sizeof(iso14b_raw_cmd_t
));
145 PacketResponseNG resp
;
146 if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND
, &resp
, TIMEOUT
) == false) {
148 PrintAndLogEx(WARNING
, "command execution time out");
150 switch_off_field_cryptorf();
154 switch (resp
.status
) {
156 iso14b_card_select_t card
;
157 memcpy(&card
, (iso14b_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14b_card_select_t
));
158 PrintAndLogEx(NORMAL
, "");
159 PrintAndLogEx(SUCCESS
, " UID : %s", sprint_hex(card
.uid
, card
.uidlen
));
160 PrintAndLogEx(SUCCESS
, " ATQB : %s", sprint_hex(card
.atqb
, sizeof(card
.atqb
)));
161 PrintAndLogEx(SUCCESS
, " CHIPID : %02X", card
.chipid
);
165 if (verbose
) PrintAndLogEx(FAILED
, "ISO 14443-3 ATTRIB fail");
168 if (verbose
) PrintAndLogEx(FAILED
, "ISO 14443-3 CRC fail");
171 if (verbose
) PrintAndLogEx(FAILED
, "ISO 14443-b card select failed");
177 static int CmdHFCryptoRFInfo(const char *Cmd
) {
178 CLIParserContext
*ctx
;
179 CLIParserInit(&ctx
, "hf cryptorf info",
180 "Act as a CryptoRF reader.",
185 arg_lit0("v", "verbose", "verbose output"),
188 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
189 bool verbose
= arg_get_lit(ctx
, 1);
191 int res
= infoHFCryptoRF(verbose
);
192 if (res
!= PM3_SUCCESS
&& verbose
) {
193 PrintAndLogEx(FAILED
, "no CryptoRF / ISO14443-B tag found");
198 // get and print general info cryptoRF
199 int readHFCryptoRF(bool loop
, bool verbose
) {
203 iso14b_raw_cmd_t packet
= {
204 .flags
= (ISO14B_CONNECT
| ISO14B_SELECT_STD
| ISO14B_DISCONNECT
),
208 clearCommandBuffer();
209 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)&packet
, sizeof(iso14b_raw_cmd_t
));
210 PacketResponseNG resp
;
211 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
214 if (resp
.status
!= PM3_SUCCESS
) {
218 // when not in continuous mode
219 if (resp
.status
!= PM3_SUCCESS
) {
221 PrintAndLogEx(WARNING
, "cryptoRF / ISO14443-b card select failed");
223 res
= PM3_EOPABORTED
;
228 iso14b_card_select_t card
;
229 memcpy(&card
, (iso14b_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14b_card_select_t
));
230 PrintAndLogEx(NORMAL
, "");
231 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex_inrow(card
.uid
, card
.uidlen
));
232 set_last_known_card(card
);
234 } while (loop
&& kbd_enter_pressed() == false);
240 static int CmdHFCryptoRFReader(const char *Cmd
) {
241 CLIParserContext
*ctx
;
242 CLIParserInit(&ctx
, "hf cryptorf reader",
243 "Act as a cryptoRF reader. Look for cryptoRF tags until Enter or the pm3 button is pressed",
244 "hf cryptorf reader -@ -> continuous reader mode"
249 arg_lit0("@", NULL
, "optional - continuous reader mode"),
252 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
253 bool cm
= arg_get_lit(ctx
, 1);
257 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
259 return readHFCryptoRF(cm
, false);
262 // need to write to file
263 static int CmdHFCryptoRFDump(const char *Cmd
) {
264 CLIParserContext
*ctx
;
265 CLIParserInit(&ctx
, "hf cryptorf dump",
266 "Dump all memory from a CryptoRF tag (512/4096 bit size)",
272 arg_str0("f", "file", "<fn>", "filename to save dump to"),
273 arg_lit0(NULL
, "64", "64byte / 512bit memory"),
274 arg_lit0(NULL
, "512", "512byte / 4096bit memory"),
277 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
279 char filename
[FILE_PATH_SIZE
] = {0};
280 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
282 bool m64
= arg_get_lit(ctx
, 2);
283 bool m512
= arg_get_lit(ctx
, 3);
286 if (m512
+ m64
!= 1) {
287 PrintAndLogEx(INFO
, "Select only one card memory size");
294 cardsize
= (512 / 8) + 4;
298 cardsize
= (4096 / 8) + 4;
302 iso14b_card_select_t card
;
303 if (get_14b_UID(&card
) == false) {
304 PrintAndLogEx(WARNING
, "No tag found.");
308 // detect blocksize from card :)
309 PrintAndLogEx(INFO
, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
312 iso14b_raw_cmd_t
*packet
= (iso14b_raw_cmd_t
*)calloc(1, sizeof(iso14b_raw_cmd_t
) + 2);
313 if (packet
== NULL
) {
314 PrintAndLogEx(FAILED
, "failed to allocate memory");
317 packet
->flags
= (ISO14B_CONNECT
| ISO14B_SELECT_SR
);
321 clearCommandBuffer();
322 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)packet
, sizeof(iso14b_raw_cmd_t
));
323 PacketResponseNG resp
;
326 if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND
, &resp
, 2000)) {
327 if (resp
.status
!= PM3_SUCCESS
) {
328 PrintAndLogEx(FAILED
, "failed to select %d]", resp
.status
);
330 return switch_off_field_cryptorf();
334 PrintAndLogEx(INFO
, "." NOLF
);
336 uint8_t data
[cardsize
];
337 memset(data
, 0, sizeof(data
));
338 uint16_t blocknum
= 0;
340 for (int retry
= 0; retry
< 5; retry
++) {
342 // set up the read command
343 packet
->flags
= (ISO14B_APPEND_CRC
| ISO14B_RAW
);
345 packet
->raw
[0] = ISO14443B_READ_BLK
;
346 packet
->raw
[1] = blocknum
& 0xFF;
348 clearCommandBuffer();
349 SendCommandNG(CMD_HF_ISO14443B_COMMAND
, (uint8_t *)&packet
, sizeof(iso14b_raw_cmd_t
) + 2);
350 if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND
, &resp
, 2000)) {
352 if (resp
.status
!= PM3_SUCCESS
) {
353 PrintAndLogEx(FAILED
, "retrying one more time");
357 uint16_t len
= resp
.length
;
358 uint8_t *recv
= resp
.data
.asBytes
;
360 if (check_crc(CRC_14443_B
, recv
, len
) == false) {
361 PrintAndLogEx(FAILED
, "crc fail, retrying one more time");
365 memcpy(data
+ (blocknum
* 4), resp
.data
.asBytes
, 4);
368 if (blocknum
== 0xFF) {
374 if (blocknum
> blocks
) {
379 PrintAndLogEx(NORMAL
, "." NOLF
);
385 PrintAndLogEx(NORMAL
, "");
387 if (blocknum
!= 0xFF) {
388 PrintAndLogEx(FAILED
, "dump failed");
389 return switch_off_field_cryptorf();
392 PrintAndLogEx(INFO
, "block# | data | ascii");
393 PrintAndLogEx(INFO
, "---------+--------------+----------");
395 for (int i
= 0; i
<= blocks
; i
++) {
397 "%3d/0x%02X | %s | %s",
400 sprint_hex(data
+ (i
* 4), 4),
401 sprint_ascii(data
+ (i
* 4), 4)
404 PrintAndLogEx(INFO
, "---------+--------------+----------");
405 PrintAndLogEx(NORMAL
, "");
407 size_t datalen
= (blocks
+ 1) * 4;
410 PrintAndLogEx(INFO
, "Using UID as filename");
411 char *fptr
= filename
+ snprintf(filename
, sizeof(filename
), "hf-cryptorf-");
412 FillFileNameByUID(fptr
, card
.uid
, "-dump", card
.uidlen
);
415 pm3_save_dump(filename
, data
, datalen
, jsfCryptorf
);
417 return switch_off_field_cryptorf();
420 static int CmdHFCryptoRFELoad(const char *Cmd
) {
422 CLIParserContext
*ctx
;
423 CLIParserInit(&ctx
, "hf cryptorf eload",
424 "Loads CryptoRF tag dump (bin/eml/json) into emulator memory on device",
425 "hf cryptorf eload -f hf-cryptorf-0102030405-dump.bin\n"
430 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
433 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
435 char filename
[FILE_PATH_SIZE
] = {0};
436 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
440 PrintAndLogEx(ERR
, "Error: Please specify a filename");
444 size_t datalen
= CRYPTORF_MEM_SIZE
;
446 uint8_t *data
= calloc(datalen
, sizeof(uint8_t));
448 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
452 if (loadFile_safe(filename
, ".bin", (void **)&data
, &datalen
) != PM3_SUCCESS
) {
454 PrintAndLogEx(WARNING
, "Error, reading file");
458 PrintAndLogEx(SUCCESS
, "Uploading to emulator memory");
460 uint32_t bytes_sent
= 0;
463 uint32_t bytes_remaining = bytes_read;
465 while (bytes_remaining > 0) {
466 uint32_t bytes_in_packet = MIN(PM3_CMD_DATA_SIZE, bytes_remaining);
467 if (bytes_in_packet == bytes_remaining) {
468 // Disable fast mode on last packet
469 g_conn.block_after_ACK = false;
471 clearCommandBuffer();
472 SendCommandMIX(CMD_HF_CRYPTORF_EML_MEMSET, bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet);
473 bytes_remaining -= bytes_in_packet;
474 bytes_sent += bytes_in_packet;
478 PrintAndLogEx(SUCCESS
, "sent " _YELLOW_("%d") " bytes of data to device emulator memory", bytes_sent
);
482 static int CmdHFCryptoRFESave(const char *Cmd
) {
484 CLIParserContext
*ctx
;
485 CLIParserInit(&ctx
, "hf cryptorf esave",
486 "Save emulator memory to file (bin/json)\n"
487 "if filename is not supplied, UID will be used.",
488 "hf cryptorf esave\n"
489 "hf cryptorf esave -f filename"
493 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
496 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
499 char filename
[FILE_PATH_SIZE
] = {0};
500 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
503 size_t numofbytes
= CRYPTORF_MEM_SIZE
;
506 uint8_t *data
= calloc(numofbytes
, sizeof(uint8_t));
508 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
512 // download emulator memory
513 PrintAndLogEx(SUCCESS
, "Reading emulator memory...");
514 if (GetFromDevice(BIG_BUF_EML
, data
, numofbytes
, 0, NULL
, 0, NULL
, 2500, false) == false) {
515 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
520 // user supplied filename?
522 PrintAndLogEx(INFO
, "Using UID as filename");
523 char *fptr
= filename
+ snprintf(filename
, sizeof(filename
), "hf-cryptorf-");
524 FillFileNameByUID(fptr
, data
, "-dump", 4);
527 pm3_save_dump(filename
, data
, numofbytes
, jsfCryptorf
);
532 static command_t CommandTable
[] = {
533 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
534 {"dump", CmdHFCryptoRFDump
, IfPm3Iso14443b
, "Read all memory pages of an CryptoRF tag, save to file"},
535 {"info", CmdHFCryptoRFInfo
, IfPm3Iso14443b
, "Tag information"},
536 {"list", CmdHFCryptoRFList
, AlwaysAvailable
, "List ISO 14443B history"},
537 {"reader", CmdHFCryptoRFReader
, IfPm3Iso14443b
, "Act as a CryptoRF reader to identify a tag"},
538 {"sim", CmdHFCryptoRFSim
, IfPm3Iso14443b
, "Fake CryptoRF tag"},
539 {"sniff", CmdHFCryptoRFSniff
, IfPm3Iso14443b
, "Eavesdrop CryptoRF"},
540 {"eload", CmdHFCryptoRFELoad
, AlwaysAvailable
, "Upload file into emulator memory"},
541 {"esave", CmdHFCryptoRFESave
, AlwaysAvailable
, "Save emulator memory to file"},
542 {NULL
, NULL
, NULL
, NULL
}
545 static int CmdHelp(const char *Cmd
) {
546 (void)Cmd
; // Cmd is not used so far
547 CmdsHelp(CommandTable
);
551 int CmdHFCryptoRF(const char *Cmd
) {
552 clearCommandBuffer();
553 return CmdsParse(CommandTable
, Cmd
);