1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2019 iceman
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 //-----------------------------------------------------------------------------
9 //-----------------------------------------------------------------------------
10 #include "cmdhfthinfilm.h"
15 #include "cliparser.h"
16 #include "cmdparser.h" // command_t
21 #include "cmdhf14a.h" // manufacture
23 static int CmdHelp(const char *Cmd
);
25 // Printing function based upon the code in libnfc
27 // https://github.com/nfc-tools/libnfc/blob/master/utils/nfc-barcode.c
28 static int print_barcode(uint8_t *barcode
, const size_t barcode_len
, bool verbose
) {
30 PrintAndLogEx(NORMAL
, "");
32 uint8_t mb
= barcode
[0] & ~0x80;
33 PrintAndLogEx(SUCCESS
, " Manufacturer : "_YELLOW_("%s") "[0x%02X]", getTagInfo(mb
), mb
);
36 PrintAndLogEx(SUCCESS
, " Data format : "_YELLOW_("%02X"), barcode
[1]);
37 if (barcode_len
> 2) {
39 compute_crc(CRC_14443_A
, barcode
, barcode_len
- 2, &b1
, &b2
);
40 bool isok
= (barcode
[barcode_len
- 1] == b1
&& barcode
[barcode_len
- 2] == b2
);
42 PrintAndLogEx(SUCCESS
, " Checksum : "_YELLOW_("%02X %02X")" - %s", b2
, b1
, (isok
) ? _GREEN_("OK") : _RED_("fail"));
44 PrintAndLogEx(SUCCESS
, " Checksum : "_YELLOW_("too few data for checksum")" - " _RED_("fail"));
46 PrintAndLogEx(SUCCESS
, " Data len (bits) : "_YELLOW_("%zu")" - %s", barcode_len
* 8, (barcode_len
== 16 || barcode_len
== 32) ? _GREEN_("OK") : _YELLOW_("warning"));
47 PrintAndLogEx(SUCCESS
, " Raw data : "_YELLOW_("%s"), sprint_hex(barcode
, barcode_len
));
48 if (barcode_len
< 4) // too few to go to next decoding stages
53 memset(s
, 0x00, sizeof(s
));
57 PrintAndLogEx(SUCCESS
, " Data format : Reserved for allocation by tag manufacturer");
60 snprintf(s
, sizeof(s
), "http://www.");
63 snprintf(s
, sizeof(s
), "https://www.");
66 snprintf(s
, sizeof(s
), "http://");
69 snprintf(s
, sizeof(s
), "https://");
72 if (barcode_len
< 16) {
73 PrintAndLogEx(WARNING
, "EPC: (partial data) %s", sprint_hex(barcode
+ 2, barcode_len
- 2));
76 PrintAndLogEx(SUCCESS
, "EPC: %s", sprint_hex(barcode
+ 2, 12));
79 PrintAndLogEx(SUCCESS
, " Data format : RFU Reserved for future use (%02X)", barcode
[1]);
81 PrintAndLogEx(SUCCESS
, "Raw data with CRC: "_YELLOW_("%s"), sprint_hex(barcode
, barcode_len
));
85 snprintf(s
+ strlen(s
), barcode_len
- 3, (const char *)&barcode
[2], barcode_len
- 4);
87 for (uint8_t i
= 0; i
< strlen(s
); i
++) {
90 if ((uint8_t) s
[i
] == 0xFE) {
95 PrintAndLogEx(SUCCESS
, " Decoded NFC URL : "_YELLOW_("%s"), s
);
99 int CmdHfThinFilmInfo(const char *Cmd
) {
100 CLIParserContext
*ctx
;
101 CLIParserInit(&ctx
, "hf thinfilm info",
102 "Get info from Thinfilm tags",
109 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
111 return infoThinFilm(true);
114 int infoThinFilm(bool verbose
) {
116 clearCommandBuffer();
117 SendCommandNG(CMD_HF_THINFILM_READ
, NULL
, 0);
119 PacketResponseNG resp
;
120 if (!WaitForResponseTimeout(CMD_HF_THINFILM_READ
, &resp
, 1500)) {
121 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
125 if (resp
.status
== PM3_SUCCESS
) {
126 if (resp
.length
== 16 || resp
.length
== 32) {
127 PrintAndLogEx(NORMAL
, "");
128 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Information") " ---------------------------");
129 print_barcode(resp
.data
.asBytes
, resp
.length
, verbose
);
132 PrintAndLogEx(WARNING
, "Response is wrong length. (%d)", resp
.length
);
141 int CmdHfThinFilmSim(const char *Cmd
) {
142 CLIParserContext
*ctx
;
143 CLIParserInit(&ctx
, "hf thinfilm sim",
144 "Simulate Thinfilm tag",
145 "hf thinfilm sim -d B70470726f786d61726b2e636f6d");
149 arg_str1("d", "data", "<hex>", "bytes to send"),
150 arg_lit0(NULL
, "raw", "raw, provided bytes should include CRC"),
153 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
156 uint8_t data
[512] = {0};
157 CLIGetHexWithReturn(ctx
, 1, data
, &data_len
);
161 if (arg_get_lit(ctx
, 2)) {
167 if (addcrc
&& data_len
<= 510) {
169 compute_crc(CRC_14443_A
, data
, data_len
, &b1
, &b2
);
170 data
[data_len
++] = b2
;
171 data
[data_len
++] = b1
;
174 clearCommandBuffer();
175 SendCommandNG(CMD_HF_THINFILM_SIMULATE
, (uint8_t *)&data
, data_len
);
176 PacketResponseNG resp
;
177 PrintAndLogEx(SUCCESS
, "press pm3-button to abort simulation");
180 while (!(ret
= kbd_enter_pressed())) {
181 if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE
, &resp
, 500) == 0) continue;
182 if (resp
.status
!= PM3_SUCCESS
) break;
185 PrintAndLogEx(INFO
, "Client side interrupted");
186 PrintAndLogEx(WARNING
, "Simulation still running on Proxmark3 till next command or button press");
188 PrintAndLogEx(INFO
, "Done");
193 static int CmdHfThinFilmList(const char *Cmd
) {
194 return CmdTraceListAlias(Cmd
, "hf thinfilm", "thinfilm");
197 static command_t CommandTable
[] = {
198 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
199 {"info", CmdHfThinFilmInfo
, IfPm3NfcBarcode
, "Tag information"},
200 {"list", CmdHfThinFilmList
, AlwaysAvailable
, "List NFC Barcode / Thinfilm history - not correct"},
201 {"sim", CmdHfThinFilmSim
, IfPm3NfcBarcode
, "Fake Thinfilm tag"},
202 {NULL
, NULL
, NULL
, NULL
}
205 static int CmdHelp(const char *Cmd
) {
206 (void)Cmd
; // Cmd is not used so far
207 CmdsHelp(CommandTable
);
211 int CmdHFThinfilm(const char *Cmd
) {
212 clearCommandBuffer();
213 return CmdsParse(CommandTable
, Cmd
);