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 // Low frequency Idteck tag commands
17 // PSK1, clk 32, 2 data blocks
18 //-----------------------------------------------------------------------------
19 #include "cmdlfidteck.h"
24 #include "cmdparser.h" // command_t
30 #include "commonutil.h" // num_to_bytes
31 #include "cliparser.h"
32 #include "cmdlfem4x05.h" // EM defines
33 #include "protocols.h" // T55x7 defines
34 #include "cmdlft55xx.h" // verifywrite
35 #include "generator.h"
36 #include "wiegand_formats.h"
38 static int CmdHelp(const char *Cmd
);
40 static int demod_idteck_signal(void) {
41 if (PSKDemod(0, 0, 100, false) != PM3_SUCCESS
) {
42 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck PSKDemod failed");
45 size_t size
= g_DemodBufferLen
;
47 // get binary from PSK1 wave
48 int idx
= detectIdteck(g_DemodBuffer
, &size
);
52 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: not enough samples");
54 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: just noise");
56 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: preamble not found");
58 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: size not correct: %zu", size
);
60 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: idx: %d", idx
);
62 // if didn't find preamble try again inverting
63 if (PSKDemod(0, 1, 100, false) != PM3_SUCCESS
) {
64 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck PSKDemod failed");
67 idx
= detectIdteck(g_DemodBuffer
, &size
);
71 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: not enough samples");
73 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: just noise");
75 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: preamble not found");
77 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: size not correct: %zu", size
);
79 PrintAndLogEx(DEBUG
, "DEBUG: Error - Idteck: idx: %d", idx
);
84 setDemodBuff(g_DemodBuffer
, 64, idx
);
88 int demodIdteck(uint8_t *raw
, bool verbose
) {
89 (void) verbose
; // unused so far
95 // get binary from PSK1 wave
96 int ret
= demod_idteck_signal();
97 if (ret
!= PM3_SUCCESS
) {
100 raw1
= bytebits_to_byte(g_DemodBuffer
, 32);
101 raw2
= bytebits_to_byte(g_DemodBuffer
+ 32, 32);
103 raw1
= bytes_to_num(raw
, 4);
104 raw2
= bytes_to_num(raw
+ 4, 4);
110 if (raw1
!= 0x4944544B) {
111 PrintAndLogEx(FAILED
, "No genuine IDTECK found");
114 // parity check (TBD)
118 // checksum check (TBD)
119 // 351FBE4B -> 90370752 Card Code [523707] CUSUM = 52+37+07=90
120 // So, first byte is Csum
121 uint8_t chksum
= ((tmp
>> 24) & 0xFF);
122 uint8_t calc
= ((tmp
>> 16) & 0xFF) +
123 ((tmp
>> 8) & 0xFF) +
126 id
= ((tmp
>> 16) & 0xFF) | ((tmp
>> 8) & 0xFF) << 8 | (tmp
& 0xFF) << 16;
129 PrintAndLogEx(SUCCESS
, "IDTECK Tag Found: Card ID " _GREEN_("%u") " ( 0x%06X ) Raw: %08X%08X chksum 0x%02X ( %s )",
135 (chksum
== calc
) ? _GREEN_("ok") : _RED_("fail")
138 wiegand_message_t packed
= {
144 HIDUnpack(0, &packed
);
148 static int CmdIdteckDemod(const char *Cmd
) {
149 CLIParserContext
*ctx
;
150 CLIParserInit(&ctx
, "lf idteck demod",
151 "Try to find Idteck preamble, if found decode / descramble data",
153 "lf idteck demod --raw 4944544B351FBE4B"
158 arg_str0("r", "raw", "<hex>", "raw bytes"),
161 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
163 uint8_t raw
[8] = {0};
164 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
166 return demodIdteck(raw
, true);
169 static int CmdIdteckClone(const char *Cmd
) {
170 CLIParserContext
*ctx
;
171 CLIParserInit(&ctx
, "lf idteck clone",
172 "clone a Idteck tag to T55x7 or Q5/T5555 tag\n"
173 "Tag must be on the antenna when issuing this command.",
174 "lf idteck clone --raw 4944544B351FBE4B"
178 arg_str1("r", "raw", "<hex>", "raw bytes"),
179 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
180 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
183 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
186 uint8_t raw
[8] = {0};
187 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
189 bool q5
= arg_get_lit(ctx
, 2);
190 bool em
= arg_get_lit(ctx
, 3);
194 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
198 uint32_t blocks
[3] = {T55x7_MODULATION_PSK1
| T55x7_BITRATE_RF_32
| 2 << T55x7_MAXBLOCK_SHIFT
, 0, 0};
199 char cardtype
[16] = {"T55x7"};
203 blocks
[0] = T5555_FIXED
| T55x7_MODULATION_PSK1
| T5555_SET_BITRATE(32) | 2 << T5555_MAXBLOCK_SHIFT
;
204 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
208 blocks
[0] = EM4305_IDTECK_CONFIG_BLOCK
;
209 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
212 for (uint8_t i
= 1; i
< ARRAYLEN(blocks
); i
++) {
213 blocks
[i
] = bytes_to_num(raw
+ ((i
- 1) * 4), sizeof(uint32_t));
216 // config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
217 PrintAndLogEx(INFO
, "Preparing to clone Idteck to " _YELLOW_("%s") " raw " _GREEN_("%s")
219 , sprint_hex_inrow(raw
, raw_len
)
221 print_blocks(blocks
, ARRAYLEN(blocks
));
225 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
227 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
229 PrintAndLogEx(SUCCESS
, "Done!");
230 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf idteck reader`") " to verify");
234 static int CmdIdteckSim(const char *Cmd
) {
235 CLIParserContext
*ctx
;
236 CLIParserInit(&ctx
, "lf idteck sim",
237 "Enables simulation of Idteck card.\n"
238 "Simulation runs until the button is pressed or another USB command is issued.",
239 "lf idteck sim --raw 4944544B351FBE4B"
244 arg_str1("r", "raw", "<hex>", "raw bytes"),
247 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
250 uint8_t raw
[8] = {0};
251 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
254 // convert to binarray
256 memset(bs
, 0x00, sizeof(bs
));
259 for (int32_t i
= 0; i
< raw_len
; i
++) {
260 uint8_t tmp
= raw
[i
];
261 bs
[counter
++] = (tmp
>> 7) & 1;
262 bs
[counter
++] = (tmp
>> 6) & 1;
263 bs
[counter
++] = (tmp
>> 5) & 1;
264 bs
[counter
++] = (tmp
>> 4) & 1;
265 bs
[counter
++] = (tmp
>> 3) & 1;
266 bs
[counter
++] = (tmp
>> 2) & 1;
267 bs
[counter
++] = (tmp
>> 1) & 1;
268 bs
[counter
++] = tmp
& 1;
271 PrintAndLogEx(SUCCESS
, "Simulating Idteck - raw " _YELLOW_("%s"), sprint_hex_inrow(raw
, raw_len
));
272 PrintAndLogEx(SUCCESS
, "Press " _GREEN_("pm3 button") " to abort simulation or run another command");
273 PrintAndLogEx(NORMAL
, "");
275 lf_psksim_t
*payload
= calloc(1, sizeof(lf_psksim_t
) + sizeof(bs
));
276 payload
->carrier
= 2;
279 memcpy(payload
->data
, bs
, sizeof(bs
));
281 clearCommandBuffer();
282 SendCommandNG(CMD_LF_PSK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_psksim_t
) + sizeof(bs
));
285 PacketResponseNG resp
;
286 WaitForResponse(CMD_LF_PSK_SIMULATE
, &resp
);
288 PrintAndLogEx(INFO
, "Done!");
289 if (resp
.status
!= PM3_EOPABORTED
) {
295 static int CmdIdteckReader(const char *Cmd
) {
296 CLIParserContext
*ctx
;
297 CLIParserInit(&ctx
, "lf idteck reader",
299 "lf idteck reader -@ -> continuous reader mode"
304 arg_lit0("@", NULL
, "optional - continuous reader mode"),
307 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
308 bool cm
= arg_get_lit(ctx
, 1);
312 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
316 lf_read(false, 5000);
317 demodIdteck(NULL
, !cm
);
318 } while (cm
&& !kbd_enter_pressed());
323 static command_t CommandTable
[] = {
324 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
325 {"demod", CmdIdteckDemod
, AlwaysAvailable
, "demodulate an Idteck tag from the GraphBuffer"},
326 {"reader", CmdIdteckReader
, IfPm3Lf
, "attempt to read and extract tag data"},
327 {"clone", CmdIdteckClone
, IfPm3Lf
, "clone Idteck tag to T55x7 or Q5/T5555"},
328 {"sim", CmdIdteckSim
, IfPm3Lf
, "simulate Idteck tag"},
329 {NULL
, NULL
, NULL
, NULL
}
332 static int CmdHelp(const char *Cmd
) {
333 (void)Cmd
; // Cmd is not used so far
334 CmdsHelp(CommandTable
);
338 int CmdLFIdteck(const char *Cmd
) {
339 clearCommandBuffer();
340 return CmdsParse(CommandTable
, Cmd
);
343 // Find IDTEC PSK1, RF Preamble == 0x4944544B, Demodsize 64bits
344 int detectIdteck(uint8_t *dest
, size_t *size
) {
345 //make sure buffer has data
346 if (*size
< 64 * 2) return -1;
348 if (getSignalProperties()->isnoise
) return -2;
350 size_t start_idx
= 0;
352 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};
355 if (preambleSearch(dest
, preamble
, sizeof(preamble
), size
, &start_idx
) == false)
358 // wrong demoded size
362 return (int)start_idx
;