fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdlfmotorola.c
blob6d1786647a429a6d5499d57d220724573585d514
1 //-----------------------------------------------------------------------------
2 // Iceman, 2019
3 //
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
6 // the license.
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
14 #include "common.h"
15 #include "cmdparser.h" // command_t
16 #include "comms.h"
17 #include "ui.h"
18 #include "cmddata.h"
19 #include "cmdlf.h"
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
31 //PSK1
32 if (PSKDemod(32, 1, 100, true) != PM3_SUCCESS) {
33 PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: PSK Demod failed");
34 return PM3_ESOFT;
37 size_t size = DemodBufferLen;
38 int ans = detectMotorola(DemodBuffer, &size);
39 if (ans < 0) {
40 if (ans == -1)
41 PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: too few bits found");
42 else if (ans == -2)
43 PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: preamble not found");
44 else if (ans == -3)
45 PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: Size not correct: %zu", size);
46 else
47 PrintAndLogEx(DEBUG, "DEBUG: Error - Motorola: ans: %d", ans);
49 return PM3_ESOFT;
51 setDemodBuff(DemodBuffer, 64, ans);
52 setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
54 //got a good demod
55 uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
56 uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
58 // A0000000E308C0C1
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
65 // 9 .0 5 4 26 3 . 71
66 // . .0 5 4 26 3 . 71
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
73 uint16_t fc = 0;
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
85 // seems to match
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.
92 uint16_t csn = 0;
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);
117 return PM3_SUCCESS;
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",
124 "lf motorola demod"
127 void *argtable[] = {
128 arg_param_begin,
129 arg_param_end
131 CLIExecWithReturn(ctx, Cmd, argtable, true);
132 CLIParserFree(ctx);
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"
143 void *argtable[] = {
144 arg_param_begin,
145 arg_lit0("@", NULL, "optional - continuous reader mode"),
146 arg_param_end
148 CLIExecWithReturn(ctx, Cmd, argtable, true);
149 bool cm = arg_get_lit(ctx, 1);
150 CLIParserFree(ctx);
152 if (cm) {
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
158 sample_config sc = {
159 .decimation = -1,
160 .bits_per_sample = -1,
161 .averaging = false,
162 .divisor = LF_FREQ2DIV(74),
163 .trigger_threshold = -1,
164 .samples_to_skip = 4500,
165 .verbose = false
167 lf_config(&sc);
169 int res;
170 do {
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;
179 lf_config(&sc);
181 return res;
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"
194 void *argtable[] = {
195 arg_param_begin,
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"),
199 arg_param_end
201 CLIExecWithReturn(ctx, Cmd, argtable, false);
203 int raw_len = 0;
204 uint8_t raw[8];
205 CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
206 bool q5 = arg_get_lit(ctx, 2);
207 bool em = arg_get_lit(ctx, 3);
208 CLIParserFree(ctx);
210 if (q5 && em) {
211 PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
212 return PM3_EINVARG;
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"};
220 // Q5
221 if (q5) {
222 blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
223 snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
226 // EM4305
227 if (em) {
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")
237 , cardtype
238 , sprint_hex_inrow(raw, sizeof(raw))
240 print_blocks(blocks, ARRAYLEN(blocks));
242 int res;
243 if (em) {
244 res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
245 } else {
246 res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
248 PrintAndLogEx(SUCCESS, "Done");
249 PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola reader`") " to verify");
250 return res;
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.",
258 "lf motorola sim"
261 void *argtable[] = {
262 arg_param_begin,
263 arg_param_end
265 CLIExecWithReturn(ctx, Cmd, argtable, true);
266 CLIParserFree(ctx);
268 // PSK sim.
269 PrintAndLogEx(INFO, " PSK1 at 66 kHz... Interesting.");
270 PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
271 return PM3_SUCCESS;
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);
286 return PM3_SUCCESS;
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
298 if (*size < 64)
299 return -1;
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)) {
312 found_size = *size;
313 if (!preambleSearch(dest, preamble_i, sizeof(preamble_i), &found_size, &start_idx)) {
314 return -2;
316 PrintAndLogEx(DEBUG, "DEBUG: detectMotorola PSK1 found inverted preamble");
317 inverted = true;
320 *size = found_size;
322 // wrong demoded size
323 if (*size != 64)
324 return -3;
326 if (inverted && start_idx > 0) {
327 for (size_t i = start_idx - 1 ; i < *size + start_idx + 2; i++) {
328 dest[i] ^= 1;
332 return (int)start_idx;
335 int readMotorolaUid(void) {
336 return (CmdMotorolaReader("") == PM3_SUCCESS);