fix one too small
[RRG-proxmark3.git] / client / src / cmdlfnoralsy.c
blob562cca539e71b59c6b98f497b046d831bf8355cb
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
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.
8 //
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 Noralsy tag commands
17 // ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown)
18 //-----------------------------------------------------------------------------
19 #include "cmdlfnoralsy.h"
20 #include <string.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #include "commonutil.h" // ARRAYLEN
24 #include "cmdparser.h" // command_t
25 #include "comms.h"
26 #include "ui.h"
27 #include "cmddata.h"
28 #include "cmdlf.h"
29 #include "protocols.h" // for T55xx config register definitions
30 #include "lfdemod.h" // parityTest
31 #include "cmdlft55xx.h" // verifywrite
32 #include "cmdlfem4x05.h" //
33 #include "cliparser.h"
35 static int CmdHelp(const char *Cmd);
37 static uint8_t noralsy_chksum(uint8_t *bits, uint8_t len) {
38 uint8_t sum = 0;
39 for (uint8_t i = 0; i < len; i += 4)
40 sum ^= bytebits_to_byte(bits + i, 4);
41 return sum & 0x0F ;
44 //see ASKDemod for what args are accepted
45 int demodNoralsy(bool verbose) {
46 (void) verbose; // unused so far
47 //ASK / Manchester
48 bool st = true;
49 if (ASKDemod_ext(32, 0, 0, 0, false, false, false, 1, &st) != PM3_SUCCESS) {
50 if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: ASK/Manchester Demod failed");
51 return PM3_ESOFT;
53 if (!st) {
54 if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: sequence terminator not found");
55 return PM3_ESOFT;
58 size_t size = g_DemodBufferLen;
59 int ans = detectNoralsy(g_DemodBuffer, &size);
60 if (ans < 0) {
61 if (g_debugMode) {
62 if (ans == -1)
63 PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: too few bits found");
64 else if (ans == -2)
65 PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: preamble not found");
66 else if (ans == -3)
67 PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: Size not correct: %zu", size);
68 else
69 PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: ans: %d", ans);
71 return PM3_ESOFT;
73 setDemodBuff(g_DemodBuffer, 96, ans);
74 setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
76 //got a good demod
77 uint32_t raw1 = bytebits_to_byte(g_DemodBuffer, 32);
78 uint32_t raw2 = bytebits_to_byte(g_DemodBuffer + 32, 32);
79 uint32_t raw3 = bytebits_to_byte(g_DemodBuffer + 64, 32);
81 uint32_t cardid = ((raw2 & 0xFFF00000) >> 20) << 16;
82 cardid |= (raw2 & 0xFF) << 8;
83 cardid |= ((raw3 & 0xFF000000) >> 24);
84 cardid = BCD2DEC(cardid);
86 uint16_t year = (raw2 & 0x000ff000) >> 12;
87 year = BCD2DEC(year);
88 year += (year > 60) ? 1900 : 2000;
90 // calc checksums
91 uint8_t calc1 = noralsy_chksum(g_DemodBuffer + 32, 40);
92 uint8_t calc2 = noralsy_chksum(g_DemodBuffer, 76);
93 uint8_t chk1 = 0, chk2 = 0;
94 chk1 = bytebits_to_byte(g_DemodBuffer + 72, 4);
95 chk2 = bytebits_to_byte(g_DemodBuffer + 76, 4);
96 // test checksums
97 if (chk1 != calc1) {
98 if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: checksum 1 failed %x - %x\n", chk1, calc1);
99 return PM3_ESOFT;
101 if (chk2 != calc2) {
102 if (g_debugMode) PrintAndLogEx(DEBUG, "DEBUG: Error - Noralsy: checksum 2 failed %x - %x\n", chk2, calc2);
103 return PM3_ESOFT;
106 PrintAndLogEx(SUCCESS, "Noralsy - Card: " _GREEN_("%u")", Year: " _GREEN_("%u") ", Raw: %08X%08X%08X", cardid, year, raw1, raw2, raw3);
107 if (raw1 != 0xBB0214FF) {
108 PrintAndLogEx(WARNING, "Unknown bits set in first block! Expected 0xBB0214FF, Found: 0x%08X", raw1);
109 PrintAndLogEx(WARNING, "Please post this output in forum to further research on this format");
111 return PM3_SUCCESS;
114 static int CmdNoralsyDemod(const char *Cmd) {
115 CLIParserContext *ctx;
116 CLIParserInit(&ctx, "lf noralsy demod",
117 "Try to find Noralsy preamble, if found decode / descramble data",
118 "lf noralsy demod"
121 void *argtable[] = {
122 arg_param_begin,
123 arg_param_end
125 CLIExecWithReturn(ctx, Cmd, argtable, true);
126 CLIParserFree(ctx);
127 return demodNoralsy(true);
130 static int CmdNoralsyReader(const char *Cmd) {
131 CLIParserContext *ctx;
132 CLIParserInit(&ctx, "lf noralsy reader",
133 "read a Noralsy tag",
134 "lf noralsy reader -@ -> continuous reader mode"
137 void *argtable[] = {
138 arg_param_begin,
139 arg_lit0("@", NULL, "optional - continuous reader mode"),
140 arg_param_end
142 CLIExecWithReturn(ctx, Cmd, argtable, true);
143 bool cm = arg_get_lit(ctx, 1);
144 CLIParserFree(ctx);
146 if (cm) {
147 PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
150 do {
151 lf_read(false, 8000);
152 demodNoralsy(!cm);
153 } while (cm && !kbd_enter_pressed());
154 return PM3_SUCCESS;
157 static int CmdNoralsyClone(const char *Cmd) {
158 CLIParserContext *ctx;
159 CLIParserInit(&ctx, "lf noralsy clone",
160 "clone a Noralsy tag to a T55x7, Q5/T5555 or EM4305/4469 tag.",
161 "lf noralsy clone --cn 112233 -> encode for T55x7 tag\n"
162 "lf noralsy clone --cn 112233 --q5 -> encode for Q5/T5555 tag\n"
163 "lf noralsy clone --cn 112233 --em -> encode for EM4305/4469"
166 void *argtable[] = {
167 arg_param_begin,
168 arg_u64_1(NULL, "cn", "<dec>", "Noralsy card ID"),
169 arg_u64_0("y", "year", "<dec>", "tag allocation year"),
170 arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
171 arg_lit0(NULL, "em", "optional - specify writing to EM4305/4469 tag"),
172 arg_param_end
174 CLIExecWithReturn(ctx, Cmd, argtable, false);
176 uint32_t id = arg_get_u32_def(ctx, 1, 0);
177 uint16_t year = arg_get_u32_def(ctx, 2, 2000);
178 bool q5 = arg_get_lit(ctx, 3);
179 bool em = arg_get_lit(ctx, 4);
180 CLIParserFree(ctx);
182 if (q5 && em) {
183 PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
184 return PM3_EINVARG;
187 uint32_t blocks[4] = {T55x7_MODULATION_MANCHESTER | T55x7_BITRATE_RF_32 | T55x7_ST_TERMINATOR | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0};
188 char cardtype[16] = {"T55x7"};
189 //Q5
190 if (q5) {
191 blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
192 snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
195 // EM4305
196 if (em) {
197 blocks[0] = EM4305_NORALSY_CONFIG_BLOCK;
198 snprintf(cardtype, sizeof(cardtype), "EM4305/4469");
201 uint8_t *bits = calloc(96, sizeof(uint8_t));
202 if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) {
203 PrintAndLogEx(ERR, "Error with tag bitstream generation.");
204 free(bits);
205 return PM3_ESOFT;
208 blocks[1] = bytebits_to_byte(bits, 32);
209 blocks[2] = bytebits_to_byte(bits + 32, 32);
210 blocks[3] = bytebits_to_byte(bits + 64, 32);
212 free(bits);
214 PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with Card id: " _GREEN_("%u"), cardtype, id);
215 print_blocks(blocks, ARRAYLEN(blocks));
217 int res;
218 if (em) {
219 res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
220 } else {
221 res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
223 PrintAndLogEx(SUCCESS, "Done");
224 PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy reader`") " to verify");
225 return res;
228 static int CmdNoralsySim(const char *Cmd) {
230 CLIParserContext *ctx;
231 CLIParserInit(&ctx, "lf noralsy sim",
232 "Enables simulation of Noralsy card with specified card number.\n"
233 "Simulation runs until the button is pressed or another USB command is issued.\n",
234 "lf noralsy sim --cn 1337\n"
235 "lf noralsy sim --cn 1337 --year 2010"
238 void *argtable[] = {
239 arg_param_begin,
240 arg_u64_1(NULL, "cn", "<dec>", "Noralsy card ID"),
241 arg_u64_0("y", "year", "<dec>", "tag allocation year"),
242 arg_param_end
244 CLIExecWithReturn(ctx, Cmd, argtable, false);
245 uint32_t id = arg_get_u32_def(ctx, 1, 0);
246 uint16_t year = arg_get_u32_def(ctx, 2, 2000);
247 CLIParserFree(ctx);
249 uint8_t bs[96];
250 memset(bs, 0, sizeof(bs));
252 if (getnoralsyBits(id, year, bs) != PM3_SUCCESS) {
253 PrintAndLogEx(ERR, "Error with tag bitstream generation.");
254 return PM3_ESOFT;
257 PrintAndLogEx(SUCCESS, "Simulating Noralsy - CardId: " _YELLOW_("%u") " year " _YELLOW_("%u"), id, year);
259 lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs));
260 payload->encoding = 1;
261 payload->invert = 0;
262 payload->separator = 1;
263 payload->clock = 32;
264 memcpy(payload->data, bs, sizeof(bs));
266 clearCommandBuffer();
267 SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs));
268 free(payload);
270 PacketResponseNG resp;
271 WaitForResponse(CMD_LF_ASK_SIMULATE, &resp);
273 PrintAndLogEx(INFO, "Done!");
274 if (resp.status != PM3_EOPABORTED) {
275 return resp.status;
277 return PM3_SUCCESS;
280 static command_t CommandTable[] = {
281 {"help", CmdHelp, AlwaysAvailable, "This help"},
282 {"demod", CmdNoralsyDemod, AlwaysAvailable, "demodulate an Noralsy tag from the GraphBuffer"},
283 {"reader", CmdNoralsyReader, IfPm3Lf, "attempt to read and extract tag data"},
284 {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7, Q5/T5555 or EM4305/4469"},
285 {"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"},
286 {NULL, NULL, NULL, NULL}
289 static int CmdHelp(const char *Cmd) {
290 (void)Cmd; // Cmd is not used so far
291 CmdsHelp(CommandTable);
292 return PM3_SUCCESS;
295 int CmdLFNoralsy(const char *Cmd) {
296 clearCommandBuffer();
297 return CmdsParse(CommandTable, Cmd);
300 int getnoralsyBits(uint32_t id, uint16_t year, uint8_t *bits) {
301 //preamp
302 num_to_bytebits(0xBB0214FF, 32, bits); // --> Have seen 0xBB0214FF / 0xBB0314FF UNKNOWN
304 //convert ID into BCD-format
305 id = DEC2BCD(id);
306 year = DEC2BCD(year);
307 year &= 0xFF;
309 uint16_t sub1 = (id & 0xFFF0000) >> 16;
310 uint8_t sub2 = (id & 0x000FF00) >> 8;
311 uint8_t sub3 = (id & 0x00000FF);
313 num_to_bytebits(sub1, 12, bits + 32);
314 num_to_bytebits(year, 8, bits + 44);
315 num_to_bytebits(0, 4, bits + 52); // --> UNKNOWN. Flag?
317 num_to_bytebits(sub2, 8, bits + 56);
318 num_to_bytebits(sub3, 8, bits + 64);
320 //chksum byte
321 uint8_t chksum = noralsy_chksum(bits + 32, 40);
322 num_to_bytebits(chksum, 4, bits + 72);
323 chksum = noralsy_chksum(bits, 76);
324 num_to_bytebits(chksum, 4, bits + 76);
325 return PM3_SUCCESS;
328 // find Noralsy preamble in already demoded data
329 int detectNoralsy(uint8_t *dest, size_t *size) {
330 if (*size < 96) return -1; //make sure buffer has data
331 size_t startIdx = 0;
332 uint8_t preamble[] = {1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0};
333 if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
334 return -2; //preamble not found
335 if (*size != 96) return -3; //wrong demoded size
336 //return start position
337 return (int)startIdx;
341 * 2520116 | BB0214FF2529900116360000 | 10111011 00000011 00010100 11111111 00100101 00101001 10010000 00000001 00010110 00110110 00000000 00000000
342 * aaa*aaaaiiiYY*iiiicc---- **** iiiiiiii iiiiYYYY YYYY**** iiiiiiii iiiiiiii cccccccc
344 * a = fixed value BB0*14FF
345 * i = printed id, BCD-format
346 * Y = year
347 * c = checksum
348 * * = unknown