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 Motorola tag commands
9 // PSK1, RF/32, 64 bits long, at 74 kHz
10 //-----------------------------------------------------------------------------
11 #include "cmdlfmotorola.h"
12 #include <ctype.h> // tolower
13 #include "commonutil.h" // ARRAYLEN
15 #include "cmdparser.h" // command_t
20 #include "lfdemod.h" // preamble test
21 #include "protocols.h" // t55xx defines
22 #include "cmdlft55xx.h" // clone..
23 #include "cmdlf.h" // cmdlfconfig
24 #include "cliparser.h" // cli parse input
25 #include "cmdlfem4x05.h" // EM defines
27 static int CmdHelp(const char *Cmd
);
29 int demodMotorola(bool verbose
) {
30 (void) verbose
; // unused so far
32 if (PSKDemod(32, 1, 100, true) != PM3_SUCCESS
) {
33 PrintAndLogEx(DEBUG
, "DEBUG: Error - Motorola: PSK Demod failed");
37 size_t size
= DemodBufferLen
;
38 int ans
= detectMotorola(DemodBuffer
, &size
);
41 PrintAndLogEx(DEBUG
, "DEBUG: Error - Motorola: too few bits found");
43 PrintAndLogEx(DEBUG
, "DEBUG: Error - Motorola: preamble not found");
45 PrintAndLogEx(DEBUG
, "DEBUG: Error - Motorola: Size not correct: %zu", size
);
47 PrintAndLogEx(DEBUG
, "DEBUG: Error - Motorola: ans: %d", ans
);
51 setDemodBuff(DemodBuffer
, 64, ans
);
52 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
55 uint32_t raw1
= bytebits_to_byte(DemodBuffer
, 32);
56 uint32_t raw2
= bytebits_to_byte(DemodBuffer
+ 32, 32);
59 // 10100000000000000000000000000000 1110 0011 0000 1000 1100 0000 1100 0001
62 // 1 1 2 2 2 3 3 4 4 4 5 5 6
63 // 0 4 8 2 6 0 4 8 2 6 0 4 8 2 6 0
64 // 1010 0000 0000 0000 0000 0000 0000 0000 1110 0011 0000 1000 1100 0000 0101 0010
67 // 6 9 A5 C0FD E7 18 B 4 3 2
69 // hex(234) 0xEA bin(234) 1110 1010
70 // hex(437) 0x1B5 bin(437) 1 1011 0101
71 // hex(229) 0xE5 bin(229) 1110 0101
75 // FC seems to be guess work. Need more samples
76 // guessing printed FC is 4 digits. 1024? 10bit?
77 // fc |= DemodBuffer[38] << 9; // b10
78 fc
|= DemodBuffer
[34] << 8; // b9
80 fc
|= DemodBuffer
[44] << 7; // b8
81 fc
|= DemodBuffer
[47] << 6; // b7
82 fc
|= DemodBuffer
[57] << 5; // b6
83 fc
|= DemodBuffer
[49] << 4; // b5
86 fc
|= DemodBuffer
[53] << 3; // b4
87 fc
|= DemodBuffer
[48] << 2; // b3
88 fc
|= DemodBuffer
[58] << 1; // b2
89 fc
|= DemodBuffer
[39] << 0; // b1
91 // CSN was same as Indala CSN descramble.
93 csn
|= DemodBuffer
[42] << 15; // b16
94 csn
|= DemodBuffer
[45] << 14; // b15
95 csn
|= DemodBuffer
[43] << 13; // b14
96 csn
|= DemodBuffer
[40] << 12; // b13
97 csn
|= DemodBuffer
[52] << 11; // b12
98 csn
|= DemodBuffer
[36] << 10; // b11
99 csn
|= DemodBuffer
[35] << 9; // b10
100 csn
|= DemodBuffer
[51] << 8; // b9
101 csn
|= DemodBuffer
[46] << 7; // b8
102 csn
|= DemodBuffer
[33] << 6; // b7
103 csn
|= DemodBuffer
[37] << 5; // b6
104 csn
|= DemodBuffer
[54] << 4; // b5
105 csn
|= DemodBuffer
[56] << 3; // b4
106 csn
|= DemodBuffer
[59] << 2; // b3
107 csn
|= DemodBuffer
[50] << 1; // b2
108 csn
|= DemodBuffer
[41] << 0; // b1
110 uint8_t checksum
= 0;
111 checksum
|= DemodBuffer
[62] << 1; // b2
112 checksum
|= DemodBuffer
[63] << 0; // b1
115 PrintAndLogEx(SUCCESS
, "Motorola - fmt: " _GREEN_("26") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u") ", Raw: %08X%08X", fc
, csn
, raw1
, raw2
);
116 PrintAndLogEx(DEBUG
, "checksum: " _GREEN_("%1d%1d"), checksum
>> 1 & 0x01, checksum
& 0x01);
120 static int CmdMotorolaDemod(const char *Cmd
) {
121 CLIParserContext
*ctx
;
122 CLIParserInit(&ctx
, "lf motorola demod",
123 "Try to find Motorola preamble, if found decode / descramble data",
131 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
133 return demodMotorola(true);
136 static int CmdMotorolaReader(const char *Cmd
) {
137 CLIParserContext
*ctx
;
138 CLIParserInit(&ctx
, "lf motorola reader",
139 "read a Motorola tag",
140 "lf motorola reader -@ -> continuous reader mode"
145 arg_lit0("@", NULL
, "optional - continuous reader mode"),
148 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
149 bool cm
= arg_get_lit(ctx
, 1);
153 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
156 // Motorola Flexpass seem to work at 74 kHz
157 // and take about 4400 samples to befor modulating
160 .bits_per_sample
= -1,
162 .divisor
= LF_FREQ2DIV(74),
163 .trigger_threshold
= -1,
164 .samples_to_skip
= 4500,
171 // 64 * 32 * 2 * n-ish
172 lf_read(false, 5000);
173 res
= demodMotorola(!cm
);
174 } while (cm
&& !kbd_enter_pressed());
176 // reset back to 125 kHz
177 sc
.divisor
= LF_DIVISOR_125
;
178 sc
.samples_to_skip
= 0;
184 static int CmdMotorolaClone(const char *Cmd
) {
185 CLIParserContext
*ctx
;
186 CLIParserInit(&ctx
, "lf motorola clone",
187 "clone Motorola UID to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
188 "defaults to 64 bit format",
189 "lf motorola clone --raw a0000000a0002021\n"
190 "lf motorola clone --q5 --raw a0000000a0002021 -> encode for Q5/T5555 tag\n"
191 "lf motorola clone --em --raw a0000000a0002021 -> encode for EM4305/4469"
196 arg_strx1("r", "raw", "<hex>", "raw hex bytes. 8 bytes"),
197 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
198 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
201 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
205 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
206 bool q5
= arg_get_lit(ctx
, 2);
207 bool em
= arg_get_lit(ctx
, 3);
211 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
215 //TODO add selection of chip for Q5 or T55x7
216 uint32_t blocks
[3] = {0};
218 blocks
[0] = T55x7_BITRATE_RF_32
| T55x7_MODULATION_PSK1
| (2 << T55x7_MAXBLOCK_SHIFT
);
219 char cardtype
[16] = {"T55x7"};
222 blocks
[0] = T5555_FIXED
| T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1
| 2 << T5555_MAXBLOCK_SHIFT
;
223 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
228 blocks
[0] = EM4305_MOTOROLA_CONFIG_BLOCK
;
229 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
232 blocks
[1] = bytes_to_num(raw
, 4);
233 blocks
[2] = bytes_to_num(raw
+ 4, 4);
235 // config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
236 PrintAndLogEx(INFO
, "Preparing to clone Motorola 64bit to " _YELLOW_("%s") " with raw " _GREEN_("%s")
238 , sprint_hex_inrow(raw
, sizeof(raw
))
240 print_blocks(blocks
, ARRAYLEN(blocks
));
244 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
246 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
248 PrintAndLogEx(SUCCESS
, "Done");
249 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify");
253 static int CmdMotorolaSim(const char *Cmd
) {
254 CLIParserContext
*ctx
;
255 CLIParserInit(&ctx
, "lf motorola sim",
256 "Enables simulation of Motorola card with specified card number.\n"
257 "Simulation runs until the button is pressed or another USB command is issued.",
265 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
269 PrintAndLogEx(INFO
, " PSK1 at 66 kHz... Interesting.");
270 PrintAndLogEx(INFO
, " To be implemented, feel free to contribute!");
274 static command_t CommandTable
[] = {
275 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
276 {"demod", CmdMotorolaDemod
, AlwaysAvailable
, "demodulate an MOTOROLA tag from the GraphBuffer"},
277 {"reader", CmdMotorolaReader
, IfPm3Lf
, "attempt to read and extract tag data"},
278 {"clone", CmdMotorolaClone
, IfPm3Lf
, "clone MOTOROLA tag to T55x7"},
279 {"sim", CmdMotorolaSim
, IfPm3Lf
, "simulate MOTOROLA tag"},
280 {NULL
, NULL
, NULL
, NULL
}
283 static int CmdHelp(const char *Cmd
) {
284 (void)Cmd
; // Cmd is not used so far
285 CmdsHelp(CommandTable
);
289 int CmdLFMotorola(const char *Cmd
) {
290 clearCommandBuffer();
291 return CmdsParse(CommandTable
, Cmd
);
294 // find MOTOROLA preamble in already demoded data
295 int detectMotorola(uint8_t *dest
, size_t *size
) {
297 //make sure buffer has data
301 bool inverted
= false;
302 size_t found_size
= *size
;
303 size_t start_idx
= 0;
305 // Seems Motorola is based on the following indala format.
306 // standard 64 bit Motorola formats including 26 bit 40134 format
307 uint8_t preamble
[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
308 uint8_t preamble_i
[] = {0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0};
310 // preamble not found
311 if (!preambleSearch(dest
, preamble
, sizeof(preamble
), &found_size
, &start_idx
)) {
313 if (!preambleSearch(dest
, preamble_i
, sizeof(preamble_i
), &found_size
, &start_idx
)) {
316 PrintAndLogEx(DEBUG
, "DEBUG: detectMotorola PSK1 found inverted preamble");
322 // wrong demoded size
326 if (inverted
&& start_idx
> 0) {
327 for (size_t i
= start_idx
- 1 ; i
< *size
+ start_idx
+ 2; i
++) {
332 return (int)start_idx
;
335 int readMotorolaUid(void) {
336 return (CmdMotorolaReader("") == PM3_SUCCESS
);