1 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
8 // Low frequency Kantech ioProx commands
9 // FSK2a, rf/64, 64 bits (complete)
10 //-----------------------------------------------------------------------------
13 #include <stdio.h> // sscanf
17 #include "commonutil.h" // ARRAYLEN
18 #include "cmdparser.h" // command_t
22 #include "ui.h" // PrintAndLog
23 #include "lfdemod.h" // parityTest, bitbytes_to_byte
24 #include "protocols.h" // for T55xx config register definitions
26 #include "cmdlft55xx.h" // verifywrite
27 #include "cliparser.h"
28 #include "cmdlfem4x05.h" // EM defines
30 static int CmdHelp(const char *Cmd
);
32 // this read loops on device side.
33 // uses the demod in lfops.c
34 static int CmdIOProxWatch(const char *Cmd
) {
35 CLIParserContext
*ctx
;
36 CLIParserInit(&ctx
, "lf io watch",
37 "Enables ioProx compatible reader mode printing details.\n"
38 "By default, values are printed and logged until the button is pressed or another USB command is issued.",
46 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
49 PrintAndLogEx(SUCCESS
, "Watching for IO Prox cards - place tag on antenna");
50 PrintAndLogEx(INFO
, "Press pm3-button to stop reading cards");
52 SendCommandNG(CMD_LF_IO_WATCH
, NULL
, 0);
53 return lfsim_wait_check(CMD_LF_IO_WATCH
);
56 //IO-Prox demod - FSK RF/64 with preamble of 000000001
57 //print ioProx ID and some format details
58 int demodIOProx(bool verbose
) {
59 (void) verbose
; // unused so far
60 int idx
= 0, retval
= PM3_SUCCESS
;
61 uint8_t bits
[MAX_GRAPH_TRACE_LEN
] = {0};
62 size_t size
= getFromGraphBuf(bits
);
64 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox not enough samples in GraphBuffer");
67 //get binary from fsk wave
69 idx
= detectIOProx(bits
, &size
, &waveIdx
);
73 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox not enough samples");
74 } else if (idx
== -2) {
75 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox just noise detected");
76 } else if (idx
== -3) {
77 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox error during fskdemod");
78 } else if (idx
== -4) {
79 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox preamble not found");
80 } else if (idx
== -5) {
81 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO size not correct, size %zu", size
);
82 } else if (idx
== -6) {
83 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox separator bits not found");
85 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox error demoding fsk %d", idx
);
90 setDemodBuff(bits
, size
, idx
);
91 setClockGrid(64, waveIdx
+ (idx
* 64));
95 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox data not found - FSK Bits: %zu", size
);
96 if (size
> 92) PrintAndLogEx(DEBUG
, "%s", sprint_bin_break(bits
, 92, 16));
102 //0 10 20 30 40 50 60
104 //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
105 //-----------------------------------------------------------------------------
106 //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 ???????? 11
108 //XSF(version)facility:codeone+codetwo (raw)
110 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d", bits
[idx
], bits
[idx
+ 1], bits
[idx
+ 2], bits
[idx
+ 3], bits
[idx
+ 4], bits
[idx
+ 5], bits
[idx
+ 6], bits
[idx
+ 7], bits
[idx
+ 8]);
111 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d", bits
[idx
+ 9], bits
[idx
+ 10], bits
[idx
+ 11], bits
[idx
+ 12], bits
[idx
+ 13], bits
[idx
+ 14], bits
[idx
+ 15], bits
[idx
+ 16], bits
[idx
+ 17]);
112 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d facility", bits
[idx
+ 18], bits
[idx
+ 19], bits
[idx
+ 20], bits
[idx
+ 21], bits
[idx
+ 22], bits
[idx
+ 23], bits
[idx
+ 24], bits
[idx
+ 25], bits
[idx
+ 26]);
113 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d version", bits
[idx
+ 27], bits
[idx
+ 28], bits
[idx
+ 29], bits
[idx
+ 30], bits
[idx
+ 31], bits
[idx
+ 32], bits
[idx
+ 33], bits
[idx
+ 34], bits
[idx
+ 35]);
114 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d code1", bits
[idx
+ 36], bits
[idx
+ 37], bits
[idx
+ 38], bits
[idx
+ 39], bits
[idx
+ 40], bits
[idx
+ 41], bits
[idx
+ 42], bits
[idx
+ 43], bits
[idx
+ 44]);
115 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d code2", bits
[idx
+ 45], bits
[idx
+ 46], bits
[idx
+ 47], bits
[idx
+ 48], bits
[idx
+ 49], bits
[idx
+ 50], bits
[idx
+ 51], bits
[idx
+ 52], bits
[idx
+ 53]);
116 PrintAndLogEx(DEBUG
, "%d%d%d%d%d%d%d%d %d%d checksum", bits
[idx
+ 54], bits
[idx
+ 55], bits
[idx
+ 56], bits
[idx
+ 57], bits
[idx
+ 58], bits
[idx
+ 59], bits
[idx
+ 60], bits
[idx
+ 61], bits
[idx
+ 62], bits
[idx
+ 63]);
118 uint32_t code
= bytebits_to_byte(bits
+ idx
, 32);
119 uint32_t code2
= bytebits_to_byte(bits
+ idx
+ 32, 32);
120 uint8_t version
= bytebits_to_byte(bits
+ idx
+ 27, 8); //14,4
121 uint8_t facilitycode
= bytebits_to_byte(bits
+ idx
+ 18, 8) ;
122 uint16_t number
= (bytebits_to_byte(bits
+ idx
+ 36, 8) << 8) | (bytebits_to_byte(bits
+ idx
+ 45, 8)); //36,9
123 uint8_t crc
= bytebits_to_byte(bits
+ idx
+ 54, 8);
126 for (uint8_t i
= 1; i
< 6; ++i
) {
127 calccrc
+= bytebits_to_byte(bits
+ idx
+ 9 * i
, 8);
130 calccrc
= 0xff - calccrc
;
132 char crc_str
[36] = {0};
134 if (crc
== calccrc
) {
135 snprintf(crc_str
, sizeof(crc_str
), "(" _GREEN_("ok") ")");
137 snprintf(crc_str
, sizeof(crc_str
), "(" _RED_("fail") ") 0x%02X != 0x%02X", crc
, calccrc
);
141 PrintAndLogEx(SUCCESS
, "IO Prox - " _GREEN_("XSF(%02d)%02x:%05d") ", Raw: %08x%08x %s", version
, facilitycode
, number
, code
, code2
, crc_str
);
145 PrintAndLogEx(DEBUG
, "DEBUG: Error - IO prox crc failed");
147 PrintAndLogEx(DEBUG
, "DEBUG: IO prox idx: %d, Len: %zu, Printing demod buffer:", idx
, size
);
148 printDemodBuff(0, false, false, true);
149 printDemodBuff(0, false, false, false);
154 static int CmdIOProxDemod(const char *Cmd
) {
155 CLIParserContext
*ctx
;
156 CLIParserInit(&ctx
, "lf io demod",
157 "Try to find ioProx preamble, if found decode / descramble data",
165 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
167 return demodIOProx(true);
169 // this read is the "normal" read, which download lf signal and tries to demod here.
170 static int CmdIOProxReader(const char *Cmd
) {
171 CLIParserContext
*ctx
;
172 CLIParserInit(&ctx
, "lf io reader",
174 "lf io reader -@ -> continuous reader mode"
179 arg_lit0("@", NULL
, "optional - continuous reader mode"),
182 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
183 bool cm
= arg_get_lit(ctx
, 1);
187 lf_read(false, 12000);
189 } while (cm
&& !kbd_enter_pressed());
194 static int CmdIOProxSim(const char *Cmd
) {
196 CLIParserContext
*ctx
;
197 CLIParserInit(&ctx
, "lf io sim",
198 "Enables simulation of ioProx card with specified facility-code and card number.\n"
199 "Simulation runs until the button is pressed or another USB command is issued.",
200 "lf io sim --vn 1 --fc 101 --cn 1337"
205 arg_u64_1(NULL
, "vn", "<dec>", "8bit version"),
206 arg_u64_1(NULL
, "fc", "<dec>", "8bit facility code"),
207 arg_u64_1(NULL
, "cn", "<dec>", "16bit card number"),
210 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
212 uint8_t version
= arg_get_u32_def(ctx
, 1, 0);
213 uint8_t fc
= arg_get_u32_def(ctx
, 2, 0);
214 uint16_t cn
= arg_get_u32_def(ctx
, 3, 0);
218 if ((cn
& 0xFFFF) != cn
) {
220 PrintAndLogEx(INFO
, "Card Number Truncated to 16-bits (ioProx): %u", cn
);
223 PrintAndLogEx(SUCCESS
, "Simulating ioProx version: " _YELLOW_("%u") " FC: " _YELLOW_("%u (0x%02x)") " CN: " _YELLOW_("%u"), version
, fc
, fc
, cn
);
224 PrintAndLogEx(SUCCESS
, "Press pm3-button to abort simulation or run another command");
227 memset(bs
, 0x00, sizeof(bs
));
229 if (getIOProxBits(version
, fc
, cn
, bs
) != PM3_SUCCESS
) {
230 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
233 // ioProx uses: fcHigh: 10, fcLow: 8, clk: 64, invert: 1
234 // arg1 --- fcHigh<<8 + fcLow
235 // arg2 --- Invert and clk setting
236 // size --- 64 bits == 8 bytes
237 lf_fsksim_t
*payload
= calloc(1, sizeof(lf_fsksim_t
) + sizeof(bs
));
238 payload
->fchigh
= 10;
240 payload
->separator
= 1;
242 memcpy(payload
->data
, bs
, sizeof(bs
));
244 clearCommandBuffer();
245 SendCommandNG(CMD_LF_FSK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_fsksim_t
) + sizeof(bs
));
247 PacketResponseNG resp
;
248 WaitForResponse(CMD_LF_FSK_SIMULATE
, &resp
);
249 PrintAndLogEx(INFO
, "Done");
250 if (resp
.status
!= PM3_EOPABORTED
)
255 static int CmdIOProxClone(const char *Cmd
) {
257 CLIParserContext
*ctx
;
258 CLIParserInit(&ctx
, "lf io clone",
259 "clone a ioProx card with specified facility-code and card number\n"
260 "to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
261 "Tag must be on the antenna when issuing this command.",
262 "lf io clone --vn 1 --fc 101 --cn 1337"
267 arg_u64_1(NULL
, "vn", "<dec>", "8bit version"),
268 arg_u64_1(NULL
, "fc", "<dec>", "8bit facility code"),
269 arg_u64_1(NULL
, "cn", "<dec>", "16bit card number"),
270 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
271 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
274 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
276 uint8_t version
= arg_get_u32_def(ctx
, 1, 0);
277 uint8_t fc
= arg_get_u32_def(ctx
, 2, 0);
278 uint16_t cn
= arg_get_u32_def(ctx
, 3, 0);
279 bool q5
= arg_get_lit(ctx
, 4);
280 bool em
= arg_get_lit(ctx
, 5);
284 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
289 memset(bits
, 0, sizeof(bits
));
291 if ((cn
& 0xFFFF) != cn
) {
293 PrintAndLogEx(INFO
, "Card Number Truncated to 16-bits (ioProx): %u", cn
);
296 if (getIOProxBits(version
, fc
, cn
, bits
) != PM3_SUCCESS
) {
297 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
301 uint32_t blocks
[3] = {T55x7_MODULATION_FSK2a
| T55x7_BITRATE_RF_64
| 2 << T55x7_MAXBLOCK_SHIFT
, 0, 0};
302 char cardtype
[16] = {"T55x7"};
305 blocks
[0] = T5555_FIXED
| T5555_MODULATION_FSK2
| T5555_INVERT_OUTPUT
| T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT
;
306 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
311 blocks
[0] = EM4305_IOPROX_CONFIG_BLOCK
;
312 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
315 blocks
[1] = bytebits_to_byte(bits
, 32);
316 blocks
[2] = bytebits_to_byte(bits
+ 32, 32);
318 PrintAndLogEx(INFO
, "Preparing to clone ioProx to " _YELLOW_("%s") " with Version: " _GREEN_("%u") " FC: " _GREEN_("%u (0x%02x)") " CN: " _GREEN_("%u")
325 print_blocks(blocks
, ARRAYLEN(blocks
));
329 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
331 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
333 PrintAndLogEx(SUCCESS
, "Done");
334 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf io reader`") " to verify");
338 static command_t CommandTable
[] = {
339 {"help", CmdHelp
, AlwaysAvailable
, "this help"},
340 {"demod", CmdIOProxDemod
, AlwaysAvailable
, "demodulate an ioProx tag from the GraphBuffer"},
341 {"reader", CmdIOProxReader
, IfPm3Lf
, "attempt to read and extract tag data"},
342 {"clone", CmdIOProxClone
, IfPm3Lf
, "clone ioProx tag to T55x7 or Q5/T5555"},
343 {"sim", CmdIOProxSim
, IfPm3Lf
, "simulate ioProx tag"},
344 {"watch", CmdIOProxWatch
, IfPm3Lf
, "continuously watch for cards. Reader mode"},
345 {NULL
, NULL
, NULL
, NULL
}
348 static int CmdHelp(const char *Cmd
) {
349 (void)Cmd
; // Cmd is not used so far
350 CmdsHelp(CommandTable
);
354 int CmdLFIO(const char *Cmd
) {
355 clearCommandBuffer();
356 return CmdsParse(CommandTable
, Cmd
);
360 //0 10 20 30 40 50 60
362 //01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
363 //-----------------------------------------------------------------------------
364 //00000000 0 11110000 1 facility 1 version* 1 code*one 1 code*two 1 crc 11
365 //XSF(version)facility:codeone+codetwo (raw)
366 int getIOProxBits(uint8_t version
, uint8_t fc
, uint16_t cn
, uint8_t *bits
) {
369 // the return bits, preamble 0000 0000 0
371 memset(pre
, 0, sizeof(pre
));
373 // skip 9 zeros as preamble
376 // another fixed byte 11110000 = 0xF0
377 num_to_bytebits(0xF0, 8, pre
+ pos
);
379 pre
[pos
] = SEPARATOR
;
383 num_to_bytebits(fc
, 8, pre
+ pos
);
385 pre
[pos
] = SEPARATOR
;
389 num_to_bytebits(version
, 8, pre
+ pos
);
391 pre
[pos
] = SEPARATOR
;
394 // cardnumber high byte
395 num_to_bytebits(((cn
& 0xFF00) >> 8), 8, pre
+ pos
);
397 pre
[pos
] = SEPARATOR
;
400 // cardnumber low byte
401 num_to_bytebits((cn
& 0xFF), 8, pre
+ pos
);
403 pre
[pos
] = SEPARATOR
;
406 // calculate and add CRC
408 for (uint8_t i
= 1; i
< 6; ++i
)
409 crc
+= bytebits_to_byte(pre
+ 9 * i
, 8);
413 num_to_bytebits(crc
, 8, pre
+ pos
);
417 pre
[pos
] = SEPARATOR
;
418 pre
[++pos
] = SEPARATOR
;
420 memcpy(bits
, pre
, sizeof(pre
));
422 PrintAndLogEx(SUCCESS
, "IO raw bits:\n %s \n", sprint_bin(bits
, 64));