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 Idteck tag commands
9 // PSK1, clk 32, 2 data blocks
10 //-----------------------------------------------------------------------------
11 #include "cmdlfidteck.h"
16 #include "cmdparser.h" // command_t
22 #include "commonutil.h" // num_to_bytes
23 #include "cliparser.h"
24 #include "cmdlfem4x05.h" // EM defines
25 #include "protocols.h" // T55x7 defines
26 #include "cmdlft55xx.h" // verifywrite
28 static int CmdHelp(const char *Cmd
);
30 int demodIdteck(bool verbose
) {
31 (void) verbose
; // unused so far
32 if (PSKDemod(0, 0, 100, false) != PM3_SUCCESS
) {
33 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck PSKDemod failed");
36 size_t size
= DemodBufferLen
;
38 //get binary from PSK1 wave
39 int idx
= detectIdteck(DemodBuffer
, &size
);
43 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: not enough samples");
45 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: just noise");
47 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: preamble not found");
49 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: size not correct: %zu", size
);
51 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: idx: %d", idx
);
53 // if didn't find preamble try again inverting
54 if (PSKDemod(0, 1, 100, false) != PM3_SUCCESS
) {
55 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck PSKDemod failed");
58 idx
= detectIdteck(DemodBuffer
, &size
);
62 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: not enough samples");
64 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: just noise");
66 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: preamble not found");
68 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: size not correct: %zu", size
);
70 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: idx: %d", idx
);
75 setDemodBuff(DemodBuffer
, 64, idx
);
79 uint32_t raw1
= bytebits_to_byte(DemodBuffer
, 32);
80 uint32_t raw2
= bytebits_to_byte(DemodBuffer
+ 32, 32);
83 //checksum check (TBD)
86 PrintAndLogEx(SUCCESS
, "IDTECK Tag Found: Card ID %u , Raw: %08X%08X", id
, raw1
, raw2
);
90 static int CmdIdteckDemod(const char *Cmd
) {
91 CLIParserContext
*ctx
;
92 CLIParserInit(&ctx
, "lf idteck demod",
93 "Try to find Idteck preamble, if found decode / descramble data",
101 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
103 return demodIdteck(true);
106 static int CmdIdteckClone(const char *Cmd
) {
107 CLIParserContext
*ctx
;
108 CLIParserInit(&ctx
, "lf idteck clone",
109 "clone a Idteck tag to T55x7 or Q5/T5555 tag\n"
110 "Tag must be on the antenna when issuing this command.",
111 "lf idteck clone --raw 4944544B351FBE4B"
115 arg_strx0("r", "raw", "<hex>", "raw bytes"),
116 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
117 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
120 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
123 uint8_t raw
[8] = {0};
124 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
126 bool q5
= arg_get_lit(ctx
, 2);
127 bool em
= arg_get_lit(ctx
, 3);
131 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
135 uint32_t blocks
[3] = {T55x7_MODULATION_PSK1
| T55x7_BITRATE_RF_32
| 2 << T55x7_MAXBLOCK_SHIFT
, 0, 0};
136 char cardtype
[16] = {"T55x7"};
140 blocks
[0] = T5555_FIXED
| T55x7_MODULATION_PSK1
| T5555_SET_BITRATE(32) | 2 << T5555_MAXBLOCK_SHIFT
;
141 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
145 blocks
[0] = EM4305_IDTECK_CONFIG_BLOCK
;
146 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
149 for (uint8_t i
= 1; i
< ARRAYLEN(blocks
); i
++) {
150 blocks
[i
] = bytes_to_num(raw
+ ((i
- 1) * 4), sizeof(uint32_t));
153 // config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
154 PrintAndLogEx(INFO
, "Preparing to clone Idteck to " _YELLOW_("%s") " raw " _GREEN_("%s")
156 , sprint_hex_inrow(raw
, raw_len
)
158 print_blocks(blocks
, ARRAYLEN(blocks
));
162 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
164 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
166 PrintAndLogEx(SUCCESS
, "Done");
167 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf idteck reader`") " to verify");
171 static int CmdIdteckSim(const char *Cmd
) {
172 CLIParserContext
*ctx
;
173 CLIParserInit(&ctx
, "lf idteck sim",
174 "Enables simulation of Idteck card.\n"
175 "Simulation runs until the button is pressed or another USB command is issued.",
176 "lf idteck sim --raw 4944544B351FBE4B"
181 arg_strx0("r", "raw", "<hex>", "raw bytes"),
184 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
187 uint8_t raw
[8] = {0};
188 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
191 // convert to binarray
193 memset(bs
, 0x00, sizeof(bs
));
196 for (int8_t i
= 0; i
< raw_len
; i
++) {
197 uint8_t tmp
= raw
[i
];
198 bs
[counter
++] = (tmp
>> 7) & 1;
199 bs
[counter
++] = (tmp
>> 6) & 1;
200 bs
[counter
++] = (tmp
>> 5) & 1;
201 bs
[counter
++] = (tmp
>> 4) & 1;
202 bs
[counter
++] = (tmp
>> 3) & 1;
203 bs
[counter
++] = (tmp
>> 2) & 1;
204 bs
[counter
++] = (tmp
>> 1) & 1;
205 bs
[counter
++] = tmp
& 1;
208 PrintAndLogEx(SUCCESS
, "Simulating Idteck - raw " _YELLOW_("%s"), sprint_hex_inrow(raw
, raw_len
));
209 PrintAndLogEx(SUCCESS
, "Press pm3-button to abort simulation or run another command");
210 PrintAndLogEx(NORMAL
, "");
212 lf_psksim_t
*payload
= calloc(1, sizeof(lf_psksim_t
) + sizeof(bs
));
213 payload
->carrier
= 2;
216 memcpy(payload
->data
, bs
, sizeof(bs
));
218 clearCommandBuffer();
219 SendCommandNG(CMD_LF_PSK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_psksim_t
) + sizeof(bs
));
222 PacketResponseNG resp
;
223 WaitForResponse(CMD_LF_PSK_SIMULATE
, &resp
);
225 PrintAndLogEx(INFO
, "Done");
226 if (resp
.status
!= PM3_EOPABORTED
)
231 static int CmdIdteckReader(const char *Cmd
) {
232 CLIParserContext
*ctx
;
233 CLIParserInit(&ctx
, "lf idteck reader",
235 "lf idteck reader -@ -> continuous reader mode"
240 arg_lit0("@", NULL
, "optional - continuous reader mode"),
243 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
244 bool cm
= arg_get_lit(ctx
, 1);
248 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
252 lf_read(false, 5000);
254 } while (cm
&& !kbd_enter_pressed());
259 static command_t CommandTable
[] = {
260 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
261 {"demod", CmdIdteckDemod
, AlwaysAvailable
, "demodulate an Idteck tag from the GraphBuffer"},
262 {"reader", CmdIdteckReader
, IfPm3Lf
, "attempt to read and extract tag data"},
263 {"clone", CmdIdteckClone
, IfPm3Lf
, "clone Idteck tag to T55x7 or Q5/T5555"},
264 {"sim", CmdIdteckSim
, IfPm3Lf
, "simulate Idteck tag"},
265 {NULL
, NULL
, NULL
, NULL
}
268 static int CmdHelp(const char *Cmd
) {
269 (void)Cmd
; // Cmd is not used so far
270 CmdsHelp(CommandTable
);
274 int CmdLFIdteck(const char *Cmd
) {
275 clearCommandBuffer();
276 return CmdsParse(CommandTable
, Cmd
);
279 // Find IDTEC PSK1, RF Preamble == 0x4944544B, Demodsize 64bits
280 int detectIdteck(uint8_t *dest
, size_t *size
) {
281 //make sure buffer has data
282 if (*size
< 64 * 2) return -1;
284 if (getSignalProperties()->isnoise
) return -2;
286 size_t start_idx
= 0;
288 uint8_t preamble
[] = {0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1};
291 if (preambleSearch(dest
, preamble
, sizeof(preamble
), size
, &start_idx
) == false)
294 // wrong demoded size
298 return (int)start_idx
;