]> cvs.zerfleddert.de Git - proxmark3-svn/blob - client/cmdlfem4x.c
Clean up data types, some header cleanup, etc.
[proxmark3-svn] / client / cmdlfem4x.c
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
10 static 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 */
20 int 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
79 retest:
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 */
172 int 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 */
236 int CmdEM410xWatch(const char *Cmd)
237 {
238 do
239 {
240 CmdLFRead("");
241 CmdSamples("2000");
242 } while ( ! CmdEM410xRead(""));
243 return 0;
244 }
245
246 /* Read the transmitted data of an EM4x50 tag
247 * Format:
248 *
249 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
250 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
251 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
252 * XXXXXXXX [row parity bit (even)] <- 8 bits plus parity
253 * CCCCCCCC <- column parity bits
254 * 0 <- stop bit
255 * LW <- Listen Window
256 *
257 * This pattern repeats for every block of data being transmitted.
258 * Transmission starts with two Listen Windows (LW - a modulated
259 * pattern of 320 cycles each (32/32/128/64/64)).
260 *
261 * Note that this data may or may not be the UID. It is whatever data
262 * is stored in the blocks defined in the control word First and Last
263 * Word Read values. UID is stored in block 32.
264 */
265 int CmdEM4x50Read(const char *Cmd)
266 {
267 int i, j, startblock, clock, skip, block, start, end, low, high;
268 bool complete= false;
269 int tmpbuff[MAX_GRAPH_TRACE_LEN / 64];
270 char tmp[6];
271
272 high= low= 0;
273 clock= 64;
274
275 /* first get high and low values */
276 for (i = 0; i < GraphTraceLen; i++)
277 {
278 if (GraphBuffer[i] > high)
279 high = GraphBuffer[i];
280 else if (GraphBuffer[i] < low)
281 low = GraphBuffer[i];
282 }
283
284 /* populate a buffer with pulse lengths */
285 i= 0;
286 j= 0;
287 while (i < GraphTraceLen)
288 {
289 // measure from low to low
290 while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
291 ++i;
292 start= i;
293 while ((GraphBuffer[i] < high) && (i<GraphTraceLen))
294 ++i;
295 while ((GraphBuffer[i] > low) && (i<GraphTraceLen))
296 ++i;
297 if (j>(MAX_GRAPH_TRACE_LEN/64)) {
298 break;
299 }
300 tmpbuff[j++]= i - start;
301 }
302
303 /* look for data start - should be 2 pairs of LW (pulses of 192,128) */
304 start= -1;
305 skip= 0;
306 for (i= 0; i < j - 4 ; ++i)
307 {
308 skip += tmpbuff[i];
309 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
310 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
311 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
312 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
313 {
314 start= i + 3;
315 break;
316 }
317 }
318 startblock= i + 3;
319
320 /* skip over the remainder of the LW */
321 skip += tmpbuff[i+1]+tmpbuff[i+2];
322 while (skip < MAX_GRAPH_TRACE_LEN && GraphBuffer[skip] > low)
323 ++skip;
324 skip += 8;
325
326 /* now do it again to find the end */
327 end= start;
328 for (i += 3; i < j - 4 ; ++i)
329 {
330 end += tmpbuff[i];
331 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
332 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
333 if (tmpbuff[i+2] >= 190 && tmpbuff[i+2] <= 194)
334 if (tmpbuff[i+3] >= 126 && tmpbuff[i+3] <= 130)
335 {
336 complete= true;
337 break;
338 }
339 }
340
341 if (start >= 0)
342 PrintAndLog("Found data at sample: %i",skip);
343 else
344 {
345 PrintAndLog("No data found!");
346 PrintAndLog("Try again with more samples.");
347 return 0;
348 }
349
350 if (!complete)
351 {
352 PrintAndLog("*** Warning!");
353 PrintAndLog("Partial data - no end found!");
354 PrintAndLog("Try again with more samples.");
355 }
356
357 /* get rid of leading crap */
358 sprintf(tmp,"%i",skip);
359 CmdLtrim(tmp);
360
361 /* now work through remaining buffer printing out data blocks */
362 block= 0;
363 i= startblock;
364 while (block < 6)
365 {
366 PrintAndLog("Block %i:", block);
367 // mandemod routine needs to be split so we can call it for data
368 // just print for now for debugging
369 CmdManchesterDemod("i 64");
370 skip= 0;
371 /* look for LW before start of next block */
372 for ( ; i < j - 4 ; ++i)
373 {
374 skip += tmpbuff[i];
375 if (tmpbuff[i] >= 190 && tmpbuff[i] <= 194)
376 if (tmpbuff[i+1] >= 126 && tmpbuff[i+1] <= 130)
377 break;
378 }
379 while (GraphBuffer[skip] > low)
380 ++skip;
381 skip += 8;
382 sprintf(tmp,"%i",skip);
383 CmdLtrim(tmp);
384 start += skip;
385 block++;
386 }
387 return 0;
388 }
389
390 static command_t CommandTable[] =
391 {
392 {"help", CmdHelp, 1, "This help"},
393 {"em410xread", CmdEM410xRead, 1, "[clock rate] -- Extract ID from EM410x tag"},
394 {"em410xsim", CmdEM410xSim, 0, "<UID> -- Simulate EM410x tag"},
395 {"em410xwatch", CmdEM410xWatch, 0, "Watches for EM410x tags"},
396 {"em4x50read", CmdEM4x50Read, 1, "Extract data from EM4x50 tag"},
397 {NULL, NULL, 0, NULL}
398 };
399
400 int CmdLFEM4X(const char *Cmd)
401 {
402 CmdsParse(CommandTable, Cmd);
403 return 0;
404 }
405
406 int CmdHelp(const char *Cmd)
407 {
408 CmdsHelp(CommandTable);
409 return 0;
410 }
Impressum, Datenschutz