]> git.zerfleddert.de Git - proxmark3-svn/blob - client/cmdlf.c
Added command to read PCF7931 125Khz LF tags. This is a beta version which needs...
[proxmark3-svn] / client / cmdlf.c
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 commands
9 //-----------------------------------------------------------------------------
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <limits.h>
15 #include "proxusb.h"
16 #include "data.h"
17 #include "graph.h"
18 #include "ui.h"
19 #include "cmdparser.h"
20 #include "cmdmain.h"
21 #include "cmddata.h"
22 #include "cmdlf.h"
23 #include "cmdlfhid.h"
24 #include "cmdlfti.h"
25 #include "cmdlfem4x.h"
26 #include "cmdlfhitag.h"
27 #include "cmdlft55xx.h"
28 #include "cmdlfpcf7931.h"
29
30 static int CmdHelp(const char *Cmd);
31
32 /* send a command before reading */
33 int CmdLFCommandRead(const char *Cmd)
34 {
35 static char dummy[3];
36
37 dummy[0]= ' ';
38
39 UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
40 sscanf(Cmd, "%i %i %i %s %s", &c.arg[0], &c.arg[1], &c.arg[2], (char *) &c.d.asBytes,(char *) &dummy+1);
41 // in case they specified 'h'
42 strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
43 SendCommand(&c);
44 return 0;
45 }
46
47 int CmdFlexdemod(const char *Cmd)
48 {
49 int i;
50 for (i = 0; i < GraphTraceLen; ++i) {
51 if (GraphBuffer[i] < 0) {
52 GraphBuffer[i] = -1;
53 } else {
54 GraphBuffer[i] = 1;
55 }
56 }
57
58 #define LONG_WAIT 100
59 int start;
60 for (start = 0; start < GraphTraceLen - LONG_WAIT; start++) {
61 int first = GraphBuffer[start];
62 for (i = start; i < start + LONG_WAIT; i++) {
63 if (GraphBuffer[i] != first) {
64 break;
65 }
66 }
67 if (i == (start + LONG_WAIT)) {
68 break;
69 }
70 }
71 if (start == GraphTraceLen - LONG_WAIT) {
72 PrintAndLog("nothing to wait for");
73 return 0;
74 }
75
76 GraphBuffer[start] = 2;
77 GraphBuffer[start+1] = -2;
78
79 uint8_t bits[64];
80
81 int bit;
82 i = start;
83 for (bit = 0; bit < 64; bit++) {
84 int j;
85 int sum = 0;
86 for (j = 0; j < 16; j++) {
87 sum += GraphBuffer[i++];
88 }
89 if (sum > 0) {
90 bits[bit] = 1;
91 } else {
92 bits[bit] = 0;
93 }
94 PrintAndLog("bit %d sum %d", bit, sum);
95 }
96
97 for (bit = 0; bit < 64; bit++) {
98 int j;
99 int sum = 0;
100 for (j = 0; j < 16; j++) {
101 sum += GraphBuffer[i++];
102 }
103 if (sum > 0 && bits[bit] != 1) {
104 PrintAndLog("oops1 at %d", bit);
105 }
106 if (sum < 0 && bits[bit] != 0) {
107 PrintAndLog("oops2 at %d", bit);
108 }
109 }
110
111 GraphTraceLen = 32*64;
112 i = 0;
113 int phase = 0;
114 for (bit = 0; bit < 64; bit++) {
115 if (bits[bit] == 0) {
116 phase = 0;
117 } else {
118 phase = 1;
119 }
120 int j;
121 for (j = 0; j < 32; j++) {
122 GraphBuffer[i++] = phase;
123 phase = !phase;
124 }
125 }
126
127 RepaintGraphWindow();
128 return 0;
129 }
130
131 int CmdIndalaDemod(const char *Cmd)
132 {
133 // Usage: recover 64bit UID by default, specify "224" as arg to recover a 224bit UID
134
135 int state = -1;
136 int count = 0;
137 int i, j;
138 // worst case with GraphTraceLen=64000 is < 4096
139 // under normal conditions it's < 2048
140 uint8_t rawbits[4096];
141 int rawbit = 0;
142 int worst = 0, worstPos = 0;
143 PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
144 for (i = 0; i < GraphTraceLen-1; i += 2) {
145 count += 1;
146 if ((GraphBuffer[i] > GraphBuffer[i + 1]) && (state != 1)) {
147 if (state == 0) {
148 for (j = 0; j < count - 8; j += 16) {
149 rawbits[rawbit++] = 0;
150 }
151 if ((abs(count - j)) > worst) {
152 worst = abs(count - j);
153 worstPos = i;
154 }
155 }
156 state = 1;
157 count = 0;
158 } else if ((GraphBuffer[i] < GraphBuffer[i + 1]) && (state != 0)) {
159 if (state == 1) {
160 for (j = 0; j < count - 8; j += 16) {
161 rawbits[rawbit++] = 1;
162 }
163 if ((abs(count - j)) > worst) {
164 worst = abs(count - j);
165 worstPos = i;
166 }
167 }
168 state = 0;
169 count = 0;
170 }
171 }
172 PrintAndLog("Recovered %d raw bits", rawbit);
173 PrintAndLog("worst metric (0=best..7=worst): %d at pos %d", worst, worstPos);
174
175 // Finding the start of a UID
176 int uidlen, long_wait;
177 if (strcmp(Cmd, "224") == 0) {
178 uidlen = 224;
179 long_wait = 30;
180 } else {
181 uidlen = 64;
182 long_wait = 29;
183 }
184 int start;
185 int first = 0;
186 for (start = 0; start <= rawbit - uidlen; start++) {
187 first = rawbits[start];
188 for (i = start; i < start + long_wait; i++) {
189 if (rawbits[i] != first) {
190 break;
191 }
192 }
193 if (i == (start + long_wait)) {
194 break;
195 }
196 }
197 if (start == rawbit - uidlen + 1) {
198 PrintAndLog("nothing to wait for");
199 return 0;
200 }
201
202 // Inverting signal if needed
203 if (first == 1) {
204 for (i = start; i < rawbit; i++) {
205 rawbits[i] = !rawbits[i];
206 }
207 }
208
209 // Dumping UID
210 uint8_t bits[224];
211 char showbits[225];
212 showbits[uidlen]='\0';
213 int bit;
214 i = start;
215 int times = 0;
216 if (uidlen > rawbit) {
217 PrintAndLog("Warning: not enough raw bits to get a full UID");
218 for (bit = 0; bit < rawbit; bit++) {
219 bits[bit] = rawbits[i++];
220 // As we cannot know the parity, let's use "." and "/"
221 showbits[bit] = '.' + bits[bit];
222 }
223 showbits[bit+1]='\0';
224 PrintAndLog("Partial UID=%s", showbits);
225 return 0;
226 } else {
227 for (bit = 0; bit < uidlen; bit++) {
228 bits[bit] = rawbits[i++];
229 showbits[bit] = '0' + bits[bit];
230 }
231 times = 1;
232 }
233
234 //convert UID to HEX
235 uint32_t uid1, uid2, uid3, uid4, uid5, uid6, uid7;
236 int idx;
237 uid1=0;
238 uid2=0;
239 if (uidlen==64){
240 for( idx=0; idx<64; idx++) {
241 if (showbits[idx] == '0') {
242 uid1=(uid1<<1)|(uid2>>31);
243 uid2=(uid2<<1)|0;
244 } else {
245 uid1=(uid1<<1)|(uid2>>31);
246 uid2=(uid2<<1)|1;
247 }
248 }
249 PrintAndLog("UID=%s (%x%08x)", showbits, uid1, uid2);
250 }
251 else {
252 uid3=0;
253 uid4=0;
254 uid5=0;
255 uid6=0;
256 uid7=0;
257 for( idx=0; idx<224; idx++) {
258 uid1=(uid1<<1)|(uid2>>31);
259 uid2=(uid2<<1)|(uid3>>31);
260 uid3=(uid3<<1)|(uid4>>31);
261 uid4=(uid4<<1)|(uid5>>31);
262 uid5=(uid5<<1)|(uid6>>31);
263 uid6=(uid6<<1)|(uid7>>31);
264 if (showbits[idx] == '0') uid7=(uid7<<1)|0;
265 else uid7=(uid7<<1)|1;
266 }
267 PrintAndLog("UID=%s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
268 }
269
270 // Checking UID against next occurences
271 for (; i + uidlen <= rawbit;) {
272 int failed = 0;
273 for (bit = 0; bit < uidlen; bit++) {
274 if (bits[bit] != rawbits[i++]) {
275 failed = 1;
276 break;
277 }
278 }
279 if (failed == 1) {
280 break;
281 }
282 times += 1;
283 }
284 PrintAndLog("Occurences: %d (expected %d)", times, (rawbit - start) / uidlen);
285
286 // Remodulating for tag cloning
287 GraphTraceLen = 32*uidlen;
288 i = 0;
289 int phase = 0;
290 for (bit = 0; bit < uidlen; bit++) {
291 if (bits[bit] == 0) {
292 phase = 0;
293 } else {
294 phase = 1;
295 }
296 int j;
297 for (j = 0; j < 32; j++) {
298 GraphBuffer[i++] = phase;
299 phase = !phase;
300 }
301 }
302
303 RepaintGraphWindow();
304 return 0;
305 }
306
307 int CmdIndalaClone(const char *Cmd)
308 {
309 unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7;
310 UsbCommand c;
311 uid1=0;
312 uid2=0;
313 uid3=0;
314 uid4=0;
315 uid5=0;
316 uid6=0;
317 uid7=0;
318 int n = 0, i = 0;
319
320 if (strchr(Cmd,'l') != 0) {
321 while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
322 uid1 = (uid1 << 4) | (uid2 >> 28);
323 uid2 = (uid2 << 4) | (uid3 >> 28);
324 uid3 = (uid3 << 4) | (uid4 >> 28);
325 uid4 = (uid4 << 4) | (uid5 >> 28);
326 uid5 = (uid5 << 4) | (uid6 >> 28);
327 uid6 = (uid6 << 4) | (uid7 >> 28);
328 uid7 = (uid7 << 4) | (n & 0xf);
329 }
330 PrintAndLog("Cloning 224bit tag with UID %x%08x%08x%08x%08x%08x%08x", uid1, uid2, uid3, uid4, uid5, uid6, uid7);
331 c.cmd = CMD_INDALA_CLONE_TAG_L;
332 c.d.asDwords[0] = uid1;
333 c.d.asDwords[1] = uid2;
334 c.d.asDwords[2] = uid3;
335 c.d.asDwords[3] = uid4;
336 c.d.asDwords[4] = uid5;
337 c.d.asDwords[5] = uid6;
338 c.d.asDwords[6] = uid7;
339 }
340 else
341 {
342 while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
343 uid1 = (uid1 << 4) | (uid2 >> 28);
344 uid2 = (uid2 << 4) | (n & 0xf);
345 }
346 PrintAndLog("Cloning 64bit tag with UID %x%08x", uid1, uid2);
347 c.cmd = CMD_INDALA_CLONE_TAG;
348 c.arg[0] = uid1;
349 c.arg[1] = uid2;
350 }
351
352 SendCommand(&c);
353 return 0;
354 }
355
356 int CmdLFRead(const char *Cmd)
357 {
358 UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K};
359 // 'h' means higher-low-frequency, 134 kHz
360 if(*Cmd == 'h') {
361 c.arg[0] = 1;
362 } else if (*Cmd == '\0') {
363 c.arg[0] = 0;
364 } else {
365 PrintAndLog("use 'read' or 'read h'");
366 return 0;
367 }
368 SendCommand(&c);
369 WaitForResponse(CMD_ACK);
370 return 0;
371 }
372
373 static void ChkBitstream(const char *str)
374 {
375 int i;
376
377 /* convert to bitstream if necessary */
378 for (i = 0; i < (int)(GraphTraceLen / 2); i++)
379 {
380 if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)
381 {
382 CmdBitstream(str);
383 break;
384 }
385 }
386 }
387
388 int CmdLFSim(const char *Cmd)
389 {
390 int i;
391 static int gap;
392
393 sscanf(Cmd, "%i", &gap);
394
395 /* convert to bitstream if necessary */
396 ChkBitstream(Cmd);
397
398 PrintAndLog("Sending data, please wait...");
399 for (i = 0; i < GraphTraceLen; i += 48) {
400 UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {i, 0, 0}};
401 int j;
402 for (j = 0; j < 48; j++) {
403 c.d.asBytes[j] = GraphBuffer[i+j];
404 }
405 SendCommand(&c);
406 WaitForResponse(CMD_ACK);
407 }
408
409 PrintAndLog("Starting simulator...");
410 UsbCommand c = {CMD_SIMULATE_TAG_125K, {GraphTraceLen, gap, 0}};
411 SendCommand(&c);
412 return 0;
413 }
414
415 int CmdLFSimBidir(const char *Cmd)
416 {
417 /* Set ADC to twice the carrier for a slight supersampling */
418 UsbCommand c = {CMD_LF_SIMULATE_BIDIR, {47, 384, 0}};
419 SendCommand(&c);
420 return 0;
421 }
422
423 /* simulate an LF Manchester encoded tag with specified bitstream, clock rate and inter-id gap */
424 int CmdLFSimManchester(const char *Cmd)
425 {
426 static int clock, gap;
427 static char data[1024], gapstring[8];
428
429 /* get settings/bits */
430 sscanf(Cmd, "%i %s %i", &clock, &data[0], &gap);
431
432 /* clear our graph */
433 ClearGraph(0);
434
435 /* fill it with our bitstream */
436 for (int i = 0; i < strlen(data) ; ++i)
437 AppendGraph(0, clock, data[i]- '0');
438
439 /* modulate */
440 CmdManchesterMod("");
441
442 /* show what we've done */
443 RepaintGraphWindow();
444
445 /* simulate */
446 sprintf(&gapstring[0], "%i", gap);
447 CmdLFSim(gapstring);
448 return 0;
449 }
450
451 int CmdVchDemod(const char *Cmd)
452 {
453 // Is this the entire sync pattern, or does this also include some
454 // data bits that happen to be the same everywhere? That would be
455 // lovely to know.
456 static const int SyncPattern[] = {
457 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
458 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
459 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
460 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
462 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
464 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
466 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
467 };
468
469 // So first, we correlate for the sync pattern, and mark that.
470 int bestCorrel = 0, bestPos = 0;
471 int i;
472 // It does us no good to find the sync pattern, with fewer than
473 // 2048 samples after it...
474 for (i = 0; i < (GraphTraceLen-2048); i++) {
475 int sum = 0;
476 int j;
477 for (j = 0; j < arraylen(SyncPattern); j++) {
478 sum += GraphBuffer[i+j]*SyncPattern[j];
479 }
480 if (sum > bestCorrel) {
481 bestCorrel = sum;
482 bestPos = i;
483 }
484 }
485 PrintAndLog("best sync at %d [metric %d]", bestPos, bestCorrel);
486
487 char bits[257];
488 bits[256] = '\0';
489
490 int worst = INT_MAX;
491 int worstPos = 0;
492
493 for (i = 0; i < 2048; i += 8) {
494 int sum = 0;
495 int j;
496 for (j = 0; j < 8; j++) {
497 sum += GraphBuffer[bestPos+i+j];
498 }
499 if (sum < 0) {
500 bits[i/8] = '.';
501 } else {
502 bits[i/8] = '1';
503 }
504 if(abs(sum) < worst) {
505 worst = abs(sum);
506 worstPos = i;
507 }
508 }
509 PrintAndLog("bits:");
510 PrintAndLog("%s", bits);
511 PrintAndLog("worst metric: %d at pos %d", worst, worstPos);
512
513 if (strcmp(Cmd, "clone")==0) {
514 GraphTraceLen = 0;
515 char *s;
516 for(s = bits; *s; s++) {
517 int j;
518 for(j = 0; j < 16; j++) {
519 GraphBuffer[GraphTraceLen++] = (*s == '1') ? 1 : 0;
520 }
521 }
522 RepaintGraphWindow();
523 }
524 return 0;
525 }
526
527 static command_t CommandTable[] =
528 {
529 {"help", CmdHelp, 1, "This help"},
530 {"cmdread", CmdLFCommandRead, 0, "<off period> <'0' period> <'1' period> <command> ['h'] -- Modulate LF reader field to send command before read (all periods in microseconds) (option 'h' for 134)"},
531 {"em4x", CmdLFEM4X, 1, "{ EM4X RFIDs... }"},
532 {"flexdemod", CmdFlexdemod, 1, "Demodulate samples for FlexPass"},
533 {"hid", CmdLFHID, 1, "{ HID RFIDs... }"},
534 {"indalademod", CmdIndalaDemod, 1, "['224'] -- Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"},
535 {"indalaclone", CmdIndalaClone, 1, "<UID> ['l']-- Clone Indala to T55x7 (tag must be in antenna)(UID in HEX)(option 'l' for 224 UID"},
536 {"read", CmdLFRead, 0, "['h'] -- Read 125/134 kHz LF ID-only tag (option 'h' for 134)"},
537 {"sim", CmdLFSim, 0, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"},
538 {"simbidir", CmdLFSimBidir, 0, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
539 {"simman", CmdLFSimManchester, 0, "<Clock> <Bitstream> [GAP] Simulate arbitrary Manchester LF tag"},
540 {"ti", CmdLFTI, 1, "{ TI RFIDs... }"},
541 {"hitag", CmdLFHitag, 1, "{ Hitag tags and transponders... }"},
542 {"vchdemod", CmdVchDemod, 1, "['clone'] -- Demodulate samples for VeriChip"},
543 {"t55xx", CmdLFT55XX, 1, "{ T55xx RFIDs... }"},
544 {"pcf7931", CmdLFPCF7931, 1, "{PCF7931 RFIDs...}"},
545 {NULL, NULL, 0, NULL}
546 };
547
548 int CmdLF(const char *Cmd)
549 {
550 CmdsParse(CommandTable, Cmd);
551 return 0;
552 }
553
554 int CmdHelp(const char *Cmd)
555 {
556 CmdsHelp(CommandTable);
557 return 0;
558 }
Impressum, Datenschutz