1 //-----------------------------------------------------------------------------
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
6 //-----------------------------------------------------------------------------
7 // Low frequency Jablotron tag commands
8 // Differential Biphase, RF/64, 64 bits long (complete)
9 //-----------------------------------------------------------------------------
11 #include "cmdlfjablotron.h"
16 #include "cmdparser.h" // command_t
18 #include "commonutil.h" // ARRAYLEN
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
) {
34 for (int i
= 16; i
< 56; i
+= 8) {
35 chksum
+= bytebits_to_byte(bits
+ i
, 8);
41 static uint64_t getJablontronCardId(uint64_t rawcode
) {
43 uint8_t bytes
[] = {0, 0, 0, 0, 0};
44 num_to_bytes(rawcode
, 5, bytes
);
45 for (int i
= 0; i
< 5; i
++) {
47 id
+= NIBBLE_HIGH(bytes
[i
]) * 10 + NIBBLE_LOW(bytes
[i
]);
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");
60 size_t size
= DemodBufferLen
;
61 int ans
= detectJablotron(DemodBuffer
, &size
);
65 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron too few bits found");
67 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron preamble not found");
69 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron size not correct: %zu", size
);
71 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron checksum failed");
73 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron ans: %d", ans
);
78 setDemodBuff(DemodBuffer
, JABLOTRON_ARR_LEN
, ans
);
79 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
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"));
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
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"
118 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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"
132 arg_lit0("@", NULL
, "optional - continuous reader mode"),
135 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
136 bool cm
= arg_get_lit(ctx
, 1);
140 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
144 lf_read(false, 16000);
146 } while (cm
&& !kbd_enter_pressed());
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"
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"),
169 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
180 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
184 uint32_t blocks
[3] = {T55x7_MODULATION_DIPHASE
| T55x7_BITRATE_RF_64
| 2 << T55x7_MAXBLOCK_SHIFT
, 0, 0};
185 char cardtype
[16] = {"T55x7"};
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");
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));
209 PrintAndLogEx(WARNING
, "Failed to allocate memory");
213 if (getJablotronBits(fullcode
, bits
) != PM3_SUCCESS
) {
214 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
218 blocks
[1] = bytebits_to_byte(bits
, 32);
219 blocks
[2] = bytebits_to_byte(bits
+ 32, 32);
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
));
230 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
232 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
234 PrintAndLogEx(SUCCESS
, "Done");
235 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf jablotron reader`") " to verify");
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"
249 arg_str1(NULL
, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
252 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
255 uint8_t raw
[5] = {0};
256 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
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));
271 PrintAndLogEx(WARNING
, "Failed to allocate memory");
275 getJablotronBits(fullcode
, bs
);
277 lf_asksim_t
*payload
= calloc(1, sizeof(lf_asksim_t
) + JABLOTRON_ARR_LEN
);
278 payload
->encoding
= 2;
280 payload
->separator
= 0;
282 memcpy(payload
->data
, bs
, JABLOTRON_ARR_LEN
);
286 clearCommandBuffer();
287 SendCommandNG(CMD_LF_ASK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_asksim_t
) + JABLOTRON_ARR_LEN
);
290 PacketResponseNG resp
;
291 WaitForResponse(CMD_LF_ASK_SIMULATE
, &resp
);
293 PrintAndLogEx(INFO
, "Done");
294 if (resp
.status
!= PM3_EOPABORTED
)
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
);
314 int CmdLFJablotron(const char *Cmd
) {
315 clearCommandBuffer();
316 return CmdsParse(CommandTable
, Cmd
);
319 int getJablotronBits(uint64_t fullcode
, uint8_t *bits
) {
321 num_to_bytebits(0xFFFF, 16, bits
);
324 num_to_bytebits(fullcode
, 40, bits
+ 16);
327 uint8_t chksum
= jablontron_chksum(bits
);
328 num_to_bytebits(chksum
, 8, bits
+ 56);
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
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
;