fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdlfpresco.c
blobbdbef5463afd64f9ab5e4284cf9d55a51fb78282
1 //-----------------------------------------------------------------------------
2 //
3 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
4 // at your option, any later version. See the LICENSE.txt file for the text of
5 // the license.
6 //-----------------------------------------------------------------------------
7 // Low frequency Presco tag commands
8 //-----------------------------------------------------------------------------
10 #include "cmdlfpresco.h"
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include "commonutil.h" // ARRAYLEN
16 #include "cmdparser.h" // command_t
17 #include "comms.h"
18 #include "ui.h"
19 #include "cmddata.h"
20 #include "cmdlf.h"
21 #include "protocols.h" // for T55xx config register definitions
22 #include "lfdemod.h" // parityTest
23 #include "cmdlft55xx.h" // verifywrite
24 #include "cmdlfem4x05.h" //
25 #include "cliparser.h"
27 static int CmdHelp(const char *Cmd);
29 // find presco preamble 0x10D in already demoded data
30 static int detectPresco(uint8_t *dest, size_t *size) {
31 if (*size < 128 * 2) return -1; //make sure buffer has data
32 size_t startIdx = 0;
33 uint8_t preamble[] = {0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
34 if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
35 return -2; //preamble not found
36 if (*size != 128) return -3; //wrong demoded size
37 //return start position
38 return (int)startIdx;
41 // convert base 12 ID to sitecode & usercode & 8 bit other unknown code
42 static int getWiegandFromPrintedPresco(void *arr, uint32_t *fullcode) {
43 char *s = (char *)arr;
44 uint8_t val = 0;
45 for (int i = 0; i < strlen(s); ++i) {
46 // Get value from number string.
47 if (s[i] == '*')
48 val = 10;
49 if (s[i] == '#')
50 val = 11;
51 if (s[i] >= 0x30 && s[i] <= 0x39)
52 val = s[i] - 0x30;
54 *fullcode += val;
56 // last digit is only added, not multipled.
57 if (i < strlen(s) - 1)
58 *fullcode *= 12;
60 return PM3_SUCCESS;
63 // calc not certain - intended to get bitstream for programming / sim
64 static int getPrescoBits(uint32_t fullcode, uint8_t *prescoBits) {
65 num_to_bytebits(0x10D00000, 32, prescoBits);
66 num_to_bytebits(0x00000000, 32, prescoBits + 32);
67 num_to_bytebits(0x00000000, 32, prescoBits + 64);
68 num_to_bytebits(fullcode, 32, prescoBits + 96);
69 return PM3_SUCCESS;
72 //see ASKDemod for what args are accepted
73 int demodPresco(bool verbose) {
74 (void) verbose; // unused so far
75 bool st = true;
76 if (ASKDemod_ext(32, 0, 0, 0, false, false, false, 1, &st) != PM3_SUCCESS) {
77 PrintAndLogEx(DEBUG, "DEBUG: Error Presco ASKDemod failed");
78 return PM3_ESOFT;
80 size_t size = DemodBufferLen;
81 int ans = detectPresco(DemodBuffer, &size);
82 if (ans < 0) {
83 if (ans == -1)
84 PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: too few bits found");
85 else if (ans == -2)
86 PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: preamble not found");
87 else if (ans == -3)
88 PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: Size not correct: %zu", size);
89 else
90 PrintAndLogEx(DEBUG, "DEBUG: Error - Presco: ans: %d", ans);
91 return PM3_ESOFT;
93 setDemodBuff(DemodBuffer, 128, ans);
94 setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
96 //got a good demod
97 uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
98 uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
99 uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32);
100 uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32);
101 uint32_t fullcode = raw4;
102 uint32_t usercode = fullcode & 0x0000FFFF;
103 uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
105 PrintAndLogEx(SUCCESS, "Presco Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08X") " Raw: " _YELLOW_("%08X%08X%08X%08X")
106 , sitecode
107 , usercode
108 , fullcode
109 , raw1, raw2, raw3, raw4
111 return PM3_SUCCESS;
114 static int CmdPrescoDemod(const char *Cmd) {
115 CLIParserContext *ctx;
116 CLIParserInit(&ctx, "lf presco demod",
117 "Try to find presco preamble, if found decode / descramble data",
118 "lf presco demod"
121 void *argtable[] = {
122 arg_param_begin,
123 arg_param_end
125 CLIExecWithReturn(ctx, Cmd, argtable, true);
126 CLIParserFree(ctx);
127 return demodPresco(true);
130 //see ASKDemod for what args are accepted
131 static int CmdPrescoReader(const char *Cmd) {
132 CLIParserContext *ctx;
133 CLIParserInit(&ctx, "lf presco reader",
134 "read a presco tag",
135 "lf presco reader -@ -> continuous reader mode"
138 void *argtable[] = {
139 arg_param_begin,
140 arg_lit0("@", NULL, "optional - continuous reader mode"),
141 arg_param_end
143 CLIExecWithReturn(ctx, Cmd, argtable, true);
144 bool cm = arg_get_lit(ctx, 1);
145 CLIParserFree(ctx);
147 if (cm) {
148 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
151 do {
152 lf_read(false, 12000);
153 demodPresco(!cm);
154 } while (cm && !kbd_enter_pressed());
155 return PM3_SUCCESS;
158 // takes base 12 ID converts to hex
159 // Or takes 8 digit hex ID
160 static int CmdPrescoClone(const char *Cmd) {
161 CLIParserContext *ctx;
162 CLIParserInit(&ctx, "lf presco clone",
163 "clone a presco tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
164 "lf presco clone -d 018363467\n"
165 "lf presco clone -d 018363467 --q5 -> encode for Q5/T5555 tag\n"
166 "lf presco clone -d 018363467 --em -> encode for EM4305/4469"
169 void *argtable[] = {
170 arg_param_begin,
171 arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
172 arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
173 arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
174 arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
175 arg_param_end
177 CLIExecWithReturn(ctx, Cmd, argtable, false);
179 int hex_len = 0;
180 uint8_t hex[4] = {0, 0, 0, 0};
181 CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
183 uint8_t idstr[11];
184 int slen = 9;
185 memset(idstr, 0x00, sizeof(idstr));
186 CLIGetStrWithReturn(ctx, 2, idstr, &slen);
188 bool q5 = arg_get_lit(ctx, 3);
189 bool em = arg_get_lit(ctx, 4);
190 CLIParserFree(ctx);
192 if (q5 && em) {
193 PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
194 return PM3_EINVARG;
197 uint32_t fullcode = 0;
199 if (hex_len) {
200 fullcode = bytes_to_num(hex, hex_len);
201 } else {
202 //param get string int param_getstr(const char *line, int paramnum, char * str)
203 if (slen < 2) {
204 PrintAndLogEx(ERR, "Must contain atleast 2 digits");
205 return PM3_EINVARG;
208 getWiegandFromPrintedPresco(idstr, &fullcode);
211 uint32_t usercode = fullcode & 0x0000FFFF; //% 65566
212 uint32_t sitecode = (fullcode >> 24) & 0x000000FF; // /= 16777216;
214 uint32_t blocks[5] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT | T55x7_ST_TERMINATOR, 0, 0, 0, 0};
216 char cardtype[16] = {"T55x7"};
217 // Q5
218 if (q5) {
219 blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR;
220 snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
223 // EM4305
224 if (em) {
225 blocks[0] = EM4305_PRESCO_CONFIG_BLOCK;
226 snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
229 if ((sitecode & 0xFF) != sitecode) {
230 sitecode &= 0xFF;
231 PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
234 if ((usercode & 0xFFFF) != usercode) {
235 usercode &= 0xFFFF;
236 PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
239 blocks[1] = 0x10D00000; //preamble
240 blocks[2] = 0x00000000;
241 blocks[3] = 0x00000000;
242 blocks[4] = fullcode;
244 PrintAndLogEx(INFO, "Preparing to clone Presco to " _GREEN_("%s") " with Site code: " _GREEN_("%u") " User code: " _GREEN_("%u") " Full code: " _GREEN_("%08x")
245 , cardtype
246 , sitecode
247 , usercode
248 , fullcode
250 print_blocks(blocks, ARRAYLEN(blocks));
252 int res;
253 if (em) {
254 res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
255 } else {
256 res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
258 PrintAndLogEx(SUCCESS, "Done");
259 PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco reader`") " to verify");
260 return res;
263 // takes base 12 ID converts to hex
264 // Or takes 8 digit hex ID
265 static int CmdPrescoSim(const char *Cmd) {
266 CLIParserContext *ctx;
267 CLIParserInit(&ctx, "lf presco sim",
268 "Enables simulation of presco card with specified card number.\n"
269 "Simulation runs until the button is pressed or another USB command is issued.\n"
270 "Per presco format, the card number is 9 digit number and can contain *# chars. Larger values are truncated.",
271 "lf presco sim -d 018363467"
274 void *argtable[] = {
275 arg_param_begin,
276 arg_str0("c", NULL, "<hex>", "8 digit hex card number"),
277 arg_str0("d", NULL, "<digits>", "9 digit presco card ID"),
278 arg_param_end
280 CLIExecWithReturn(ctx, Cmd, argtable, false);
282 int hex_len = 0;
283 uint8_t hex[4] = {0, 0, 0, 0};
284 CLIGetHexWithReturn(ctx, 1, hex, &hex_len);
286 uint8_t idstr[11];
287 int slen = 9;
288 memset(idstr, 0x00, sizeof(idstr));
289 CLIGetStrWithReturn(ctx, 2, idstr, &slen);
290 CLIParserFree(ctx);
292 uint32_t fullcode = 0;
294 if (hex_len) {
295 fullcode = bytes_to_num(hex, hex_len);
296 } else {
297 if (slen < 2) {
298 PrintAndLogEx(ERR, "Must contain atleast 2 digits");
299 return PM3_EINVARG;
301 getWiegandFromPrintedPresco(idstr, &fullcode);
304 uint32_t usercode = fullcode & 0x0000FFFF;
305 uint32_t sitecode = (fullcode >> 24) & 0x000000FF;
307 if ((sitecode & 0xFF) != sitecode) {
308 sitecode &= 0xFF;
309 PrintAndLogEx(INFO, "Site code truncated to 8-bits (Presco): %u", sitecode);
312 if ((usercode & 0xFFFF) != usercode) {
313 usercode &= 0xFFFF;
314 PrintAndLogEx(INFO, "User code truncated to 16-bits (Presco): %u", usercode);
317 PrintAndLogEx(SUCCESS, "Simulating Presco - Site Code: " _GREEN_("%u") " User Code: " _GREEN_("%u") " Full Code: " _GREEN_("%08X")
318 , sitecode
319 , usercode
320 , fullcode)
323 uint8_t bs[128];
324 getPrescoBits(fullcode, bs);
326 lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
327 payload->encoding = 1;
328 payload->invert = 0;
329 payload->separator = 1;
330 payload->clock = 32;
331 memcpy(payload->data, bs, sizeof(bs));
333 clearCommandBuffer();
334 SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
335 free(payload);
337 PacketResponseNG resp;
338 WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
340 PrintAndLogEx(INFO, "Done");
341 if (resp.status != PM3_EOPABORTED)
342 return resp.status;
343 return PM3_SUCCESS;
346 static command_t CommandTable[] = {
347 {"help", CmdHelp, AlwaysAvailable, "This help"},
348 {"demod", CmdPrescoDemod, AlwaysAvailable, "demodulate Presco tag from the GraphBuffer"},
349 {"reader", CmdPrescoReader, IfPm3Lf, "attempt to read and extract tag data"},
350 {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"},
351 {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"},
352 {NULL, NULL, NULL, NULL}
355 static int CmdHelp(const char *Cmd) {
356 (void)Cmd; // Cmd is not used so far
357 CmdsHelp(CommandTable);
358 return PM3_SUCCESS;
361 int CmdLFPresco(const char *Cmd) {
362 clearCommandBuffer();
363 return CmdsParse(CommandTable, Cmd);