1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Low frequency Jablotron tag commands
17 // Differential Biphase, RF/64, 64 bits long (complete)
18 //-----------------------------------------------------------------------------
20 #include "cmdlfjablotron.h"
25 #include "cmdparser.h" // command_t
27 #include "commonutil.h" // ARRAYLEN
31 #include "protocols.h" // for T55xx config register definitions
32 #include "lfdemod.h" // parityTest
33 #include "cmdlft55xx.h" // verifywrite
34 #include "cliparser.h"
35 #include "cmdlfem4x05.h" // EM defines
37 #define JABLOTRON_ARR_LEN 64
39 static int CmdHelp(const char *Cmd
);
41 static uint8_t jablontron_chksum(uint8_t *bits
) {
43 for (int i
= 16; i
< 56; i
+= 8) {
44 chksum
+= bytebits_to_byte(bits
+ i
, 8);
50 static uint64_t getJablontronCardId(uint64_t rawcode
) {
52 uint8_t bytes
[] = {0, 0, 0, 0, 0};
53 num_to_bytes(rawcode
, 5, bytes
);
54 for (int i
= 0; i
< 5; i
++) {
56 id
+= NIBBLE_HIGH(bytes
[i
]) * 10 + NIBBLE_LOW(bytes
[i
]);
61 int demodJablotron(bool verbose
) {
62 (void) verbose
; // unused so far
63 //Differential Biphase / di-phase (inverted biphase)
64 //get binary from ask wave
65 if (ASKbiphaseDemod(0, 64, 1, 0, false) != PM3_SUCCESS
) {
66 if (g_debugMode
) PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron ASKbiphaseDemod failed");
69 size_t size
= g_DemodBufferLen
;
70 int ans
= detectJablotron(g_DemodBuffer
, &size
);
74 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron too few bits found");
76 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron preamble not found");
78 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron size not correct: %zu", size
);
80 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron checksum failed");
82 PrintAndLogEx(DEBUG
, "DEBUG: Error - Jablotron ans: %d", ans
);
87 setDemodBuff(g_DemodBuffer
, JABLOTRON_ARR_LEN
, ans
);
88 setClockGrid(g_DemodClock
, g_DemodStartIdx
+ (ans
* g_DemodClock
));
91 uint32_t raw1
= bytebits_to_byte(g_DemodBuffer
, 32);
92 uint32_t raw2
= bytebits_to_byte(g_DemodBuffer
+ 32, 32);
94 // bytebits_to_byte - uint32_t
95 uint64_t rawid
= ((uint64_t)(bytebits_to_byte(g_DemodBuffer
+ 16, 8) & 0xff) << 32) | bytebits_to_byte(g_DemodBuffer
+ 24, 32);
96 uint64_t id
= getJablontronCardId(rawid
);
98 PrintAndLogEx(SUCCESS
, "Jablotron - Card: " _GREEN_("%"PRIx64
) ", Raw: %08X%08X", id
, raw1
, raw2
);
100 uint8_t chksum
= raw2
& 0xFF;
101 bool isok
= (chksum
== jablontron_chksum(g_DemodBuffer
));
103 PrintAndLogEx(DEBUG
, "Checksum: %02X ( %s )", chksum
, isok
? _GREEN_("ok") : _RED_("Fail"));
106 // Printed format: 1410-nn-nnnn-nnnn
107 PrintAndLogEx(SUCCESS
, "Printed: " _GREEN_("1410-%02X-%04X-%04X"),
108 (uint8_t)(id
>> 32) & 0xFF,
109 (uint16_t)(id
>> 16) & 0xFFFF,
110 (uint16_t)id
& 0xFFFF
115 //see ASKDemod for what args are accepted
116 static int CmdJablotronDemod(const char *Cmd
) {
117 CLIParserContext
*ctx
;
118 CLIParserInit(&ctx
, "lf jablotron demod",
119 "Try to find Jablotron preamble, if found decode / descramble data",
120 "lf jablotron demod\n"
127 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
129 return demodJablotron(true);
132 static int CmdJablotronReader(const char *Cmd
) {
133 CLIParserContext
*ctx
;
134 CLIParserInit(&ctx
, "lf jablotron reader",
135 "read a jablotron tag",
136 "lf jablotron reader -@ -> continuous reader mode"
141 arg_lit0("@", NULL
, "optional - continuous reader mode"),
144 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
145 bool cm
= arg_get_lit(ctx
, 1);
149 PrintAndLogEx(INFO
, "Press " _GREEN_("<Enter>") " to exit");
153 lf_read(false, 16000);
155 } while (cm
&& !kbd_enter_pressed());
160 static int CmdJablotronClone(const char *Cmd
) {
162 CLIParserContext
*ctx
;
163 CLIParserInit(&ctx
, "lf jablotron clone",
164 "clone a Jablotron tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
165 "Tag must be on the antenna when issuing this command.",
166 "lf jablotron clone --cn 01b669 -> encode for T55x7 tag\n"
167 "lf jablotron clone --cn 01b669 --q5 -> encode for Q5/T5555 tag\n"
168 "lf jablotron clone --cn 01b669 --em -> encode for EM4305/4469"
173 arg_str1(NULL
, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
174 arg_lit0(NULL
, "q5", "optional - specify writing to Q5/T5555 tag"),
175 arg_lit0(NULL
, "em", "optional - specify writing to EM4305/4469 tag"),
178 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
181 uint8_t raw
[5] = {0};
182 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
184 bool q5
= arg_get_lit(ctx
, 2);
185 bool em
= arg_get_lit(ctx
, 3);
189 PrintAndLogEx(FAILED
, "Can't specify both Q5 and EM4305 at the same time");
193 uint32_t blocks
[3] = {T55x7_MODULATION_DIPHASE
| T55x7_BITRATE_RF_64
| 2 << T55x7_MAXBLOCK_SHIFT
, 0, 0};
194 char cardtype
[16] = {"T55x7"};
197 blocks
[0] = T5555_FIXED
| T5555_MODULATION_BIPHASE
| T5555_INVERT_OUTPUT
| T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT
;
198 snprintf(cardtype
, sizeof(cardtype
), "Q5/T5555");
203 blocks
[0] = EM4305_JABLOTRON_CONFIG_BLOCK
;
204 snprintf(cardtype
, sizeof(cardtype
), "EM4305/4469");
208 uint64_t fullcode
= bytes_to_num(raw
, raw_len
);
210 // clearing the topbit needed for the preambl detection.
211 if ((fullcode
& 0x7FFFFFFFFF) != fullcode
) {
212 fullcode
&= 0x7FFFFFFFFF;
213 PrintAndLogEx(INFO
, "Card Number Truncated to 39bits: %"PRIx64
, fullcode
);
216 uint8_t *bits
= calloc(JABLOTRON_ARR_LEN
, sizeof(uint8_t));
218 PrintAndLogEx(WARNING
, "Failed to allocate memory");
222 if (getJablotronBits(fullcode
, bits
) != PM3_SUCCESS
) {
223 PrintAndLogEx(ERR
, "Error with tag bitstream generation.");
227 blocks
[1] = bytebits_to_byte(bits
, 32);
228 blocks
[2] = bytebits_to_byte(bits
+ 32, 32);
232 uint64_t id
= getJablontronCardId(fullcode
);
234 PrintAndLogEx(INFO
, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: " _GREEN_("%"PRIx64
)" id: " _GREEN_("%"PRIx64
), cardtype
, fullcode
, id
);
235 print_blocks(blocks
, ARRAYLEN(blocks
));
239 res
= em4x05_clone_tag(blocks
, ARRAYLEN(blocks
), 0, false);
241 res
= clone_t55xx_tag(blocks
, ARRAYLEN(blocks
));
243 PrintAndLogEx(SUCCESS
, "Done");
244 PrintAndLogEx(HINT
, "Hint: try " _YELLOW_("`lf jablotron reader`") " to verify");
248 static int CmdJablotronSim(const char *Cmd
) {
249 CLIParserContext
*ctx
;
250 CLIParserInit(&ctx
, "lf jablotron sim",
251 "Enables simulation of jablotron card with specified card number.\n"
252 "Simulation runs until the button is pressed or another USB command is issued.",
253 "lf jablotron sim --cn 01b669"
258 arg_str1(NULL
, "cn", "<hex>", "Jablotron card ID - 5 bytes max"),
261 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
264 uint8_t raw
[5] = {0};
265 CLIGetHexWithReturn(ctx
, 1, raw
, &raw_len
);
268 uint64_t fullcode
= bytes_to_num(raw
, raw_len
);
270 // clearing the topbit needed for the preambl detection.
271 if ((fullcode
& 0x7FFFFFFFFF) != fullcode
) {
272 fullcode
&= 0x7FFFFFFFFF;
273 PrintAndLogEx(INFO
, "Card Number Truncated to 39bits: %"PRIx64
, fullcode
);
276 PrintAndLogEx(SUCCESS
, "Simulating Jablotron - FullCode: " _YELLOW_("%"PRIx64
), fullcode
);
278 uint8_t *bs
= calloc(JABLOTRON_ARR_LEN
, sizeof(uint8_t));
280 PrintAndLogEx(WARNING
, "Failed to allocate memory");
284 getJablotronBits(fullcode
, bs
);
286 lf_asksim_t
*payload
= calloc(1, sizeof(lf_asksim_t
) + JABLOTRON_ARR_LEN
);
287 payload
->encoding
= 2;
289 payload
->separator
= 0;
291 memcpy(payload
->data
, bs
, JABLOTRON_ARR_LEN
);
295 clearCommandBuffer();
296 SendCommandNG(CMD_LF_ASK_SIMULATE
, (uint8_t *)payload
, sizeof(lf_asksim_t
) + JABLOTRON_ARR_LEN
);
299 PacketResponseNG resp
;
300 WaitForResponse(CMD_LF_ASK_SIMULATE
, &resp
);
302 PrintAndLogEx(INFO
, "Done!");
303 if (resp
.status
!= PM3_EOPABORTED
) {
309 static command_t CommandTable
[] = {
310 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
311 {"demod", CmdJablotronDemod
, AlwaysAvailable
, "demodulate an Jablotron tag from the GraphBuffer"},
312 {"reader", CmdJablotronReader
, IfPm3Lf
, "attempt to read and extract tag data"},
313 {"clone", CmdJablotronClone
, IfPm3Lf
, "clone jablotron tag to T55x7, Q5/T5555 or EM4305/4469"},
314 {"sim", CmdJablotronSim
, IfPm3Lf
, "simulate jablotron tag"},
315 {NULL
, NULL
, NULL
, NULL
}
318 static int CmdHelp(const char *Cmd
) {
319 (void)Cmd
; // Cmd is not used so far
320 CmdsHelp(CommandTable
);
324 int CmdLFJablotron(const char *Cmd
) {
325 clearCommandBuffer();
326 return CmdsParse(CommandTable
, Cmd
);
329 int getJablotronBits(uint64_t fullcode
, uint8_t *bits
) {
331 num_to_bytebits(0xFFFF, 16, bits
);
334 num_to_bytebits(fullcode
, 40, bits
+ 16);
337 uint8_t chksum
= jablontron_chksum(bits
);
338 num_to_bytebits(chksum
, 8, bits
+ 56);
342 // ASK/Diphase fc/64 (inverted Biphase)
343 // Note: this is not a demod, this is only a detection
344 // the parameter *bits needs to be demoded before call
345 // 0xFFFF preamble, 64bits
346 int detectJablotron(uint8_t *bits
, size_t *size
) {
347 if (*size
< JABLOTRON_ARR_LEN
* 2) return -1; //make sure buffer has enough data
349 uint8_t preamble
[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0};
350 if (preambleSearch(bits
, preamble
, sizeof(preamble
), size
, &startIdx
) == 0)
351 return -2; //preamble not found
352 if (*size
!= JABLOTRON_ARR_LEN
) return -3; // wrong demoded size
354 uint8_t checkchksum
= jablontron_chksum(bits
+ startIdx
);
355 uint8_t crc
= bytebits_to_byte(bits
+ startIdx
+ 56, 8);
356 if (checkchksum
!= crc
) return -5;
357 return (int)startIdx
;