]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdlfem4x.c
Client cleanup and restructuring. Stage 1...
[proxmark3-svn] / client / cmdlfem4x.c
CommitLineData
7fe9b0b7 1#include <stdio.h>
2#include "proxusb.h"
3#include "ui.h"
4#include "graph.h"
5#include "cmdparser.h"
6#include "cmddata.h"
7#include "cmdlf.h"
8#include "cmdlfem4x.h"
9
10static int CmdHelp(const char *Cmd);
11
12/* Read the ID of an EM410x tag.
13 * Format:
14 * 1111 1111 1 <-- standard non-repeatable header
15 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
16 * ....
17 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
18 * 0 <-- stop bit, end of tag
19 */
20int CmdEM410xRead(const char *Cmd)
21{
22 int i, j, clock, header, rows, bit, hithigh, hitlow, first, bit2idx, high, low;
23 int parity[4];
24 char id[11];
25 int retested = 0;
26 int BitStream[MAX_GRAPH_TRACE_LEN];
27 high = low = 0;
28
29 /* Detect high and lows and clock */
30 for (i = 0; i < GraphTraceLen; i++)
31 {
32 if (GraphBuffer[i] > high)
33 high = GraphBuffer[i];
34 else if (GraphBuffer[i] < low)
35 low = GraphBuffer[i];
36 }
37
38 /* get clock */
39 clock = GetClock(Cmd, high, 0);
40
41 /* parity for our 4 columns */
42 parity[0] = parity[1] = parity[2] = parity[3] = 0;
43 header = rows = 0;
44
45 /* manchester demodulate */
46 bit = bit2idx = 0;
47 for (i = 0; i < (int)(GraphTraceLen / clock); i++)
48 {
49 hithigh = 0;
50 hitlow = 0;
51 first = 1;
52
53 /* Find out if we hit both high and low peaks */
54 for (j = 0; j < clock; j++)
55 {
56 if (GraphBuffer[(i * clock) + j] == high)
57 hithigh = 1;
58 else if (GraphBuffer[(i * clock) + j] == low)
59 hitlow = 1;
60
61 /* it doesn't count if it's the first part of our read
62 because it's really just trailing from the last sequence */
63 if (first && (hithigh || hitlow))
64 hithigh = hitlow = 0;
65 else
66 first = 0;
67
68 if (hithigh && hitlow)
69 break;
70 }
71
72 /* If we didn't hit both high and low peaks, we had a bit transition */
73 if (!hithigh || !hitlow)
74 bit ^= 1;
75
76 BitStream[bit2idx++] = bit;
77 }
78
79retest:
80 /* We go till 5 before the graph ends because we'll get that far below */
81 for (i = 1; i < bit2idx - 5; i++)
82 {
83 /* Step 2: We have our header but need our tag ID */
84 if (header == 9 && rows < 10)
85 {
86 /* Confirm parity is correct */
87 if ((BitStream[i] ^ BitStream[i+1] ^ BitStream[i+2] ^ BitStream[i+3]) == BitStream[i+4])
88 {
89 /* Read another byte! */
90 sprintf(id+rows, "%x", (8 * BitStream[i]) + (4 * BitStream[i+1]) + (2 * BitStream[i+2]) + (1 * BitStream[i+3]));
91 rows++;
92
93 /* Keep parity info */
94 parity[0] ^= BitStream[i];
95 parity[1] ^= BitStream[i+1];
96 parity[2] ^= BitStream[i+2];
97 parity[3] ^= BitStream[i+3];
98
99 /* Move 4 bits ahead */
100 i += 4;
101 }
102
103 /* Damn, something wrong! reset */
104 else
105 {
106 PrintAndLog("Thought we had a valid tag but failed at word %d (i=%d)", rows + 1, i);
107
108 /* Start back rows * 5 + 9 header bits, -1 to not start at same place */
109 i -= 9 + (5 * rows) - 5;
110
111 rows = header = 0;
112 }
113 }
114
115 /* Step 3: Got our 40 bits! confirm column parity */
116 else if (rows == 10)
117 {
118 /* We need to make sure our 4 bits of parity are correct and we have a stop bit */
119 if (BitStream[i] == parity[0] && BitStream[i+1] == parity[1] &&
120 BitStream[i+2] == parity[2] && BitStream[i+3] == parity[3] &&
121 BitStream[i+4] == 0)
122 {
123 /* Sweet! */
124 PrintAndLog("EM410x Tag ID: %s", id);
125
126 /* Stop any loops */
127 return 1;
128 }
129
130 /* Crap! Incorrect parity or no stop bit, start all over */
131 else
132 {
133 rows = header = 0;
134
135 /* Go back 59 bits (9 header bits + 10 rows at 4+1 parity) */
136 i -= 59;
137 }
138 }
139
140 /* Step 1: get our header */
141 else if (header < 9)
142 {
143 /* Need 9 consecutive 1's */
144 if (BitStream[i] == 1)
145 header++;
146
147 /* We don't have a header, not enough consecutive 1 bits */
148 else
149 header = 0;
150 }
151 }
152
153 /* if we've already retested after flipping bits, return */
154 if (retested++)
155 return 0;
156
157 /* if this didn't work, try flipping bits */
158 for (i = 0; i < bit2idx; i++)
159 BitStream[i] ^= 1;
160
161 goto retest;
162}
163
164/* emulate an EM410X tag
165 * Format:
166 * 1111 1111 1 <-- standard non-repeatable header
167 * XXXX [row parity bit] <-- 10 rows of 5 bits for our 40 bit tag ID
168 * ....
169 * CCCC <-- each bit here is parity for the 10 bits above in corresponding column
170 * 0 <-- stop bit, end of tag
171 */
172int CmdEM410xSim(const char *Cmd)
173{
174 int i, n, j, h, binary[4], parity[4];
175
176 /* clock is 64 in EM410x tags */
177 int clock = 64;
178
179 /* clear our graph */
180 ClearGraph(0);
181
182 /* write it out a few times */
183 for (h = 0; h < 4; h++)
184 {
185 /* write 9 start bits */
186 for (i = 0; i < 9; i++)
187 AppendGraph(0, clock, 1);
188
189 /* for each hex char */
190 parity[0] = parity[1] = parity[2] = parity[3] = 0;
191 for (i = 0; i < 10; i++)
192 {
193 /* read each hex char */
194 sscanf(&Cmd[i], "%1x", &n);
195 for (j = 3; j >= 0; j--, n/= 2)
196 binary[j] = n % 2;
197
198 /* append each bit */
199 AppendGraph(0, clock, binary[0]);
200 AppendGraph(0, clock, binary[1]);
201 AppendGraph(0, clock, binary[2]);
202 AppendGraph(0, clock, binary[3]);
203
204 /* append parity bit */
205 AppendGraph(0, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
206
207 /* keep track of column parity */
208 parity[0] ^= binary[0];
209 parity[1] ^= binary[1];
210 parity[2] ^= binary[2];
211 parity[3] ^= binary[3];
212 }
213
214 /* parity columns */
215 AppendGraph(0, clock, parity[0]);
216 AppendGraph(0, clock, parity[1]);
217 AppendGraph(0, clock, parity[2]);
218 AppendGraph(0, clock, parity[3]);
219
220 /* stop bit */
221 AppendGraph(0, clock, 0);
222 }
223
224 /* modulate that biatch */
225 CmdManchesterMod("");
226
227 /* booyah! */
228 RepaintGraphWindow();
229
230 CmdLFSim("");
231 return 0;
232}
233
234/* Function is equivalent of loread + losamples + em410xread
235 * looped until an EM410x tag is detected */
236int CmdEM410xWatch(const char *Cmd)
237{
238 char *zero = "";
239 char *twok = "2000";
240
241 int stop = 0;
242 do
243 {
244 CmdLFRead(zero);
245 CmdLFSamples(twok);
246 stop = CmdEM410xRead(zero);
247 } while (!stop);
248 return 0;
249}
250
251/* Read the transmitted data of an EM4x50 tag
252 * Format:
253 *
254 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
255 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
256 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
257 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
258 * CCCCCCCC <- column parity bits
259 * 0 <- stop bit
260 * LW <- Listen Window
261 *
262 * This pattern repeats for every block of data being transmitted.
263 * Transmission starts with two Listen Windows (LW - a modulated
264 * pattern of 320 cycles each (32/32/128/64/64)).
265 *
266 * Note that this data may or may not be the UID. It is whatever data
267 * is stored in the blocks defined in the control word First and Last
268 * Word Read values. UID is stored in block 32.
269 */
270int CmdEM4x50Read(const char *Cmd)
271{
272 int i, j, startblock, clock, skip, block, start, end, low, high;
273 bool complete= false;
274 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
275 char tmp[6];
276
277 high= low= 0;
278 clock= 64;
279
280 /* first get high and low values */
281 for (i = 0; i < GraphTraceLen; i++)
282 {
283 if (GraphBuffer[i] > high)
284 high = GraphBuffer[i];
285 else if (GraphBuffer[i] < low)
286 low = GraphBuffer[i];
287 }
288
289 /* populate a buffer with pulse lengths */
290 i= 0;
291 j= 0;
292 while (i < GraphTraceLen)
293 {
294 // measure from low to low
295 while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
296 ++i;
297 start= i;
298 while ((GraphBuffer[i] < high) && (i<GraphTraceLen))
299 ++i;
300 while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
301 ++i;
302 if (j>(MAX_GRAPH_TRACE_LEN/64)) {
303 break;
304 }
305 tmpbuff[j++]= i - start;
306 }
307
308 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
309 start= -1;
310 skip= 0;
311 for (i= 0; i < j - 4 ; ++i)
312 {
313 skip += tmpbuff[i];
314 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
315 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
316 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
317 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
318 {
319 start= i + 3;
320 break;
321 }
322 }
323 startblock= i + 3;
324
325 /* skip over the remainder of the LW */
326 skip += tmpbuff[i+1]+tmpbuff[i+2];
327 while (skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)
328 ++skip;
329 skip += 8;
330
331 /* now do it again to find the end */
332 end= start;
333 for (i += 3; i < j - 4 ; ++i)
334 {
335 end += tmpbuff[i];
336 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
337 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
338 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
339 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
340 {
341 complete= true;
342 break;
343 }
344 }
345
346 if (start >= 0)
347 PrintAndLog("Found data at sample: %i",skip);
348 else
349 {
350 PrintAndLog("No data found!");
351 PrintAndLog("Try again with more samples.");
352 return 0;
353 }
354
355 if (!complete)
356 {
357 PrintAndLog("*** Warning!");
358 PrintAndLog("Partial data - no end found!");
359 PrintAndLog("Try again with more samples.");
360 }
361
362 /* get rid of leading crap */
363 sprintf(tmp,"%i",skip);
364 CmdLtrim(tmp);
365
366 /* now work through remaining buffer printing out data blocks */
367 block= 0;
368 i= startblock;
369 while (block < 6)
370 {
371 PrintAndLog("Block %i:", block);
372 // mandemod routine needs to be split so we can call it for data
373 // just print for now for debugging
374 CmdManchesterDemod("i 64");
375 skip= 0;
376 /* look for LW before start of next block */
377 for ( ; i < j - 4 ; ++i)
378 {
379 skip += tmpbuff[i];
380 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
381 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
382 break;
383 }
384 while (GraphBuffer[skip] > low)
385 ++skip;
386 skip += 8;
387 sprintf(tmp,"%i",skip);
388 CmdLtrim(tmp);
389 start += skip;
390 block++;
391 }
392 return 0;
393}
394
395static command_t CommandTable[] =
396{
397 {"help", CmdHelp, 1, "This help"},
398 {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
399 {"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
400 {"em410xwatch", CmdEM410xWatch, 0, "Watches for EM410x tags"},
401 {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
402 {NULL, NULL, 0, NULL}
403};
404
405int CmdLFEM4X(const char *Cmd)
406{
407 CmdsParse(CommandTable, Cmd);
408 return 0;
409}
410
411int CmdHelp(const char *Cmd)
412{
413 CmdsHelp(CommandTable);
414 return 0;
415}
Impressum, Datenschutz