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 FDX-A FECAVA Destron tag commands
17 //-----------------------------------------------------------------------------
18 #include "cmdlfdestron.h"
19 #include <ctype.h> // tolower
20 #include <string.h> // memcpy
21 #include "commonutil.h" // ARRAYLEN
23 #include "cmdparser.h" // command_t
28 #include "lfdemod.h" // preamble test
29 #include "protocols.h" // t55xx defines
30 #include "cmdlft55xx.h" // clone..
31 #include "cmdlf.h" // cmdlfconfig
33 #include "cliparser.h" // cli parse input
34 #include "cmdlfem4x05.h" // EM defines
36 #define DESTRON_FRAME_SIZE 96
37 #define DESTRON_PREAMBLE_SIZE 16
39 static int CmdHelp(const char *Cmd
);
41 int demodDestron(bool verbose
) {
42 (void) verbose
; // unused so far
44 if (FSKrawDemod(0, 0, 0, 0, false) != PM3_SUCCESS
) {
45 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: FSK Demod failed");
49 size_t size
= g_DemodBufferLen
;
50 int ans
= detectDestron(g_DemodBuffer
, &size
);
53 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: too few bits found");
55 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: preamble not found");
57 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: Size not correct: %zu", size
);
59 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: ans: %d", ans
);
64 setDemodBuff(g_DemodBuffer
, DESTRON_FRAME_SIZE
, ans
);
65 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
67 uint8_t bits
[DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
] = {0};
68 size_t bitlen
= DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
;
69 memcpy(bits
, g_DemodBuffer
+ DESTRON_PREAMBLE_SIZE
, DESTRON_FRAME_SIZE
- DESTRON_PREAMBLE_SIZE
);
72 uint16_t errCnt
= manrawdecode(bits
, &bitlen
, 0, &alignPos
);
74 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: Manchester decoding errors: %d", ans
);
78 uint8_t data
[5] = {0};
79 uint8_t parity_err
= 0;
80 for (int i
= 0; i
< sizeof(data
); i
++) {
81 data
[i
] = bytebits_to_byte(bits
+ i
* 8, 8);
82 parity_err
+= oddparity8(data
[i
]);
86 PrintAndLogEx(DEBUG
, "DEBUG: Error - Destron: parity errors: %d", parity_err
);
89 PrintAndLogEx(SUCCESS
, "FDX-A FECAVA Destron: " _GREEN_("%s"), sprint_hex_inrow(data
, 5));
93 static int CmdDestronDemod(const char *Cmd
) {
94 CLIParserContext
*ctx
;
95 CLIParserInit(&ctx
, "lf destron demod",
96 "Try to find Destron preamble, if found decode / descramble data",
104 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
106 return demodDestron(true);
109 static int CmdDestronReader(const char *Cmd
) {
110 CLIParserContext
*ctx
;
111 CLIParserInit(&ctx
, "lf destron reader",
112 "read a Destron tag",
113 "lf destron reader -@ -> continuous reader mode"
118 arg_lit0("@", NULL
, "optional - continuous reader mode"),
121 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
122 bool cm
= arg_get_lit(ctx
, 1);
126 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
130 lf_read(false, 16000);
132 } while (cm
&& !kbd_enter_pressed());
137 static int CmdDestronClone(const char *Cmd
) {
138 CLIParserContext
*ctx
;
139 CLIParserInit(&ctx
, "lf destron clone",
140 "clone a Destron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
141 "lf destron clone --uid 1A2B3C4D5E\n"
142 "lf destron clone --q5 --uid 1A2B3C4D5E -> encode for Q5/T5555 tag\n"
143 "lf destron clone --em --uid 1A2B3C4D5E -> encode for EM4305/4469"
148 arg_str1("u", "uid", "<hex>", "5 bytes max"),
149 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
150 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
154 //TODO add selection of chip for Q5 or T55x7
155 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
159 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
160 bool q5
= arg_get_lit(ctx
, 2);
161 bool em
= arg_get_lit(ctx
, 3);
165 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
170 PrintAndLogEx(FAILED
, "Uid is max 5 bytes. (got %u)", datalen
);
174 uint32_t blocks
[4] = {0};
175 blocks
[0] = T55x7_BITRATE_RF_50
| T55x7_MODULATION_FSK2
| 3 << T55x7_MAXBLOCK_SHIFT
;
176 char cardtype
[16] = {"T55x7"};
179 blocks
[0] = T5555_FIXED
| T5555_MODULATION_FSK2
| T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT
;
180 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
185 PrintAndLogEx(WARNING
, "Beware some EM4305 tags don't support FSK and datarate = RF/50, check your tag copy!");
186 blocks
[0] = EM4305_DESTRON_CONFIG_BLOCK
;
187 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
190 uint8_t data_ex
[12 + 24] = {0}; // ManchesterEncode need extra room
191 for (int i
= 0; i
< datalen
; i
++) {
192 data_ex
[i
+ 1] = ~(data
[i
] | (oddparity8(data
[i
]) << 7));
195 // manchester encode it
196 for (int i
= 0; i
< 3; i
++) {
197 blocks
[i
+ 1] = manchesterEncode2Bytes((data_ex
[i
* 2] << 8) + data_ex
[i
* 2 + 1]);
200 blocks
[1] = (blocks
[1] & 0xFFFF) | 0xAAE20000;
202 PrintAndLogEx(INFO
, "Preparing to clone Destron tag to " _YELLOW_("%s") " with ID: " _YELLOW_("%s")
204 , sprint_hex_inrow(data
, datalen
)
208 print_blocks(blocks
, ARRAYLEN(blocks
));
211 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
213 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
215 PrintAndLogEx(SUCCESS
, "Done");
216 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf destron reader`") " to verify");
220 static int CmdDestronSim(const char *Cmd
) {
221 CLIParserContext
*ctx
;
222 CLIParserInit(&ctx
, "lf destron sim",
223 "Try to find Destron preamble, if found decode / descramble data",
231 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
233 PrintAndLogEx(INFO
, " To be implemented, feel free to contribute!");
237 static command_t CommandTable
[] = {
238 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
239 {"demod", CmdDestronDemod
, AlwaysAvailable
, "demodulate an Destron tag from the GraphBuffer"},
240 {"reader", CmdDestronReader
, IfPm3Lf
, "attempt to read and extract tag data"},
241 {"clone", CmdDestronClone
, IfPm3Lf
, "clone Destron tag to T55x7, Q5/T5555 or EM4305/4469"},
242 {"sim", CmdDestronSim
, IfPm3Lf
, "simulate Destron tag"},
243 {NULL
, NULL
, NULL
, NULL
}
246 static int CmdHelp(const char *Cmd
) {
247 (void)Cmd
; // Cmd is not used so far
248 CmdsHelp(CommandTable
);
252 int CmdLFDestron(const char *Cmd
) {
253 clearCommandBuffer();
254 return CmdsParse(CommandTable
, Cmd
);
257 // find Destron preamble in already demoded data
258 int detectDestron(uint8_t *dest
, size_t *size
) {
260 //make sure buffer has data
264 size_t found_size
= *size
;
265 size_t start_idx
= 0;
267 uint8_t preamble
[DESTRON_PREAMBLE_SIZE
] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0};
269 // preamble not found
270 if (!preambleSearch(dest
, preamble
, sizeof(preamble
), &found_size
, &start_idx
)) {
273 PrintAndLogEx(DEBUG
, "DEBUG: detectDestron FSK found preamble");
276 // wrong demoded size
280 return (int)start_idx
;
283 int readDestronUid(void) {
284 return (CmdDestronReader("") == PM3_SUCCESS
);