fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdlfjablotron.c
blobf7db7169efbad4860d253e26b5ce24f08a7a1170
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 Jablotron tag commands
8 // Differential Biphase, RF/64, 64 bits long (complete)
9 //-----------------------------------------------------------------------------
11 #include "cmdlfjablotron.h"
12 #include <string.h>
13 #include <inttypes.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include "cmdparser.h" // command_t
17 #include "comms.h"
18 #include "commonutil.h" // ARRAYLEN
19 #include "ui.h"
20 #include "cmddata.h"
21 #include "cmdlf.h"
22 #include "protocols.h" // for T55xx config register definitions
23 #include "lfdemod.h" // parityTest
24 #include "cmdlft55xx.h" // verifywrite
25 #include "cliparser.h"
26 #include "cmdlfem4x05.h" // EM defines
28 #define JABLOTRON_ARR_LEN 64
30 static int CmdHelp(const char *Cmd);
32 static uint8_t jablontron_chksum(uint8_t *bits) {
33 uint8_t chksum = 0;
34 for (int i = 16; i < 56; i += 8) {
35 chksum += bytebits_to_byte(bits + i, 8);
37 chksum ^= 0x3A;
38 return chksum;
41 static uint64_t getJablontronCardId(uint64_t rawcode) {
42 uint64_t id = 0;
43 uint8_t bytes[] = {0, 0, 0, 0, 0};
44 num_to_bytes(rawcode, 5, bytes);
45 for (int i = 0; i < 5; i++) {
46 id *= 100;
47 id += NIBBLE_HIGH(bytes[i]) * 10 + NIBBLE_LOW(bytes[i]);
49 return id;
52 int demodJablotron(bool verbose) {
53 (void) verbose; // unused so far
54 //Differential Biphase / di-phase (inverted biphase)
55 //get binary from ask wave
56 if (ASKbiphaseDemod(0, 64, 1, 0, false) != PM3_SUCCESS) {
57 if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron ASKbiphaseDemod failed");
58 return PM3_ESOFT;
60 size_t size = DemodBufferLen;
61 int ans = detectJablotron(DemodBuffer, &size);
62 if (ans < 0) {
63 if (g_debugMode) {
64 if (ans == -1)
65 PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron too few bits found");
66 else if (ans == -2)
67 PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron preamble not found");
68 else if (ans == -3)
69 PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron size not correct: %zu", size);
70 else if (ans == -5)
71 PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron checksum failed");
72 else
73 PrintAndLogEx(DEBUG, "DEBUG: Error - Jablotron ans: %d", ans);
75 return PM3_ESOFT;
78 setDemodBuff(DemodBuffer, JABLOTRON_ARR_LEN, ans);
79 setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
81 //got a good demod
82 uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
83 uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
85 // bytebits_to_byte - uint32_t
86 uint64_t rawid = ((uint64_t)(bytebits_to_byte(DemodBuffer + 16, 8) & 0xff) << 32) | bytebits_to_byte(DemodBuffer + 24, 32);
87 uint64_t id = getJablontronCardId(rawid);
89 PrintAndLogEx(SUCCESS, "Jablotron - Card: " _GREEN_("%"PRIx64) ", Raw: %08X%08X", id, raw1, raw2);
91 uint8_t chksum = raw2 & 0xFF;
92 bool isok = (chksum == jablontron_chksum(DemodBuffer));
94 PrintAndLogEx(DEBUG, "Checksum: %02X (%s)", chksum, isok ? _GREEN_("ok") : _RED_("Fail"));
96 id = DEC2BCD(id);
97 // Printed format: 1410-nn-nnnn-nnnn
98 PrintAndLogEx(SUCCESS, "Printed: " _GREEN_("1410-%02X-%04X-%04X"),
99 (uint8_t)(id >> 32) & 0xFF,
100 (uint16_t)(id >> 16) & 0xFFFF,
101 (uint16_t)id & 0xFFFF
103 return PM3_SUCCESS;
106 //see ASKDemod for what args are accepted
107 static int CmdJablotronDemod(const char *Cmd) {
108 CLIParserContext *ctx;
109 CLIParserInit(&ctx, "lf jablotron demod",
110 "Try to find Jablotron preamble, if found decode / descramble data",
111 "lf jablotron demod\n"
114 void *argtable[] = {
115 arg_param_begin,
116 arg_param_end
118 CLIExecWithReturn(ctx, Cmd, argtable, true);
119 CLIParserFree(ctx);
120 return demodJablotron(true);
123 static int CmdJablotronReader(const char *Cmd) {
124 CLIParserContext *ctx;
125 CLIParserInit(&ctx, "lf jablotron reader",
126 "read a jablotron tag",
127 "lf jablotron reader -@ -> continuous reader mode"
130 void *argtable[] = {
131 arg_param_begin,
132 arg_lit0("@", NULL, "optional - continuous reader mode"),
133 arg_param_end
135 CLIExecWithReturn(ctx, Cmd, argtable, true);
136 bool cm = arg_get_lit(ctx, 1);
137 CLIParserFree(ctx);
139 if (cm) {
140 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
143 do {
144 lf_read(false, 16000);
145 demodJablotron(!cm);
146 } while (cm && !kbd_enter_pressed());
148 return PM3_SUCCESS;
151 static int CmdJablotronClone(const char *Cmd) {
153 CLIParserContext *ctx;
154 CLIParserInit(&ctx, "lf jablotron clone",
155 "clone a Jablotron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
156 "Tag must be on the antenna when issuing this command.",
157 "lf jablotron clone --cn 01b669\n"
158 "lf jablotron clone --q5 --cn 01b669 -> encode for Q5/T5555 tag\n"
159 "lf jablotron clone --em --cn 01b669 -> encode for EM4305/4469"
162 void *argtable[] = {
163 arg_param_begin,
164 arg_str1(NULL, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
165 arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
166 arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
167 arg_param_end
169 CLIExecWithReturn(ctx, Cmd, argtable, false);
171 int raw_len = 0;
172 uint8_t raw[5] = {0};
173 CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
175 bool q5 = arg_get_lit(ctx, 2);
176 bool em = arg_get_lit(ctx, 3);
177 CLIParserFree(ctx);
179 if (q5 && em) {
180 PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
181 return PM3_EINVARG;
184 uint32_t blocks[3] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
185 char cardtype[16] = {"T55x7"};
186 // Q5
187 if (q5) {
188 blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
189 snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
192 // EM4305
193 if (em) {
194 blocks[0] = EM4305_JABLOTRON_CONFIG_BLOCK;
195 snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
199 uint64_t fullcode = bytes_to_num(raw, raw_len);
201 // clearing the topbit needed for the preambl detection.
202 if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
203 fullcode &= 0x7FFFFFFFFF;
204 PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
207 uint8_t *bits = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
208 if (bits == NULL) {
209 PrintAndLogEx(WARNING, "Failed to allocate memory");
210 return PM3_EMALLOC;
213 if (getJablotronBits(fullcode, bits) != PM3_SUCCESS) {
214 PrintAndLogEx(ERR, "Error with tag bitstream generation.");
215 return PM3_ESOFT;
218 blocks[1] = bytebits_to_byte(bits, 32);
219 blocks[2] = bytebits_to_byte(bits + 32, 32);
221 free(bits);
223 uint64_t id = getJablontronCardId(fullcode);
225 PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: " _GREEN_("%"PRIx64)" id: " _GREEN_("%"PRIx64), cardtype, fullcode, id);
226 print_blocks(blocks, ARRAYLEN(blocks));
228 int res;
229 if (em) {
230 res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
231 } else {
232 res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
234 PrintAndLogEx(SUCCESS, "Done");
235 PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf jablotron reader`") " to verify");
236 return res;
239 static int CmdJablotronSim(const char *Cmd) {
240 CLIParserContext *ctx;
241 CLIParserInit(&ctx, "lf jablotron sim",
242 "Enables simulation of jablotron card with specified card number.\n"
243 "Simulation runs until the button is pressed or another USB command is issued.",
244 "lf jablotron sim --cn 01b669"
247 void *argtable[] = {
248 arg_param_begin,
249 arg_str1(NULL, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
250 arg_param_end
252 CLIExecWithReturn(ctx, Cmd, argtable, false);
254 int raw_len = 0;
255 uint8_t raw[5] = {0};
256 CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
257 CLIParserFree(ctx);
259 uint64_t fullcode = bytes_to_num(raw, raw_len);
261 // clearing the topbit needed for the preambl detection.
262 if ((fullcode & 0x7FFFFFFFFF) != fullcode) {
263 fullcode &= 0x7FFFFFFFFF;
264 PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
267 PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: " _YELLOW_("%"PRIx64), fullcode);
269 uint8_t *bs = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
270 if (bs == NULL) {
271 PrintAndLogEx(WARNING, "Failed to allocate memory");
272 return PM3_EMALLOC;
275 getJablotronBits(fullcode, bs);
277 lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + JABLOTRON_ARR_LEN);
278 payload->encoding = 2;
279 payload->invert = 1;
280 payload->separator = 0;
281 payload->clock = 64;
282 memcpy(payload->data, bs, JABLOTRON_ARR_LEN);
284 free(bs);
286 clearCommandBuffer();
287 SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + JABLOTRON_ARR_LEN);
288 free(payload);
290 PacketResponseNG resp;
291 WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
293 PrintAndLogEx(INFO, "Done");
294 if (resp.status != PM3_EOPABORTED)
295 return resp.status;
296 return PM3_SUCCESS;
299 static command_t CommandTable[] = {
300 {"help", CmdHelp, AlwaysAvailable, "This help"},
301 {"demod", CmdJablotronDemod, AlwaysAvailable, "demodulate an Jablotron tag from the GraphBuffer"},
302 {"reader", CmdJablotronReader, IfPm3Lf, "attempt to read and extract tag data"},
303 {"clone", CmdJablotronClone, IfPm3Lf, "clone jablotron tag to T55x7 or Q5/T5555"},
304 {"sim", CmdJablotronSim, IfPm3Lf, "simulate jablotron tag"},
305 {NULL, NULL, NULL, NULL}
308 static int CmdHelp(const char *Cmd) {
309 (void)Cmd; // Cmd is not used so far
310 CmdsHelp(CommandTable);
311 return PM3_SUCCESS;
314 int CmdLFJablotron(const char *Cmd) {
315 clearCommandBuffer();
316 return CmdsParse(CommandTable, Cmd);
319 int getJablotronBits(uint64_t fullcode, uint8_t *bits) {
320 //preamp
321 num_to_bytebits(0xFFFF, 16, bits);
323 //fullcode
324 num_to_bytebits(fullcode, 40, bits + 16);
326 //chksum byte
327 uint8_t chksum = jablontron_chksum(bits);
328 num_to_bytebits(chksum, 8, bits + 56);
329 return PM3_SUCCESS;
332 // ASK/Diphase fc/64 (inverted Biphase)
333 // Note: this is not a demod, this is only a detection
334 // the parameter *bits needs to be demoded before call
335 // 0xFFFF preamble, 64bits
336 int detectJablotron(uint8_t *bits, size_t *size) {
337 if (*size < JABLOTRON_ARR_LEN * 2) return -1; //make sure buffer has enough data
338 size_t startIdx = 0;
339 uint8_t preamble[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0};
340 if (preambleSearch(bits, preamble, sizeof(preamble), size, &startIdx) == 0)
341 return -2; //preamble not found
342 if (*size != JABLOTRON_ARR_LEN) return -3; // wrong demoded size
344 uint8_t checkchksum = jablontron_chksum(bits + startIdx);
345 uint8_t crc = bytebits_to_byte(bits + startIdx + 56, 8);
346 if (checkchksum != crc) return -5;
347 return (int)startIdx;