textual
[RRG-proxmark3.git] / client / src / cmdlfnexwatch.c
blobd46c4004645ca9e9e710a230a7e43ae4f77a5ba8
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 Honeywell NexWatch tag commands
8 // PSK1 RF/16, RF/2, 128 bits long (known)
9 //-----------------------------------------------------------------------------
11 #include "cmdlfnexwatch.h"
12 #include <inttypes.h> // PRIu
13 #include <string.h>
14 #include <ctype.h> // tolower
15 #include <stdlib.h> // free, alloc
16 #include "commonutil.h" // ARRAYLEN
17 #include "cmdparser.h" // command_t
18 #include "comms.h"
19 #include "ui.h"
20 #include "cmddata.h" // preamblesearch
21 #include "cmdlf.h"
22 #include "lfdemod.h"
23 #include "protocols.h" // t55xx defines
24 #include "cmdlft55xx.h" // clone..
25 #include "cmdlfem4x05.h" //
26 #include "cliparser.h"
28 typedef enum {
29 SCRAMBLE,
30 DESCRAMBLE
31 } NexWatchScramble_t;
33 static int CmdHelp(const char *Cmd);
35 // scramble parity (1234) -> (4231)
36 static uint8_t nexwatch_parity_swap(uint8_t parity) {
37 uint8_t a = (((parity >> 3) & 1));
38 a |= (((parity >> 1) & 1) << 1);
39 a |= (((parity >> 2) & 1) << 2);
40 a |= ((parity & 1) << 3);
41 return a;
43 // parity check
44 // from 32b hex id, 4b mode,
45 static uint8_t nexwatch_parity(uint8_t hexid[5]) {
46 uint8_t p = 0;
47 for (uint8_t i = 0; i < 5; i++) {
48 p ^= NIBBLE_HIGH(hexid[i]);
49 p ^= NIBBLE_LOW(hexid[i]);
51 return nexwatch_parity_swap(p);
54 /// NETWATCH checksum
55 /// @param magic = 0xBE Quadrakey, 0x88 Nexkey
56 /// @param id = descrambled id (printed card number)
57 /// @param parity = the parity based upon the scrambled raw id.
58 static uint8_t nexwatch_checksum(uint8_t magic, uint32_t id, uint8_t parity) {
59 uint8_t a = ((id >> 24) & 0xFF);
60 a -= ((id >> 16) & 0xFF);
61 a -= ((id >> 8) & 0xFF);
62 a -= (id & 0xFF);
63 a -= magic;
64 a -= (reflect8(parity) >> 4);
65 return reflect8(a);
68 // Scrambled id ( 88 bit cardnumber format)
69 // ref:: http://www.proxmark.org/forum/viewtopic.php?pid=14662#p14662
70 static int nexwatch_scamble(NexWatchScramble_t action, uint32_t *id, uint32_t *scambled) {
72 // 255 = Not used/Unknown other values are the bit offset in the ID/FC values
73 uint8_t hex_2_id [] = {
74 31, 27, 23, 19, 15, 11, 7, 3,
75 30, 26, 22, 18, 14, 10, 6, 2,
76 29, 25, 21, 17, 13, 9, 5, 1,
77 28, 24, 20, 16, 12, 8, 4, 0
80 switch (action) {
81 case DESCRAMBLE: {
82 *id = 0;
83 for (uint8_t idx = 0; idx < 32; idx++) {
85 if (hex_2_id[idx] == 255)
86 continue;
88 bool bit_state = (*scambled >> hex_2_id[idx]) & 1;
89 *id |= (bit_state << (31 - idx));
91 break;
93 case SCRAMBLE: {
94 *scambled = 0;
95 for (uint8_t idx = 0; idx < 32; idx++) {
97 if (hex_2_id[idx] == 255)
98 continue;
100 bool bit_state = (*id >> idx) & 1;
101 *scambled |= (bit_state << (31 - hex_2_id[idx]));
103 break;
105 default:
106 break;
108 return PM3_SUCCESS;
111 int demodNexWatch(bool verbose) {
112 (void) verbose; // unused so far
113 if (PSKDemod(0, 0, 100, false) != PM3_SUCCESS) {
114 PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal");
115 return PM3_ESOFT;
117 bool invert = false;
118 size_t size = DemodBufferLen;
119 int idx = detectNexWatch(DemodBuffer, &size, &invert);
120 if (idx < 0) {
121 if (idx == -1)
122 PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch not enough samples");
123 // else if (idx == -2)
124 // PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch only noise found");
125 // else if (idx == -3)
126 // PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch problem during PSK demod");
127 else if (idx == -4)
128 PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch preamble not found");
129 // else if (idx == -5)
130 // PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch size not correct: %d", size);
131 else
132 PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch error %d", idx);
134 return PM3_ESOFT;
137 // skip the 4 first bits from the nexwatch preamble identification (we use 4 extra zeros..)
138 idx += 4;
140 setDemodBuff(DemodBuffer, size, idx);
141 setClockGrid(g_DemodClock, g_DemodStartIdx + (idx * g_DemodClock));
143 if (invert) {
144 PrintAndLogEx(INFO, "Inverted the demodulated data");
145 for (size_t i = 0; i < size; i++)
146 DemodBuffer[i] ^= 1;
149 //got a good demod
150 uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
151 uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
152 uint32_t raw3 = bytebits_to_byte(DemodBuffer + 32 + 32, 32);
154 // get rawid
155 uint32_t rawid = 0;
156 for (uint8_t k = 0; k < 4; k++) {
157 for (uint8_t m = 0; m < 8; m++) {
158 rawid = (rawid << 1) | DemodBuffer[m + k + (m * 4)];
162 // descrambled id
163 uint32_t cn = 0;
164 uint32_t scambled = bytebits_to_byte(DemodBuffer + 8 + 32, 32);
165 nexwatch_scamble(DESCRAMBLE, &cn, &scambled);
167 uint8_t mode = bytebits_to_byte(DemodBuffer + 72, 4);
168 uint8_t parity = bytebits_to_byte(DemodBuffer + 76, 4);
169 uint8_t chk = bytebits_to_byte(DemodBuffer + 80, 8);
171 // parity check
172 // from 32b hex id, 4b mode
173 uint8_t hex[5] = {0};
174 for (uint8_t i = 0; i < 5; i++) {
175 hex[i] = bytebits_to_byte(DemodBuffer + 8 + 32 + (i * 8), 8);
177 // mode is only 4 bits.
178 hex[4] &= 0xf0;
179 uint8_t calc_parity = nexwatch_parity(hex);
181 // Checksum
182 typedef struct {
183 uint8_t magic;
184 char desc[13];
185 uint8_t chk;
186 } nexwatch_magic_t;
187 nexwatch_magic_t items[] = {
188 {0xBE, "Quadrakey", 0},
189 {0x88, "Nexkey", 0},
190 {0x86, "Honeywell", 0}
193 uint8_t m_idx;
194 for (m_idx = 0; m_idx < ARRAYLEN(items); m_idx++) {
196 items[m_idx].chk = nexwatch_checksum(items[m_idx].magic, cn, calc_parity);
197 if (items[m_idx].chk == chk) {
198 break;
202 // output
203 PrintAndLogEx(SUCCESS, " NexWatch raw id : " _YELLOW_("0x%08"PRIx32), rawid);
205 if (m_idx < ARRAYLEN(items)) {
206 PrintAndLogEx(SUCCESS, " fingerprint : " _GREEN_("%s"), items[m_idx].desc);
208 PrintAndLogEx(SUCCESS, " 88bit id : " _YELLOW_("%"PRIu32) " (" _YELLOW_("0x%08"PRIx32)")", cn, cn);
209 PrintAndLogEx(SUCCESS, " mode : %x", mode);
211 if (parity == calc_parity) {
212 PrintAndLogEx(DEBUG, " parity : %s (0x%X)", _GREEN_("ok"), parity);
213 } else {
214 PrintAndLogEx(DEBUG, " parity : %s (0x%X != 0x%X)", _RED_("fail"), parity, calc_parity);
217 PrintAndLogEx(DEBUG, " checksum : %s (0x%02X)", (m_idx < ARRAYLEN(items)) ? _GREEN_("ok") : _RED_("fail"), chk);
219 PrintAndLogEx(INFO, " Raw : " _YELLOW_("%08"PRIX32"%08"PRIX32"%08"PRIX32), raw1, raw2, raw3);
220 return PM3_SUCCESS;
223 static int CmdNexWatchDemod(const char *Cmd) {
224 CLIParserContext *ctx;
225 CLIParserInit(&ctx, "lf nexwatch demod",
226 "Try to find Nexwatch preamble, if found decode / descramble data",
227 "lf nexwatch demod"
230 void *argtable[] = {
231 arg_param_begin,
232 arg_param_end
234 CLIExecWithReturn(ctx, Cmd, argtable, true);
235 CLIParserFree(ctx);
236 return demodNexWatch(true);
239 static int CmdNexWatchReader(const char *Cmd) {
240 CLIParserContext *ctx;
241 CLIParserInit(&ctx, "lf nexwatch reader",
242 "read a Nexwatch tag",
243 "lf nexwatch reader -@ -> continuous reader mode"
246 void *argtable[] = {
247 arg_param_begin,
248 arg_lit0("@", NULL, "optional - continuous reader mode"),
249 arg_param_end
251 CLIExecWithReturn(ctx, Cmd, argtable, true);
252 bool cm = arg_get_lit(ctx, 1);
253 CLIParserFree(ctx);
255 if (cm) {
256 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
259 do {
260 lf_read(false, 20000);
261 demodNexWatch(!cm);
262 } while (cm && !kbd_enter_pressed());
263 return PM3_SUCCESS;
266 static int CmdNexWatchClone(const char *Cmd) {
267 CLIParserContext *ctx;
268 CLIParserInit(&ctx, "lf nexwatch clone",
269 "clone a Nexwatch tag to a T55x7, Q5/T5555 or EM4305/4469 tag.\n"
270 "You can use raw hex values or create a credential based on id, mode\n"
271 "and type of credential (Nexkey / Quadrakey / Russian)",
272 "lf nexwatch clone --raw 5600000000213C9F8F150C00\n"
273 "lf nexwatch clone --cn 521512301 -m 1 --nc -> Nexkey credential\n"
274 "lf nexwatch clone --cn 521512301 -m 1 --qc -> Quadrakey credential\n"
275 "lf nexwatch clone --cn 521512301 -m 1 --hc -> Honeywell credential\n"
278 void *argtable[] = {
279 arg_param_begin,
280 arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
281 arg_u64_0(NULL, "cn", "<dec>", "card id"),
282 arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
283 arg_lit0(NULL, "nc", "Nexkey credential"),
284 arg_lit0(NULL, "qc", "Quadrakey credential"),
285 arg_lit0(NULL, "hc", "Honeywell credential"),
286 arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
287 arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
288 arg_param_end
290 CLIExecWithReturn(ctx, Cmd, argtable, false);
292 int raw_len = 0;
293 // skip first block, 3*4 = 12 bytes left
294 uint8_t raw[12] = {0x56, 0};
295 CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
297 uint32_t cn = arg_get_u32_def(ctx, 2, -1);
298 uint32_t mode = arg_get_u32_def(ctx, 3, -1);
299 bool use_nexkey = arg_get_lit(ctx, 4);
300 bool use_quadrakey = arg_get_lit(ctx, 5);
301 bool use_unk = arg_get_lit(ctx, 6);
302 bool q5 = arg_get_lit(ctx, 7);
303 bool em = arg_get_lit(ctx, 8);
304 CLIParserFree(ctx);
306 if (use_nexkey && use_quadrakey) {
307 PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
308 return PM3_EINVARG;
311 if (q5 && em) {
312 PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
313 return PM3_EINVARG;
316 // 56000000 00213C9F 8F150C00
317 bool use_raw = (raw_len != 0);
319 if (use_raw && cn != -1) {
320 PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
321 return PM3_EINVARG;
324 if (cn != -1) {
325 uint32_t scrambled;
326 nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
327 num_to_bytes(scrambled, 4, raw + 5);
330 if (mode != -1) {
331 if (mode > 15) {
332 mode = 1;
334 mode &= 0x0F;
335 raw[9] |= (mode << 4);
338 uint8_t magic = 0xBE;
339 if (use_nexkey)
340 magic = 0x88;
342 if (use_quadrakey)
343 magic = 0xBE;
345 if (use_unk)
346 magic = 0x86;
348 uint32_t blocks[4];
350 //Nexwatch - compat mode, PSK, data rate 40, 3 data blocks
351 blocks[0] = T55x7_MODULATION_PSK1 | T55x7_BITRATE_RF_32 | 3 << T55x7_MAXBLOCK_SHIFT;
352 char cardtype[16] = {"T55x7"};
353 // Q5
354 if (q5) {
355 blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
356 snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
359 // EM4305
360 if (em) {
361 blocks[0] = EM4305_NEXWATCH_CONFIG_BLOCK;
362 snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
365 if (use_raw == false) {
366 uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
367 raw[9] |= parity;
368 raw[10] |= nexwatch_checksum(magic, cn, parity);
371 for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) {
372 blocks[i] = bytes_to_num(raw + ((i - 1) * 4), sizeof(uint32_t));
375 PrintAndLogEx(INFO, "Preparing to clone NexWatch to " _YELLOW_("%s") " raw " _YELLOW_("%s"), cardtype, sprint_hex_inrow(raw, sizeof(raw)));
376 print_blocks(blocks, ARRAYLEN(blocks));
378 int res;
379 if (em) {
380 res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
381 } else {
382 res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
384 PrintAndLogEx(SUCCESS, "Done");
385 PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch reader`") " to verify");
386 return res;
389 static int CmdNexWatchSim(const char *Cmd) {
391 CLIParserContext *ctx;
392 CLIParserInit(&ctx, "lf nexwatch sim",
393 "Enables simulation of secura card with specified card number.\n"
394 "Simulation runs until the button is pressed or another USB command is issued.\n"
395 "You can use raw hex values or create a credential based on id, mode\n"
396 "and type of credential (Nexkey/Quadrakey)",
397 "lf nexwatch sim --raw 5600000000213C9F8F150C00\n"
398 "lf nexwatch sim --cn 521512301 -m 1 --nc -> Nexkey credential\n"
399 "lf nexwatch sim --cn 521512301 -m 1 --qc -> Quadrakey credential\n"
400 "lf nexwatch sim --cn 521512301 -m 1 --hc -> Honeywell credential\n"
403 void *argtable[] = {
404 arg_param_begin,
405 arg_str0("r", "raw", "<hex>", "raw hex data. 12 bytes"),
406 arg_u64_0(NULL, "cn", "<dec>", "card id"),
407 arg_u64_0("m", "mode", "<dec>", "mode (decimal) (0-15, defaults to 1)"),
408 arg_lit0(NULL, "nc", "Nexkey credential"),
409 arg_lit0(NULL, "qc", "Quadrakey credential"),
410 arg_lit0(NULL, "hc", "Honeywell credential"),
411 arg_param_end
413 CLIExecWithReturn(ctx, Cmd, argtable, false);
415 int raw_len = 0;
416 // skip first block, 3*4 = 12 bytes left
417 uint8_t raw[12] = {0x56, 0};
418 CLIGetHexWithReturn(ctx, 1, raw, &raw_len);
420 uint32_t cn = arg_get_u32_def(ctx, 2, -1);
421 uint32_t mode = arg_get_u32_def(ctx, 3, -1);
422 bool use_nexkey = arg_get_lit(ctx, 4);
423 bool use_quadrakey = arg_get_lit(ctx, 5);
424 bool use_unk = arg_get_lit(ctx, 6);
425 CLIParserFree(ctx);
427 if (use_nexkey && use_quadrakey) {
428 PrintAndLogEx(FAILED, "Can't specify both Nexkey and Quadrakey at the same time");
429 return PM3_EINVARG;
432 bool use_raw = (raw_len != 0);
434 if (use_raw && cn != -1) {
435 PrintAndLogEx(FAILED, "Can't specify both Raw and Card id at the same time");
436 return PM3_EINVARG;
439 if (cn != -1) {
440 uint32_t scrambled;
441 nexwatch_scamble(SCRAMBLE, &cn, &scrambled);
442 num_to_bytes(scrambled, 4, raw + 5);
445 if (mode != -1) {
446 if (mode > 15) {
447 mode = 1;
449 mode &= 0x0F;
450 raw[9] |= (mode << 4);
453 uint8_t magic = 0xBE;
454 if (use_nexkey)
455 magic = 0x88;
457 if (use_quadrakey)
458 magic = 0xBE;
460 if (use_unk)
461 magic = 0x86;
463 if (use_raw == false) {
464 uint8_t parity = nexwatch_parity(raw + 5) & 0xF;
465 raw[9] |= parity;
466 raw[10] |= nexwatch_checksum(magic, cn, parity);
469 uint8_t bs[96];
470 memset(bs, 0, sizeof(bs));
472 // hex to bits. (3 * 32 == 96)
473 for (size_t i = 0; i < 3; i++) {
474 uint32_t tmp = bytes_to_num(raw + (i * sizeof(uint32_t)), sizeof(uint32_t));
475 num_to_bytebits(tmp, sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8));
478 PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw " _YELLOW_("%s"), sprint_hex_inrow(raw, sizeof(raw)));
480 lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs));
481 payload->carrier = 2;
482 payload->invert = 0;
483 payload->clock = 32;
484 memcpy(payload->data, bs, sizeof(bs));
486 clearCommandBuffer();
487 SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs));
488 free(payload);
490 PacketResponseNG resp;
491 WaitForResponse(CMD_LF_PSK_SIMULATE, &resp);
493 PrintAndLogEx(INFO, "Done");
494 if (resp.status != PM3_EOPABORTED)
495 return resp.status;
497 return PM3_SUCCESS;
500 static command_t CommandTable[] = {
501 {"help", CmdHelp, AlwaysAvailable, "This help"},
502 {"demod", CmdNexWatchDemod, AlwaysAvailable, "demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"},
503 {"reader", CmdNexWatchReader, IfPm3Lf, "attempt to read and extract tag data"},
504 {"clone", CmdNexWatchClone, IfPm3Lf, "clone NexWatch tag to T55x7"},
505 {"sim", CmdNexWatchSim, IfPm3Lf, "simulate NexWatch tag"},
506 {NULL, NULL, NULL, NULL}
509 static int CmdHelp(const char *Cmd) {
510 (void)Cmd; // Cmd is not used so far
511 CmdsHelp(CommandTable);
512 return PM3_SUCCESS;
515 int CmdLFNEXWATCH(const char *Cmd) {
516 clearCommandBuffer();
517 return CmdsParse(CommandTable, Cmd);
520 int detectNexWatch(uint8_t *dest, size_t *size, bool *invert) {
522 uint8_t preamble[28] = {0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
523 // sanity check.
524 if (*size < 96) return -1;
526 size_t startIdx = 0;
528 if (!preambleSearch(DemodBuffer, preamble, sizeof(preamble), size, &startIdx)) {
529 // if didn't find preamble try again inverting
530 uint8_t preamble_i[28] = {1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
531 if (!preambleSearch(DemodBuffer, preamble_i, sizeof(preamble_i), size, &startIdx)) return -4;
532 *invert ^= 1;
535 // size tests?
536 return (int) startIdx;