]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdlfem4x.c
move new functions to utilities area
[proxmark3-svn] / client / cmdlfem4x.c
CommitLineData
a553f267 1//-----------------------------------------------------------------------------
2// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
3//
4// This code is licensed to you under the terms of the GNU GPL, version 2 or,
5// at your option, any later version. See the LICENSE.txt file for the text of
6// the license.
7//-----------------------------------------------------------------------------
8// Low frequency EM4x commands
9//-----------------------------------------------------------------------------
10
7fe9b0b7 11#include <stdio.h>
9e13f875 12#include <string.h>
ec564290 13#include <inttypes.h>
902cb3c0 14#include "proxmark3.h"
7fe9b0b7 15#include "ui.h"
3fe4ff4f 16#include "util.h"
7fe9b0b7 17#include "graph.h"
18#include "cmdparser.h"
19#include "cmddata.h"
20#include "cmdlf.h"
7666f460 21#include "cmdmain.h"
7fe9b0b7 22#include "cmdlfem4x.h"
23f0a7d8 23#include "lfdemod.h"
6ac4cb27 24
c3bfb9c7 25char *global_em410xId;
7fe9b0b7 26
27static int CmdHelp(const char *Cmd);
28
66707a3b 29int CmdEMdemodASK(const char *Cmd)
30{
3fe4ff4f 31 char cmdp = param_getchar(Cmd, 0);
cc15a118 32 int findone = (cmdp == '1') ? 1 : 0;
23f0a7d8 33 UsbCommand c={CMD_EM410X_DEMOD};
34 c.arg[0]=findone;
35 SendCommand(&c);
36 return 0;
66707a3b 37}
38
7fe9b0b7 39/* Read the ID of an EM410x tag.
40 * Format:
41 * 1111 1111 1 <-- standard non-repeatable header
42 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
43 * ....
44 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
45 * 0 <-- stop bit, end of tag
46 */
47int CmdEM410xRead(const char *Cmd)
48{
23f0a7d8 49 uint32_t hi=0;
50 uint64_t lo=0;
51
fef74fdc 52 if(!AskEm410xDemod("", &hi, &lo, false)) return 0;
23f0a7d8 53 PrintAndLog("EM410x pattern found: ");
54 printEM410x(hi, lo);
55 if (hi){
56 PrintAndLog ("EM410x XL pattern found");
57 return 0;
58 }
59 char id[12] = {0x00};
38d618ba 60 sprintf(id, "%010"PRIx64,lo);
23f0a7d8 61
62 global_em410xId = id;
63 return 1;
7fe9b0b7 64}
65
c8518913 66int usage_lf_em410x_sim(void) {
67 PrintAndLog("Simulating EM410x tag");
68 PrintAndLog("");
69 PrintAndLog("Usage: lf em 410xsim [h] <uid> <clock>");
70 PrintAndLog("Options:");
71 PrintAndLog(" h - this help");
72 PrintAndLog(" uid - uid (10 HEX symbols)");
73 PrintAndLog(" clock - clock (32|64) (optional)");
74 PrintAndLog("samples:");
75 PrintAndLog(" lf em 410xsim 0F0368568B");
76 PrintAndLog(" lf em 410xsim 0F0368568B 32");
77 return 0;
78}
79
13d77ef9 80// emulate an EM410X tag
7fe9b0b7 81int CmdEM410xSim(const char *Cmd)
82{
3fe4ff4f 83 int i, n, j, binary[4], parity[4];
84
85 char cmdp = param_getchar(Cmd, 0);
86 uint8_t uid[5] = {0x00};
87
c8518913 88 if (cmdp == 'h' || cmdp == 'H') return usage_lf_em410x_sim();
daa4fbae 89 /* clock is 64 in EM410x tags */
415274a7 90 uint8_t clock = 64;
3fe4ff4f 91
92 if (param_gethex(Cmd, 0, uid, 10)) {
93 PrintAndLog("UID must include 10 HEX symbols");
94 return 0;
95 }
415274a7 96 param_getdec(Cmd,1, &clock);
daa4fbae 97
98 PrintAndLog("Starting simulating UID %02X%02X%02X%02X%02X clock: %d", uid[0],uid[1],uid[2],uid[3],uid[4],clock);
3fe4ff4f 99 PrintAndLog("Press pm3-button to about simulation");
7fe9b0b7 100
23f0a7d8 101
102 /* clear our graph */
103 ClearGraph(0);
104
105 /* write 9 start bits */
106 for (i = 0; i < 9; i++)
107 AppendGraph(0, clock, 1);
108
109 /* for each hex char */
110 parity[0] = parity[1] = parity[2] = parity[3] = 0;
111 for (i = 0; i < 10; i++)
112 {
113 /* read each hex char */
114 sscanf(&Cmd[i], "%1x", &n);
115 for (j = 3; j >= 0; j--, n/= 2)
116 binary[j] = n % 2;
117
118 /* append each bit */
119 AppendGraph(0, clock, binary[0]);
120 AppendGraph(0, clock, binary[1]);
121 AppendGraph(0, clock, binary[2]);
122 AppendGraph(0, clock, binary[3]);
123
124 /* append parity bit */
125 AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
126
127 /* keep track of column parity */
128 parity[0] ^= binary[0];
129 parity[1] ^= binary[1];
130 parity[2] ^= binary[2];
131 parity[3] ^= binary[3];
132 }
133
134 /* parity columns */
135 AppendGraph(0, clock, parity[0]);
136 AppendGraph(0, clock, parity[1]);
137 AppendGraph(0, clock, parity[2]);
138 AppendGraph(0, clock, parity[3]);
139
140 /* stop bit */
141 AppendGraph(1, clock, 0);
3fe4ff4f 142
23f0a7d8 143 CmdLFSim("0"); //240 start_gap.
144 return 0;
7fe9b0b7 145}
146
3fe4ff4f 147/* Function is equivalent of lf read + data samples + em410xread
148 * looped until an EM410x tag is detected
149 *
150 * Why is CmdSamples("16000")?
151 * TBD: Auto-grow sample size based on detected sample rate. IE: If the
152 * rate gets lower, then grow the number of samples
153 * Changed by martin, 4000 x 4 = 16000,
154 * see http://www.proxmark.org/forum/viewtopic.php?pid=7235#p7235
3fe4ff4f 155*/
7fe9b0b7 156int CmdEM410xWatch(const char *Cmd)
157{
3fe4ff4f 158 do {
159 if (ukbhit()) {
160 printf("\naborted via keyboard!\n");
161 break;
162 }
163
1fbf8956 164 CmdLFRead("s");
2767fc02 165 getSamples("8201",true); //capture enough to get 2 complete preambles (4096*2+9)
13d77ef9 166 } while (!CmdEM410xRead(""));
167
3fe4ff4f 168 return 0;
7fe9b0b7 169}
170
23f0a7d8 171//currently only supports manchester modulations
c3bfb9c7 172int CmdEM410xWatchnSpoof(const char *Cmd)
173{
174 CmdEM410xWatch(Cmd);
1fbf8956 175 PrintAndLog("# Replaying captured ID: %s",global_em410xId);
176 CmdLFaskSim("");
177 return 0;
c3bfb9c7 178}
179
6e984446 180int CmdEM410xWrite(const char *Cmd)
181{
182 uint64_t id = 0xFFFFFFFFFFFFFFFF; // invalid id value
183 int card = 0xFF; // invalid card value
184 unsigned int clock = 0; // invalid clock value
185
2b11c7c7 186 sscanf(Cmd, "%" SCNx64 " %d %d", &id, &card, &clock);
6e984446 187
188 // Check ID
189 if (id == 0xFFFFFFFFFFFFFFFF) {
190 PrintAndLog("Error! ID is required.\n");
191 return 0;
192 }
193 if (id >= 0x10000000000) {
194 PrintAndLog("Error! Given EM410x ID is longer than 40 bits.\n");
195 return 0;
196 }
197
198 // Check Card
199 if (card == 0xFF) {
200 PrintAndLog("Error! Card type required.\n");
201 return 0;
202 }
203 if (card < 0) {
204 PrintAndLog("Error! Bad card type selected.\n");
205 return 0;
206 }
207
208 // Check Clock
76346455 209 // Default: 64
210 if (clock == 0)
211 clock = 64;
212
213 // Allowed clock rates: 16, 32, 40 and 64
214 if ((clock != 16) && (clock != 32) && (clock != 64) && (clock != 40)) {
215 PrintAndLog("Error! Clock rate %d not valid. Supported clock rates are 16, 32, 40 and 64.\n", clock);
6e984446 216 return 0;
217 }
218
219 if (card == 1) {
220 PrintAndLog("Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", "T55x7", id, clock);
221 // NOTE: We really should pass the clock in as a separate argument, but to
222 // provide for backwards-compatibility for older firmware, and to avoid
223 // having to add another argument to CMD_EM410X_WRITE_TAG, we just store
224 // the clock rate in bits 8-15 of the card value
76346455 225 card = (card & 0xFF) | ((clock << 8) & 0xFF00);
226 } else if (card == 0) {
6e984446 227 PrintAndLog("Writing %s tag with UID 0x%010" PRIx64, "T5555", id, clock);
76346455 228 card = (card & 0xFF) | ((clock << 8) & 0xFF00);
229 } else {
6e984446 230 PrintAndLog("Error! Bad card type selected.\n");
231 return 0;
232 }
233
234 UsbCommand c = {CMD_EM410X_WRITE_TAG, {card, (uint32_t)(id >> 32), (uint32_t)id}};
235 SendCommand(&c);
236
237 return 0;
238}
239
4c6ccc2b 240//**************** Start of EM4x50 Code ************************
23f0a7d8 241bool EM_EndParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
242{
243 if (rows*cols>size) return false;
244 uint8_t colP=0;
cc15a118 245 //assume last col is a parity and do not test
23f0a7d8 246 for (uint8_t colNum = 0; colNum < cols-1; colNum++) {
247 for (uint8_t rowNum = 0; rowNum < rows; rowNum++) {
248 colP ^= BitStream[(rowNum*cols)+colNum];
249 }
250 if (colP != pType) return false;
251 }
252 return true;
253}
254
255bool EM_ByteParityTest(uint8_t *BitStream, size_t size, uint8_t rows, uint8_t cols, uint8_t pType)
256{
257 if (rows*cols>size) return false;
258 uint8_t rowP=0;
259 //assume last row is a parity row and do not test
260 for (uint8_t rowNum = 0; rowNum < rows-1; rowNum++) {
261 for (uint8_t colNum = 0; colNum < cols; colNum++) {
262 rowP ^= BitStream[(rowNum*cols)+colNum];
263 }
264 if (rowP != pType) return false;
265 }
266 return true;
267}
268
269uint32_t OutputEM4x50_Block(uint8_t *BitStream, size_t size, bool verbose, bool pTest)
270{
271 if (size<45) return 0;
272 uint32_t code = bytebits_to_byte(BitStream,8);
273 code = code<<8 | bytebits_to_byte(BitStream+9,8);
274 code = code<<8 | bytebits_to_byte(BitStream+18,8);
275 code = code<<8 | bytebits_to_byte(BitStream+27,8);
276 if (verbose || g_debugMode){
277 for (uint8_t i = 0; i<5; i++){
cc15a118 278 if (i == 4) PrintAndLog(""); //parity byte spacer
23f0a7d8 279 PrintAndLog("%d%d%d%d%d%d%d%d %d -> 0x%02x",
280 BitStream[i*9],
281 BitStream[i*9+1],
282 BitStream[i*9+2],
283 BitStream[i*9+3],
284 BitStream[i*9+4],
285 BitStream[i*9+5],
286 BitStream[i*9+6],
287 BitStream[i*9+7],
288 BitStream[i*9+8],
289 bytebits_to_byte(BitStream+i*9,8)
290 );
291 }
292 if (pTest)
293 PrintAndLog("Parity Passed");
294 else
295 PrintAndLog("Parity Failed");
296 }
23f0a7d8 297 return code;
298}
7666f460 299/* Read the transmitted data of an EM4x50 tag from the graphbuffer
7fe9b0b7 300 * Format:
301 *
302 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
303 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
304 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
305 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
306 * CCCCCCCC <- column parity bits
307 * 0 <- stop bit
308 * LW <- Listen Window
309 *
310 * This pattern repeats for every block of data being transmitted.
311 * Transmission starts with two Listen Windows (LW - a modulated
312 * pattern of 320 cycles each (32/32/128/64/64)).
313 *
314 * Note that this data may or may not be the UID. It is whatever data
315 * is stored in the blocks defined in the control word First and Last
316 * Word Read values. UID is stored in block 32.
317 */
cc15a118 318 //completed by Marshmellow
23f0a7d8 319int EM4x50Read(const char *Cmd, bool verbose)
320{
cc15a118 321 uint8_t fndClk[] = {8,16,32,40,50,64,128};
23f0a7d8 322 int clk = 0;
323 int invert = 0;
23f0a7d8 324 int tol = 0;
325 int i, j, startblock, skip, block, start, end, low, high, minClk;
cc15a118 326 bool complete = false;
23f0a7d8 327 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
23f0a7d8 328 uint32_t Code[6];
329 char tmp[6];
23f0a7d8 330 char tmp2[20];
49bbc60a 331 int phaseoff;
cc15a118 332 high = low = 0;
23f0a7d8 333 memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
cc15a118 334
335 // get user entry if any
336 sscanf(Cmd, "%i %i", &clk, &invert);
337
338 // save GraphBuffer - to restore it later
339 save_restoreGB(1);
340
23f0a7d8 341 // first get high and low values
cc15a118 342 for (i = 0; i < GraphTraceLen; i++) {
23f0a7d8 343 if (GraphBuffer[i] > high)
344 high = GraphBuffer[i];
345 else if (GraphBuffer[i] < low)
346 low = GraphBuffer[i];
347 }
348
cc15a118 349 i = 0;
350 j = 0;
351 minClk = 255;
352 // get to first full low to prime loop and skip incomplete first pulse
353 while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
354 ++i;
355 while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
356 ++i;
357 skip = i;
358
359 // populate tmpbuff buffer with pulse lengths
360 while (i < GraphTraceLen) {
23f0a7d8 361 // measure from low to low
cc15a118 362 while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
23f0a7d8 363 ++i;
364 start= i;
cc15a118 365 while ((GraphBuffer[i] < high) && (i < GraphTraceLen))
23f0a7d8 366 ++i;
cc15a118 367 while ((GraphBuffer[i] > low) && (i < GraphTraceLen))
23f0a7d8 368 ++i;
369 if (j>=(MAX_GRAPH_TRACE_LEN/64)) {
370 break;
371 }
372 tmpbuff[j++]= i - start;
cc15a118 373 if (i-start < minClk && i < GraphTraceLen) {
374 minClk = i - start;
375 }
23f0a7d8 376 }
377 // set clock
cc15a118 378 if (!clk) {
23f0a7d8 379 for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
380 tol = fndClk[clkCnt]/8;
cc15a118 381 if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) {
23f0a7d8 382 clk=fndClk[clkCnt];
383 break;
384 }
385 }
cc15a118 386 if (!clk) return 0;
6e984446 387 } else tol = clk/8;
23f0a7d8 388
389 // look for data start - should be 2 pairs of LW (pulses of clk*3,clk*2)
cc15a118 390 start = -1;
391 for (i= 0; i < j - 4 ; ++i) {
23f0a7d8 392 skip += tmpbuff[i];
cc15a118 393 if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
394 if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
395 if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
396 if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
23f0a7d8 397 {
398 start= i + 4;
399 break;
400 }
401 }
cc15a118 402 startblock = i + 4;
23f0a7d8 403
404 // skip over the remainder of LW
49bbc60a 405 skip += tmpbuff[i+1] + tmpbuff[i+2] + clk;
406 if (tmpbuff[i+3]>clk)
407 phaseoff = tmpbuff[i+3]-clk;
408 else
409 phaseoff = 0;
23f0a7d8 410 // now do it again to find the end
411 end = skip;
cc15a118 412 for (i += 3; i < j - 4 ; ++i) {
23f0a7d8 413 end += tmpbuff[i];
cc15a118 414 if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol) //3 clocks
415 if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol) //2 clocks
416 if (tmpbuff[i+2] >= clk*3-tol && tmpbuff[i+2] <= clk*3+tol) //3 clocks
417 if (tmpbuff[i+3] >= clk-tol) //1.5 to 2 clocks - depends on bit following
23f0a7d8 418 {
419 complete= true;
420 break;
421 }
422 }
423 end = i;
424 // report back
425 if (verbose || g_debugMode) {
426 if (start >= 0) {
cc15a118 427 PrintAndLog("\nNote: one block = 50 bits (32 data, 12 parity, 6 marker)");
23f0a7d8 428 } else {
cc15a118 429 PrintAndLog("No data found!, clock tried:%d",clk);
23f0a7d8 430 PrintAndLog("Try again with more samples.");
cc15a118 431 PrintAndLog(" or after a 'data askedge' command to clean up the read");
23f0a7d8 432 return 0;
433 }
23f0a7d8 434 } else if (start < 0) return 0;
cc15a118 435 start = skip;
23f0a7d8 436 snprintf(tmp2, sizeof(tmp2),"%d %d 1000 %d", clk, invert, clk*47);
437 // get rid of leading crap
cc15a118 438 snprintf(tmp, sizeof(tmp), "%i", skip);
23f0a7d8 439 CmdLtrim(tmp);
440 bool pTest;
cc15a118 441 bool AllPTest = true;
23f0a7d8 442 // now work through remaining buffer printing out data blocks
443 block = 0;
444 i = startblock;
cc15a118 445 while (block < 6) {
23f0a7d8 446 if (verbose || g_debugMode) PrintAndLog("\nBlock %i:", block);
447 skip = phaseoff;
448
449 // look for LW before start of next block
cc15a118 450 for ( ; i < j - 4 ; ++i) {
23f0a7d8 451 skip += tmpbuff[i];
452 if (tmpbuff[i] >= clk*3-tol && tmpbuff[i] <= clk*3+tol)
453 if (tmpbuff[i+1] >= clk-tol)
454 break;
455 }
49bbc60a 456 if (i >= j-4) break; //next LW not found
23f0a7d8 457 skip += clk;
49bbc60a 458 if (tmpbuff[i+1]>clk)
459 phaseoff = tmpbuff[i+1]-clk;
460 else
461 phaseoff = 0;
23f0a7d8 462 i += 2;
fef74fdc 463 if (ASKDemod(tmp2, false, false, 1) < 1) {
cc15a118 464 save_restoreGB(0);
465 return 0;
466 }
23f0a7d8 467 //set DemodBufferLen to just one block
468 DemodBufferLen = skip/clk;
469 //test parities
470 pTest = EM_ByteParityTest(DemodBuffer,DemodBufferLen,5,9,0);
471 pTest &= EM_EndParityTest(DemodBuffer,DemodBufferLen,5,9,0);
472 AllPTest &= pTest;
473 //get output
cc15a118 474 Code[block] = OutputEM4x50_Block(DemodBuffer,DemodBufferLen,verbose, pTest);
475 if (g_debugMode) PrintAndLog("\nskipping %d samples, bits:%d", skip, skip/clk);
23f0a7d8 476 //skip to start of next block
477 snprintf(tmp,sizeof(tmp),"%i",skip);
478 CmdLtrim(tmp);
479 block++;
cc15a118 480 if (i >= end) break; //in case chip doesn't output 6 blocks
23f0a7d8 481 }
482 //print full code:
483 if (verbose || g_debugMode || AllPTest){
49bbc60a 484 if (!complete) {
485 PrintAndLog("*** Warning!");
486 PrintAndLog("Partial data - no end found!");
487 PrintAndLog("Try again with more samples.");
488 }
cc15a118 489 PrintAndLog("Found data at sample: %i - using clock: %i", start, clk);
490 end = block;
491 for (block=0; block < end; block++){
23f0a7d8 492 PrintAndLog("Block %d: %08x",block,Code[block]);
493 }
49bbc60a 494 if (AllPTest) {
23f0a7d8 495 PrintAndLog("Parities Passed");
49bbc60a 496 } else {
23f0a7d8 497 PrintAndLog("Parities Failed");
cc15a118 498 PrintAndLog("Try cleaning the read samples with 'data askedge'");
49bbc60a 499 }
23f0a7d8 500 }
501
502 //restore GraphBuffer
503 save_restoreGB(0);
504 return (int)AllPTest;
505}
506
7fe9b0b7 507int CmdEM4x50Read(const char *Cmd)
508{
23f0a7d8 509 return EM4x50Read(Cmd, true);
7fe9b0b7 510}
511
4c6ccc2b 512//**************** Start of EM4x05/EM4x69 Code ************************
7666f460 513int usage_lf_em_read(void) {
514 PrintAndLog("Read EM4x05/EM4x69. Tag must be on antenna. ");
515 PrintAndLog("");
e39a92bb 516 PrintAndLog("Usage: lf em 4x05readword [h] <address> <pwd>");
7666f460 517 PrintAndLog("Options:");
518 PrintAndLog(" h - this help");
519 PrintAndLog(" address - memory address to read. (0-15)");
520 PrintAndLog(" pwd - password (hex) (optional)");
521 PrintAndLog("samples:");
e39a92bb 522 PrintAndLog(" lf em 4x05readword 1");
523 PrintAndLog(" lf em 4x05readword 1 11223344");
7666f460 524 return 0;
525}
6f1a5978 526
4c6ccc2b 527// for command responses from em4x05 or em4x69
528// download samples from device and copy them to the Graphbuffer
529bool downloadSamplesEM() {
530 // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
531 uint8_t got[6000];
532 GetFromBigBuf(got, sizeof(got), 0);
533 if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) {
534 PrintAndLog("command execution time out");
535 return false;
6f1a5978 536 }
4c6ccc2b 537 setGraphBuf(got, sizeof(got));
538 return true;
e39a92bb 539}
540
541bool EM4x05testDemodReadData(uint32_t *word, bool readCmd) {
34ff8985 542 // em4x05/em4x69 command response preamble is 00001010
4c6ccc2b 543 // skip first two 0 bits as they might have been missed in the demod
544 uint8_t preamble[] = {0,0,1,0,1,0};
e39a92bb 545 size_t startIdx = 0;
e39a92bb 546
34ff8985 547 // set size to 20 to only test first 14 positions for the preamble or less if not a read command
548 size_t size = (readCmd) ? 20 : 11;
549 // sanity check
550 size = (size > DemodBufferLen) ? DemodBufferLen : size;
551 // test preamble
e88096ba 552 if ( !preambleSearchEx(DemodBuffer, preamble, sizeof(preamble), &size, &startIdx, true) ) {
e39a92bb 553 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305 preamble not found :: %d", startIdx);
554 return false;
555 }
4c6ccc2b 556 // if this is a readword command, get the read bytes and test the parities
e39a92bb 557 if (readCmd) {
4c6ccc2b 558 if (!EM_EndParityTest(DemodBuffer + startIdx + sizeof(preamble), 45, 5, 9, 0)) {
559 if (g_debugMode) PrintAndLog("DEBUG: Error - End Parity check failed");
560 return false;
561 }
e88096ba 562 // test for even parity bits and remove them. (leave out the end row of parities so 36 bits)
563 if ( removeParity(DemodBuffer, startIdx + sizeof(preamble),9,0,36) == 0 ) {
e39a92bb 564 if (g_debugMode) PrintAndLog("DEBUG: Error - Parity not detected");
565 return false;
566 }
567
e88096ba 568 setDemodBuf(DemodBuffer, 32, 0);
4c6ccc2b 569 *word = bytebits_to_byteLSBF(DemodBuffer, 32);
e39a92bb 570 }
571 return true;
6f1a5978 572}
573
59f726c9 574// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE
575// should cover 90% of known used configs
576// the rest will need to be manually demoded for now...
e39a92bb 577int demodEM4x05resp(uint32_t *word, bool readCmd) {
6f1a5978 578 int ans = 0;
6f1a5978 579
580 // test for FSK wave (easiest to 99% ID)
34212c66 581 if (GetFskClock("", false, false)) {
6f1a5978 582 //valid fsk clocks found
583 ans = FSKrawDemod("0 0", false);
584 if (!ans) {
4c6ccc2b 585 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: FSK Demod failed, ans: %d", ans);
6f1a5978 586 } else {
e39a92bb 587 if (EM4x05testDemodReadData(word, readCmd)) {
588 return 1;
6f1a5978 589 }
590 }
591 }
59f726c9 592 // PSK clocks should be easy to detect ( but difficult to demod a non-repeating pattern... )
34212c66 593 ans = GetPskClock("", false, false);
6980d66b 594 if (ans>0) {
595 //try psk1
34212c66 596 ans = PSKDemod("0 0 6", false);
59f726c9 597 if (!ans) {
4c6ccc2b 598 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
59f726c9 599 } else {
e39a92bb 600 if (EM4x05testDemodReadData(word, readCmd)) {
601 return 1;
6980d66b 602 } else {
603 //try psk2
604 psk1TOpsk2(DemodBuffer, DemodBufferLen);
605 if (EM4x05testDemodReadData(word, readCmd)) {
606 return 1;
607 }
608 }
609 //try psk1 inverted
34212c66 610 ans = PSKDemod("0 1 6", false);
6980d66b 611 if (!ans) {
4c6ccc2b 612 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: PSK1 Demod failed, ans: %d", ans);
6980d66b 613 } else {
614 if (EM4x05testDemodReadData(word, readCmd)) {
615 return 1;
616 } else {
617 //try psk2
618 psk1TOpsk2(DemodBuffer, DemodBufferLen);
619 if (EM4x05testDemodReadData(word, readCmd)) {
620 return 1;
621 }
622 }
59f726c9 623 }
624 }
6f1a5978 625 }
626
4c6ccc2b 627 // manchester is more common than biphase... try first
6980d66b 628 bool stcheck = false;
629 // try manchester - NOTE: ST only applies to T55x7 tags.
630 ans = ASKDemod_ext("0,0,1", false, false, 1, &stcheck);
631 if (!ans) {
4c6ccc2b 632 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/Manchester Demod failed, ans: %d", ans);
6980d66b 633 } else {
634 if (EM4x05testDemodReadData(word, readCmd)) {
635 return 1;
6f1a5978 636 }
637 }
638
6980d66b 639 //try biphase
34212c66 640 ans = ASKbiphaseDemod("0 0 1", false);
6980d66b 641 if (!ans) {
4c6ccc2b 642 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
6980d66b 643 } else {
644 if (EM4x05testDemodReadData(word, readCmd)) {
645 return 1;
6f1a5978 646 }
647 }
648
6980d66b 649 //try diphase (differential biphase or inverted)
34212c66 650 ans = ASKbiphaseDemod("0 1 1", false);
6980d66b 651 if (!ans) {
4c6ccc2b 652 if (g_debugMode) PrintAndLog("DEBUG: Error - EM4305: ASK/biphase Demod failed, ans: %d", ans);
6980d66b 653 } else {
654 if (EM4x05testDemodReadData(word, readCmd)) {
655 return 1;
59f726c9 656 }
6980d66b 657 }
658
6f1a5978 659 return -1;
660}
661
fa1e00cf 662int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordData) {
7666f460 663 UsbCommand c = {CMD_EM4X_READ_WORD, {addr, pwd, usePwd}};
664 clearCommandBuffer();
23f0a7d8 665 SendCommand(&c);
7666f460 666 UsbCommand resp;
667 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)){
668 PrintAndLog("Command timed out");
669 return -1;
670 }
4c6ccc2b 671 if ( !downloadSamplesEM() ) {
6f1a5978 672 return -1;
7666f460 673 }
6f1a5978 674 int testLen = (GraphTraceLen < 1000) ? GraphTraceLen : 1000;
675 if (graphJustNoise(GraphBuffer, testLen)) {
676 PrintAndLog("no tag not found");
677 return -1;
678 }
59f726c9 679 //attempt demod:
fa1e00cf 680 return demodEM4x05resp(wordData, true);
681}
682
683int EM4x05ReadWord(uint8_t addr, uint32_t pwd, bool usePwd) {
e39a92bb 684 uint32_t wordData = 0;
fa1e00cf 685 int success = EM4x05ReadWord_ext(addr, pwd, usePwd, &wordData);
4c6ccc2b 686 if (success == 1)
33a1fe96 687 PrintAndLog("%s Address %02d | %08X", (addr>13) ? "Lock":" Got",addr,wordData);
4c6ccc2b 688 else
fa1e00cf 689 PrintAndLog("Read Address %02d | failed",addr);
4c6ccc2b 690
e39a92bb 691 return success;
692}
693
694int CmdEM4x05ReadWord(const char *Cmd) {
695 uint8_t addr;
696 uint32_t pwd;
697 bool usePwd = false;
698 uint8_t ctmp = param_getchar(Cmd, 0);
699 if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_read();
700
701 addr = param_get8ex(Cmd, 0, 50, 10);
702 // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
703 pwd = param_get32ex(Cmd, 1, 1, 16);
704
705 if ( (addr > 15) ) {
706 PrintAndLog("Address must be between 0 and 15");
707 return 1;
708 }
4c6ccc2b 709 if ( pwd == 1 ) {
e39a92bb 710 PrintAndLog("Reading address %02u", addr);
4c6ccc2b 711 } else {
e39a92bb 712 usePwd = true;
713 PrintAndLog("Reading address %02u | password %08X", addr, pwd);
714 }
61500621 715
4c6ccc2b 716 return EM4x05ReadWord(addr, pwd, usePwd);
54a942b0 717}
718
e39a92bb 719int usage_lf_em_dump(void) {
720 PrintAndLog("Dump EM4x05/EM4x69. Tag must be on antenna. ");
721 PrintAndLog("");
722 PrintAndLog("Usage: lf em 4x05dump [h] <pwd>");
723 PrintAndLog("Options:");
724 PrintAndLog(" h - this help");
725 PrintAndLog(" pwd - password (hex) (optional)");
726 PrintAndLog("samples:");
727 PrintAndLog(" lf em 4x05dump");
728 PrintAndLog(" lf em 4x05dump 11223344");
729 return 0;
730}
731
732int CmdEM4x05dump(const char *Cmd) {
733 uint8_t addr = 0;
734 uint32_t pwd;
735 bool usePwd = false;
736 uint8_t ctmp = param_getchar(Cmd, 0);
737 if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
738
739 // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
740 pwd = param_get32ex(Cmd, 0, 1, 16);
741
742 if ( pwd != 1 ) {
743 usePwd = true;
744 }
745 int success = 1;
746 for (; addr < 16; addr++) {
747 if (addr == 2) {
748 if (usePwd) {
34212c66 749 PrintAndLog(" PWD Address %02u | %08X",addr,pwd);
e39a92bb 750 } else {
34212c66 751 PrintAndLog(" PWD Address 02 | cannot read");
e39a92bb 752 }
753 } else {
754 success &= EM4x05ReadWord(addr, pwd, usePwd);
755 }
756 }
757
758 return success;
759}
760
761
7666f460 762int usage_lf_em_write(void) {
763 PrintAndLog("Write EM4x05/EM4x69. Tag must be on antenna. ");
764 PrintAndLog("");
e39a92bb 765 PrintAndLog("Usage: lf em 4x05writeword [h] <address> <data> <pwd>");
7666f460 766 PrintAndLog("Options:");
767 PrintAndLog(" h - this help");
768 PrintAndLog(" address - memory address to write to. (0-15)");
769 PrintAndLog(" data - data to write (hex)");
770 PrintAndLog(" pwd - password (hex) (optional)");
771 PrintAndLog("samples:");
e39a92bb 772 PrintAndLog(" lf em 4x05writeword 1");
773 PrintAndLog(" lf em 4x05writeword 1 deadc0de 11223344");
7666f460 774 return 0;
775}
59f726c9 776
e39a92bb 777int CmdEM4x05WriteWord(const char *Cmd) {
7666f460 778 uint8_t ctmp = param_getchar(Cmd, 0);
779 if ( strlen(Cmd) == 0 || ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_write();
23f0a7d8 780
7666f460 781 bool usePwd = false;
782
e39a92bb 783 uint8_t addr = 16; // default to invalid address
784 uint32_t data = 0xFFFFFFFF; // default to blank data
785 uint32_t pwd = 0xFFFFFFFF; // default to blank password
23f0a7d8 786
e39a92bb 787 addr = param_get8ex(Cmd, 0, 16, 10);
788 data = param_get32ex(Cmd, 1, 0, 16);
789 pwd = param_get32ex(Cmd, 2, 1, 16);
7666f460 790
791
e39a92bb 792 if ( (addr > 15) ) {
7666f460 793 PrintAndLog("Address must be between 0 and 15");
23f0a7d8 794 return 1;
795 }
e39a92bb 796 if ( pwd == 1 )
7666f460 797 PrintAndLog("Writing address %d data %08X", addr, data);
798 else {
799 usePwd = true;
800 PrintAndLog("Writing address %d data %08X using password %08X", addr, data, pwd);
801 }
23f0a7d8 802
7666f460 803 uint16_t flag = (addr << 8 ) | usePwd;
23f0a7d8 804
7666f460 805 UsbCommand c = {CMD_EM4X_WRITE_WORD, {flag, data, pwd}};
806 clearCommandBuffer();
23f0a7d8 807 SendCommand(&c);
7666f460 808 UsbCommand resp;
e39a92bb 809 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){
7666f460 810 PrintAndLog("Error occurred, device did not respond during write operation.");
811 return -1;
812 }
4c6ccc2b 813 if ( !downloadSamplesEM() ) {
814 return -1;
7666f460 815 }
e39a92bb 816 //check response for 00001010 for write confirmation!
59f726c9 817 //attempt demod:
e39a92bb 818 uint32_t dummy = 0;
819 int result = demodEM4x05resp(&dummy,false);
59f726c9 820 if (result == 1) {
821 PrintAndLog("Write Verified");
34ff8985 822 } else {
823 PrintAndLog("Write could not be verified");
59f726c9 824 }
825 return result;
54a942b0 826}
827
0a85edf4 828void printEM4x05config(uint32_t wordData) {
829 uint16_t datarate = (((wordData & 0x3F)+1)*2);
830 uint8_t encoder = ((wordData >> 6) & 0xF);
831 char enc[14];
832 memset(enc,0,sizeof(enc));
833
834 uint8_t PSKcf = (wordData >> 10) & 0x3;
835 char cf[10];
836 memset(cf,0,sizeof(cf));
837 uint8_t delay = (wordData >> 12) & 0x3;
838 char cdelay[33];
839 memset(cdelay,0,sizeof(cdelay));
840 uint8_t LWR = (wordData >> 14) & 0xF; //last word read
841
842 switch (encoder) {
843 case 0: snprintf(enc,sizeof(enc),"NRZ"); break;
844 case 1: snprintf(enc,sizeof(enc),"Manchester"); break;
845 case 2: snprintf(enc,sizeof(enc),"Biphase"); break;
846 case 3: snprintf(enc,sizeof(enc),"Miller"); break;
847 case 4: snprintf(enc,sizeof(enc),"PSK1"); break;
848 case 5: snprintf(enc,sizeof(enc),"PSK2"); break;
849 case 6: snprintf(enc,sizeof(enc),"PSK3"); break;
850 case 7: snprintf(enc,sizeof(enc),"Unknown"); break;
851 case 8: snprintf(enc,sizeof(enc),"FSK1"); break;
852 case 9: snprintf(enc,sizeof(enc),"FSK2"); break;
853 default: snprintf(enc,sizeof(enc),"Unknown"); break;
854 }
855
856 switch (PSKcf) {
857 case 0: snprintf(cf,sizeof(cf),"RF/2"); break;
858 case 1: snprintf(cf,sizeof(cf),"RF/8"); break;
859 case 2: snprintf(cf,sizeof(cf),"RF/4"); break;
860 case 3: snprintf(cf,sizeof(cf),"unknown"); break;
861 }
862
863 switch (delay) {
864 case 0: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
865 case 1: snprintf(cdelay, sizeof(cdelay),"BP/8 or 1/8th bit period delay"); break;
866 case 2: snprintf(cdelay, sizeof(cdelay),"BP/4 or 1/4th bit period delay"); break;
867 case 3: snprintf(cdelay, sizeof(cdelay),"no delay"); break;
868 }
869 PrintAndLog("ConfigWord: %08X (Word 4)\n", wordData);
870 PrintAndLog("Config Breakdown:", wordData);
33a1fe96 871 PrintAndLog(" Data Rate: %02u | RF/%u", wordData & 0x3F, datarate);
0a85edf4 872 PrintAndLog(" Encoder: %u | %s", encoder, enc);
873 PrintAndLog(" PSK CF: %u | %s", PSKcf, cf);
874 PrintAndLog(" Delay: %u | %s", delay, cdelay);
33a1fe96 875 PrintAndLog(" LastWordR: %02u | Address of last word for default read", LWR);
0a85edf4 876 PrintAndLog(" ReadLogin: %u | Read Login is %s", (wordData & 0x40000)>>18, (wordData & 0x40000) ? "Required" : "Not Required");
877 PrintAndLog(" ReadHKL: %u | Read Housekeeping Words Login is %s", (wordData & 0x80000)>>19, (wordData & 0x80000) ? "Required" : "Not Required");
878 PrintAndLog("WriteLogin: %u | Write Login is %s", (wordData & 0x100000)>>20, (wordData & 0x100000) ? "Required" : "Not Required");
879 PrintAndLog(" WriteHKL: %u | Write Housekeeping Words Login is %s", (wordData & 0x200000)>>21, (wordData & 0x200000) ? "Required" : "Not Required");
880 PrintAndLog(" R.A.W.: %u | Read After Write is %s", (wordData & 0x400000)>>22, (wordData & 0x400000) ? "On" : "Off");
881 PrintAndLog(" Disable: %u | Disable Command is %s", (wordData & 0x800000)>>23, (wordData & 0x800000) ? "Accepted" : "Not Accepted");
882 PrintAndLog(" R.T.F.: %u | Reader Talk First is %s", (wordData & 0x1000000)>>24, (wordData & 0x1000000) ? "Enabled" : "Disabled");
883 PrintAndLog(" Pigeon: %u | Pigeon Mode is %s\n", (wordData & 0x4000000)>>26, (wordData & 0x4000000) ? "Enabled" : "Disabled");
884}
885
fa1e00cf 886void printEM4x05info(uint8_t chipType, uint8_t cap, uint16_t custCode, uint32_t serial) {
887 switch (chipType) {
0a85edf4 888 case 9: PrintAndLog("\n Chip Type: %u | EM4305", chipType); break;
889 case 4: PrintAndLog(" Chip Type: %u | Unknown", chipType); break;
890 case 2: PrintAndLog(" Chip Type: %u | EM4469", chipType); break;
fa1e00cf 891 //add more here when known
0a85edf4 892 default: PrintAndLog(" Chip Type: %u Unknown", chipType); break;
fa1e00cf 893 }
894
895 switch (cap) {
0a85edf4 896 case 3: PrintAndLog(" Cap Type: %u | 330pF",cap); break;
897 case 2: PrintAndLog(" Cap Type: %u | %spF",cap, (chipType==2)? "75":"210"); break;
898 case 1: PrintAndLog(" Cap Type: %u | 250pF",cap); break;
899 case 0: PrintAndLog(" Cap Type: %u | no resonant capacitor",cap); break;
900 default: PrintAndLog(" Cap Type: %u | unknown",cap); break;
fa1e00cf 901 }
902
0a85edf4 903 PrintAndLog(" Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default": "Unknown");
fa1e00cf 904 if (serial != 0) {
0a85edf4 905 PrintAndLog("\n Serial #: %08X\n", serial);
fa1e00cf 906 }
907}
908
34ff8985 909void printEM4x05ProtectionBits(uint32_t wordData) {
33a1fe96 910 for (uint8_t i = 0; i < 15; i++) {
911 PrintAndLog(" Word: %02u | %s", i, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
912 if (i==14) {
913 PrintAndLog(" Word: %02u | %s", i+1, (((1 << i) & wordData ) || i < 2) ? "Is Write Locked" : "Is Not Write Locked");
914 }
34ff8985 915 }
916}
917
fa1e00cf 918//quick test for EM4x05/EM4x69 tag
919bool EM4x05Block0Test(uint32_t *wordData) {
920 if (EM4x05ReadWord_ext(0,0,false,wordData) == 1) {
921 return true;
922 }
923 return false;
924}
925
926int CmdEM4x05info(const char *Cmd) {
927 //uint8_t addr = 0;
0a85edf4 928 uint32_t pwd;
fa1e00cf 929 uint32_t wordData = 0;
0a85edf4 930 bool usePwd = false;
fa1e00cf 931 uint8_t ctmp = param_getchar(Cmd, 0);
932 if ( ctmp == 'H' || ctmp == 'h' ) return usage_lf_em_dump();
933
934 // for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
0a85edf4 935 pwd = param_get32ex(Cmd, 0, 1, 16);
fa1e00cf 936
0a85edf4 937 if ( pwd != 1 ) {
938 usePwd = true;
939 }
fa1e00cf 940
0a85edf4 941 // read word 0 (chip info)
942 // block 0 can be read even without a password.
fa1e00cf 943 if ( !EM4x05Block0Test(&wordData) )
944 return -1;
945
946 uint8_t chipType = (wordData >> 1) & 0xF;
947 uint8_t cap = (wordData >> 5) & 3;
948 uint16_t custCode = (wordData >> 9) & 0x3FF;
949
0a85edf4 950 // read word 1 (serial #) doesn't need pwd
fa1e00cf 951 wordData = 0;
952 if (EM4x05ReadWord_ext(1, 0, false, &wordData) != 1) {
953 //failed, but continue anyway...
954 }
955 printEM4x05info(chipType, cap, custCode, wordData);
956
0a85edf4 957 // read word 4 (config block)
fa1e00cf 958 // needs password if one is set
0a85edf4 959 wordData = 0;
960 if ( EM4x05ReadWord_ext(4, pwd, usePwd, &wordData) != 1 ) {
961 //failed
962 return 0;
963 }
964 printEM4x05config(wordData);
34ff8985 965
966 // read word 14 and 15 to see which is being used for the protection bits
967 wordData = 0;
968 if ( EM4x05ReadWord_ext(14, pwd, usePwd, &wordData) != 1 ) {
969 //failed
970 return 0;
971 }
972 // if status bit says this is not the used protection word
973 if (!(wordData & 0x8000)) {
974 if ( EM4x05ReadWord_ext(15, pwd, usePwd, &wordData) != 1 ) {
975 //failed
976 return 0;
977 }
978 }
979 if (!(wordData & 0x8000)) {
980 //something went wrong
981 return 0;
982 }
983 printEM4x05ProtectionBits(wordData);
984
0a85edf4 985 return 1;
fa1e00cf 986}
987
988
2d4eae76 989static command_t CommandTable[] =
7fe9b0b7 990{
23f0a7d8 991 {"help", CmdHelp, 1, "This help"},
e39a92bb 992 {"410xdemod", CmdEMdemodASK, 0, "[findone] -- Extract ID from EM410x tag (option 0 for continuous loop, 1 for only 1 tag)"},
993 {"410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag in GraphBuffer"},
994 {"410xsim", CmdEM410xSim, 0, "<UID> [clock rate] -- Simulate EM410x tag"},
995 {"410xwatch", CmdEM410xWatch, 0, "['h'] -- Watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
996 {"410xspoof", CmdEM410xWatchnSpoof, 0, "['h'] --- Watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
997 {"410xwrite", CmdEM410xWrite, 0, "<UID> <'0' T5555> <'1' T55x7> [clock rate] -- Write EM410x UID to T5555(Q5) or T55x7 tag, optionally setting clock rate"},
fa1e00cf 998 {"4x05dump", CmdEM4x05dump, 0, "(pwd) -- Read EM4x05/EM4x69 all word data"},
999 {"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"},
1000 {"4x05readword", CmdEM4x05ReadWord, 0, "<Word> (pwd) -- Read EM4x05/EM4x69 word data"},
1001 {"4x05writeword", CmdEM4x05WriteWord, 0, "<Word> <data> (pwd) -- Write EM4x05/EM4x69 word data"},
e39a92bb 1002 {"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"},
23f0a7d8 1003 {NULL, NULL, 0, NULL}
7fe9b0b7 1004};
1005
1006int CmdLFEM4X(const char *Cmd)
1007{
23f0a7d8 1008 CmdsParse(CommandTable, Cmd);
1009 return 0;
7fe9b0b7 1010}
1011
1012int CmdHelp(const char *Cmd)
1013{
23f0a7d8 1014 CmdsHelp(CommandTable);
1015 return 0;
7fe9b0b7 1016}
Impressum, Datenschutz