]>
Commit | Line | Data |
---|---|---|
bd20f8f4 | 1 | //----------------------------------------------------------------------------- |
2 | // (c) 2009 Henryk Plötz <henryk@ploetzli.ch> | |
da05bc6e A |
3 | // 2016 Iceman |
4 | // 2018 AntiCat (rwd rewritten) | |
bd20f8f4 | 5 | // |
6 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
7 | // at your option, any later version. See the LICENSE.txt file for the text of | |
8 | // the license. | |
9 | //----------------------------------------------------------------------------- | |
10 | // LEGIC RF simulation code | |
11 | //----------------------------------------------------------------------------- | |
a7247d85 | 12 | |
e30c654b | 13 | #include "proxmark3.h" |
a7247d85 | 14 | #include "apps.h" |
f7e3ed82 | 15 | #include "util.h" |
9ab7a6c7 | 16 | #include "string.h" |
a7247d85 | 17 | |
f7e3ed82 | 18 | #include "legicrf.h" |
8e220a91 | 19 | #include "legic_prng.h" |
da05bc6e | 20 | #include "legic.h" |
8e220a91 | 21 | #include "crc.h" |
22 | ||
a7247d85 | 23 | static struct legic_frame { |
ccedd6ae | 24 | int bits; |
a2b1414f | 25 | uint32_t data; |
a7247d85 | 26 | } current_frame; |
8e220a91 | 27 | |
3612a8a8 | 28 | static enum { |
29 | STATE_DISCON, | |
30 | STATE_IV, | |
31 | STATE_CON, | |
32 | } legic_state; | |
33 | ||
34 | static crc_t legic_crc; | |
35 | static int legic_read_count; | |
36 | static uint32_t legic_prng_bc; | |
37 | static uint32_t legic_prng_iv; | |
38 | ||
39 | static int legic_phase_drift; | |
40 | static int legic_frame_drift; | |
41 | static int legic_reqresp_drift; | |
8e220a91 | 42 | |
add16a62 | 43 | AT91PS_TC timer; |
3612a8a8 | 44 | AT91PS_TC prng_timer; |
add16a62 | 45 | |
da05bc6e A |
46 | static legic_card_select_t card;/* metadata of currently selected card */ |
47 | ||
48 | //----------------------------------------------------------------------------- | |
49 | // Frame timing and pseudorandom number generator | |
50 | // | |
51 | // The Prng is forwarded every 100us (TAG_BIT_PERIOD), except when the reader is | |
52 | // transmitting. In that case the prng has to be forwarded every bit transmitted: | |
53 | // - 60us for a 0 (RWD_TIME_0) | |
54 | // - 100us for a 1 (RWD_TIME_1) | |
55 | // | |
56 | // The data dependent timing makes writing comprehensible code significantly | |
57 | // harder. The current aproach forwards the prng data based if there is data on | |
58 | // air and time based, using GET_TICKS, during computational and wait periodes. | |
59 | // | |
60 | // To not have the necessity to calculate/guess exection time dependend timeouts | |
61 | // tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots. | |
62 | //----------------------------------------------------------------------------- | |
63 | ||
64 | static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ | |
65 | ||
66 | #define RWD_TIME_PAUSE 30 /* 20us */ | |
67 | #define RWD_TIME_1 150 /* READER_TIME_PAUSE 20us off + 80us on = 100us */ | |
68 | #define RWD_TIME_0 90 /* READER_TIME_PAUSE 20us off + 40us on = 60us */ | |
69 | #define RWD_FRAME_WAIT 330 /* 220us from TAG frame end to READER frame start */ | |
70 | #define TAG_FRAME_WAIT 495 /* 330us from READER frame end to TAG frame start */ | |
71 | #define TAG_BIT_PERIOD 150 /* 100us */ | |
72 | #define TAG_WRITE_TIMEOUT 60 /* 40 * 100us (write should take at most 3.6ms) */ | |
73 | ||
74 | #define SIM_DIVISOR 586 /* prng_time/DIV count prng needs to be forwared */ | |
75 | #define SIM_SHIFT 900 /* prng_time+SHIFT shift of delayed start */ | |
76 | #define RWD_TIME_FUZZ 20 /* rather generous 13us, since the peak detector | |
77 | /+ hysteresis fuzz quite a bit */ | |
78 | ||
79 | #define LEGIC_READ 0x01 /* Read Command */ | |
80 | #define LEGIC_WRITE 0x00 /* Write Command */ | |
81 | ||
82 | #define SESSION_IV 0x55 /* An arbitrary chose session IV, all shoud work */ | |
83 | #define OFFSET_LOG 1024 /* The largest Legic Prime card is 1k */ | |
84 | #define WRITE_LOWERLIMIT 4 /* UID and MCC are not writable */ | |
85 | ||
86 | #define INPUT_THRESHOLD 8 /* heuristically determined, lower values */ | |
87 | /* lead to detecting false ack during write */ | |
88 | ||
89 | #define FUZZ_EQUAL(value, target, fuzz) ((value) > ((target)-(fuzz)) && (value) < ((target)+(fuzz))) | |
90 | ||
91 | //----------------------------------------------------------------------------- | |
92 | // I/O interface abstraction (FPGA -> ARM) | |
93 | //----------------------------------------------------------------------------- | |
94 | ||
95 | static inline uint8_t rx_byte_from_fpga() { | |
96 | for(;;) { | |
97 | WDT_HIT(); | |
98 | ||
99 | // wait for byte be become available in rx holding register | |
100 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { | |
101 | return AT91C_BASE_SSC->SSC_RHR; | |
102 | } | |
103 | } | |
104 | } | |
105 | ||
106 | //----------------------------------------------------------------------------- | |
107 | // Demodulation (Reader) | |
108 | //----------------------------------------------------------------------------- | |
109 | ||
110 | // Returns a demedulated bit | |
111 | // | |
112 | // The FPGA running xcorrelation samples the subcarrier at ~13.56 MHz. The mode | |
113 | // was initialy designed to receive BSPK/2-PSK. Hance, it reports an I/Q pair | |
114 | // every 4.7us (8 bits i and 8 bits q). | |
115 | // | |
116 | // The subcarrier amplitude can be calculated using Pythagoras sqrt(i^2 + q^2). | |
117 | // To reduce CPU time the amplitude is approximated by using linear functions: | |
118 | // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) | |
119 | // | |
120 | // Note: The SSC receiver is never synchronized the calculation my be performed | |
121 | // on a I/Q pair from two subsequent correlations, but does not matter. | |
122 | // | |
123 | // The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples | |
124 | // and averages the next (most stable) 8 samples. The final 8 samples are dropped | |
125 | // also. | |
126 | // | |
127 | // The demedulated should be alligned to the bit periode by the caller. This is | |
128 | // done in rx_bit_as_reader and rx_ack_as_reader. | |
129 | static inline bool rx_bit_as_reader() { | |
130 | int32_t cq = 0; | |
131 | int32_t ci = 0; | |
132 | ||
133 | // skip first 5 I/Q pairs | |
134 | for(size_t i = 0; i<5; ++i) { | |
135 | (int8_t)rx_byte_from_fpga(); | |
136 | (int8_t)rx_byte_from_fpga(); | |
137 | } | |
138 | ||
139 | // sample next 8 I/Q pairs | |
140 | for(size_t i = 0; i<8; ++i) { | |
141 | cq += (int8_t)rx_byte_from_fpga(); | |
142 | ci += (int8_t)rx_byte_from_fpga(); | |
143 | } | |
144 | ||
145 | // calculate power | |
146 | int32_t power = (MAX(ABS(ci), ABS(cq)) + (MIN(ABS(ci), ABS(cq)) >> 1)); | |
147 | ||
148 | // compare average (power / 8) to threshold | |
149 | return ((power >> 3) > INPUT_THRESHOLD); | |
150 | } | |
151 | ||
152 | //----------------------------------------------------------------------------- | |
153 | // Modulation (Reader) | |
154 | // | |
155 | // I've tried to modulate the Legic specific pause-puls using ssc and the default | |
156 | // ssc clock of 105.4 kHz (bit periode of 9.4us) - previous commit. However, | |
157 | // the timing was not precise enough. By increasing the ssc clock this could | |
158 | // be circumvented, but the adventage over bitbang would be little. | |
159 | //----------------------------------------------------------------------------- | |
160 | ||
161 | static inline void tx_bit_as_reader(bool bit) { | |
162 | // insert pause | |
163 | LOW(GPIO_SSC_DOUT); | |
164 | last_frame_end += RWD_TIME_PAUSE; | |
165 | while(GET_TICKS < last_frame_end) { }; | |
166 | HIGH(GPIO_SSC_DOUT); | |
167 | ||
168 | // return to high, wait for bit periode to end | |
169 | last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; | |
170 | while(GET_TICKS < last_frame_end) { }; | |
171 | } | |
172 | ||
173 | //----------------------------------------------------------------------------- | |
174 | // Frame Handling (Reader) | |
175 | // | |
176 | // The LEGIC RF protocol from card to reader does not include explicit frame | |
177 | // start/stop information or length information. The reader must know beforehand | |
178 | // how many bits it wants to receive. | |
179 | // Notably: a card sending a stream of 0-bits is indistinguishable from no card | |
180 | // present. | |
181 | //----------------------------------------------------------------------------- | |
182 | ||
183 | static void tx_frame_as_reader(uint32_t frame, uint8_t len) { | |
184 | FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); | |
185 | ||
186 | // wait for next tx timeslot | |
187 | last_frame_end += RWD_FRAME_WAIT; | |
188 | while(GET_TICKS < last_frame_end) { }; | |
189 | ||
190 | // transmit frame, MSB first | |
191 | for(uint8_t i = 0; i < len; ++i) { | |
192 | bool bit = (frame >> i) & 0x01; | |
193 | tx_bit_as_reader(bit ^ legic_prng_get_bit()); | |
194 | legic_prng_forward(1); | |
195 | }; | |
196 | ||
197 | // add pause to mark end of the frame | |
198 | LOW(GPIO_SSC_DOUT); | |
199 | last_frame_end += RWD_TIME_PAUSE; | |
200 | while(GET_TICKS < last_frame_end) { }; | |
201 | HIGH(GPIO_SSC_DOUT); | |
202 | } | |
203 | ||
204 | static uint32_t rx_frame_as_reader(uint8_t len) { | |
205 | FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | |
206 | | FPGA_HF_READER_RX_XCORR_848_KHZ | |
207 | | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); | |
208 | ||
209 | // hold sampling until card is expected to respond | |
210 | last_frame_end += TAG_FRAME_WAIT; | |
211 | while(GET_TICKS < last_frame_end) { }; | |
212 | ||
213 | uint32_t frame = 0; | |
214 | for(uint8_t i = 0; i < len; i++) { | |
215 | frame |= (rx_bit_as_reader() ^ legic_prng_get_bit()) << i; | |
216 | legic_prng_forward(1); | |
217 | ||
218 | // rx_bit_as_reader runs only 95us, resync to TAG_BIT_PERIOD | |
219 | last_frame_end += TAG_BIT_PERIOD; | |
220 | while(GET_TICKS < last_frame_end) { }; | |
221 | } | |
222 | ||
223 | return frame; | |
224 | } | |
225 | ||
226 | static bool rx_ack_as_reader() { | |
227 | // change fpga into rx mode | |
228 | FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | |
229 | | FPGA_HF_READER_RX_XCORR_848_KHZ | |
230 | | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); | |
231 | ||
232 | // hold sampling until card is expected to respond | |
233 | last_frame_end += TAG_FRAME_WAIT; | |
234 | while(GET_TICKS < last_frame_end) { }; | |
235 | ||
236 | uint32_t ack = 0; | |
237 | for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { | |
238 | // sample bit | |
239 | ack = rx_bit_as_reader(); | |
240 | legic_prng_forward(1); | |
241 | ||
242 | // rx_bit_as_reader runs only 95us, resync to TAG_BIT_PERIOD | |
243 | last_frame_end += TAG_BIT_PERIOD; | |
244 | while(GET_TICKS < last_frame_end) { }; | |
245 | ||
246 | // check if it was an ACK | |
247 | if(ack) { | |
248 | break; | |
249 | } | |
250 | } | |
251 | ||
252 | return ack; | |
253 | } | |
254 | ||
255 | //----------------------------------------------------------------------------- | |
256 | // Legic Reader | |
257 | //----------------------------------------------------------------------------- | |
258 | ||
259 | int init_card(uint8_t cardtype, legic_card_select_t *p_card) { | |
260 | p_card->tagtype = cardtype; | |
261 | ||
262 | switch(p_card->tagtype) { | |
263 | case 0x0d: | |
264 | p_card->cmdsize = 6; | |
265 | p_card->addrsize = 5; | |
266 | p_card->cardsize = 22; | |
267 | break; | |
268 | case 0x1d: | |
269 | p_card->cmdsize = 9; | |
270 | p_card->addrsize = 8; | |
271 | p_card->cardsize = 256; | |
272 | break; | |
273 | case 0x3d: | |
274 | p_card->cmdsize = 11; | |
275 | p_card->addrsize = 10; | |
276 | p_card->cardsize = 1024; | |
277 | break; | |
278 | default: | |
279 | p_card->cmdsize = 0; | |
280 | p_card->addrsize = 0; | |
281 | p_card->cardsize = 0; | |
282 | return 2; | |
283 | } | |
284 | return 0; | |
285 | } | |
286 | ||
287 | static void init_reader(bool clear_mem) { | |
288 | // configure FPGA | |
289 | FpgaDownloadAndGo(FPGA_BITSTREAM_HF); | |
290 | FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | |
291 | | FPGA_HF_READER_RX_XCORR_848_KHZ | |
292 | | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); | |
293 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD); | |
294 | LED_D_ON(); | |
295 | ||
296 | // configure SSC with defaults | |
297 | FpgaSetupSsc(); | |
298 | ||
299 | // re-claim GPIO_SSC_DOUT as GPIO and enable output | |
300 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; | |
301 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; | |
302 | HIGH(GPIO_SSC_DOUT); | |
303 | ||
304 | // init crc calculator | |
305 | crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); | |
306 | ||
307 | // start us timer | |
308 | StartTicks(); | |
309 | } | |
310 | ||
311 | // Setup reader to card connection | |
312 | // | |
313 | // The setup consists of a three way handshake: | |
314 | // - Transmit initialisation vector 7 bits | |
315 | // - Receive card type 6 bits | |
316 | // - Acknowledge frame 6 bits | |
317 | static uint32_t setup_phase_reader(uint8_t iv) { | |
318 | // init coordination timestamp | |
319 | last_frame_end = GET_TICKS; | |
320 | ||
321 | // Switch on carrier and let the card charge for 5ms. | |
322 | last_frame_end += 7500; | |
323 | while(GET_TICKS < last_frame_end) { }; | |
324 | ||
325 | legic_prng_init(0); | |
326 | tx_frame_as_reader(iv, 7); | |
327 | ||
328 | // configure iv | |
329 | legic_prng_init(iv); | |
330 | legic_prng_forward(2); | |
331 | ||
332 | // receive card type | |
333 | int32_t card_type = rx_frame_as_reader(6); | |
334 | legic_prng_forward(3); | |
335 | ||
336 | // send obsfuscated acknowledgment frame | |
337 | switch (card_type) { | |
338 | case 0x0D: | |
339 | tx_frame_as_reader(0x19, 6); // MIM22 | READCMD = 0x18 | 0x01 | |
340 | break; | |
341 | case 0x1D: | |
342 | case 0x3D: | |
343 | tx_frame_as_reader(0x39, 6); // MIM256 | READCMD = 0x38 | 0x01 | |
344 | break; | |
345 | } | |
346 | ||
347 | return card_type; | |
348 | } | |
349 | ||
350 | static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) { | |
351 | crc_clear(&legic_crc); | |
352 | crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz); | |
353 | return crc_finish(&legic_crc); | |
354 | } | |
355 | ||
356 | static int16_t read_byte(uint16_t index, uint8_t cmd_sz) { | |
357 | uint16_t cmd = (index << 1) | LEGIC_READ; | |
358 | ||
359 | // read one byte | |
360 | LED_B_ON(); | |
361 | legic_prng_forward(2); | |
362 | tx_frame_as_reader(cmd, cmd_sz); | |
363 | legic_prng_forward(2); | |
364 | uint32_t frame = rx_frame_as_reader(12); | |
365 | LED_B_OFF(); | |
366 | ||
367 | // split frame into data and crc | |
368 | uint8_t byte = BYTEx(frame, 0); | |
369 | uint8_t crc = BYTEx(frame, 1); | |
370 | ||
371 | // check received against calculated crc | |
372 | uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte); | |
373 | if(calc_crc != crc) { | |
374 | Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc); | |
375 | return -1; | |
376 | } | |
377 | ||
378 | legic_prng_forward(1); | |
379 | ||
380 | return byte; | |
381 | } | |
382 | ||
383 | // Transmit write command, wait until (3.6ms) the tag sends back an unencrypted | |
384 | // ACK ('1' bit) and forward the prng time based. | |
385 | bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) { | |
386 | uint32_t cmd = index << 1 | LEGIC_WRITE; // prepare command | |
387 | uint8_t crc = calc_crc4(cmd, addr_sz + 1, byte); // calculate crc | |
388 | cmd |= byte << (addr_sz + 1); // append value | |
389 | cmd |= (crc & 0xF) << (addr_sz + 1 + 8); // and crc | |
390 | ||
391 | // send write command | |
392 | LED_C_ON(); | |
393 | legic_prng_forward(2); | |
394 | tx_frame_as_reader(cmd, addr_sz + 1 + 8 + 4); // sz = addr_sz + cmd + data + crc | |
395 | legic_prng_forward(3); | |
396 | LED_C_OFF(); | |
397 | ||
398 | // wait for ack | |
399 | return rx_ack_as_reader(); | |
400 | } | |
401 | ||
402 | //----------------------------------------------------------------------------- | |
403 | // Command Line Interface | |
404 | // | |
405 | // Only this functions are public / called from appmain.c | |
406 | //----------------------------------------------------------------------------- | |
407 | void LegicRfReader(int offset, int bytes) { | |
408 | uint8_t *BigBuf = BigBuf_get_addr(); | |
409 | memset(BigBuf, 0, 1024); | |
410 | ||
411 | // configure ARM and FPGA | |
412 | init_reader(false); | |
413 | ||
414 | // establish shared secret and detect card type | |
415 | DbpString("Reading card ..."); | |
416 | uint8_t card_type = setup_phase_reader(SESSION_IV); | |
417 | if(init_card(card_type, &card) != 0) { | |
418 | Dbprintf("No or unknown card found, aborting"); | |
419 | goto OUT; | |
420 | } | |
421 | ||
422 | // if no argument is specified create full dump | |
423 | if(bytes == -1) { | |
424 | bytes = card.cardsize; | |
425 | } | |
426 | ||
427 | // do not read beyond card memory | |
428 | if(bytes + offset > card.cardsize) { | |
429 | bytes = card.cardsize - offset; | |
430 | } | |
431 | ||
432 | for(uint16_t i = 0; i < bytes; ++i) { | |
433 | int16_t byte = read_byte(offset + i, card.cmdsize); | |
434 | if(byte == -1) { | |
435 | Dbprintf("operation failed @ 0x%03.3x", bytes); | |
436 | goto OUT; | |
437 | } | |
438 | BigBuf[i] = byte; | |
439 | } | |
440 | ||
441 | // OK | |
442 | Dbprintf("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); | |
443 | Dbprintf("'data hexsamples %d' to view results", (bytes+7) & ~7); | |
444 | ||
445 | OUT: | |
446 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
447 | LED_B_OFF(); | |
448 | LED_C_OFF(); | |
449 | LED_D_OFF(); | |
450 | StopTicks(); | |
451 | } | |
452 | ||
453 | void LegicRfWriter(int bytes, int offset) { | |
454 | uint8_t *BigBuf = BigBuf_get_addr(); | |
455 | ||
456 | // configure ARM and FPGA | |
457 | init_reader(false); | |
458 | ||
459 | // uid is not writeable | |
460 | if(offset <= WRITE_LOWERLIMIT) { | |
461 | goto OUT; | |
462 | } | |
463 | ||
464 | // establish shared secret and detect card type | |
465 | Dbprintf("Writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); | |
466 | uint8_t card_type = setup_phase_reader(SESSION_IV); | |
467 | if(init_card(card_type, &card) != 0) { | |
468 | Dbprintf("No or unknown card found, aborting"); | |
469 | goto OUT; | |
470 | } | |
471 | ||
472 | // do not write beyond card memory | |
473 | if(bytes + offset > card.cardsize) { | |
474 | bytes = card.cardsize - offset; | |
475 | } | |
476 | ||
477 | // write in reverse order, only then is DCF (decremental field) writable | |
478 | while(bytes-- > 0 && !BUTTON_PRESS()) { | |
479 | if(!write_byte(bytes + offset, BigBuf[bytes], card.addrsize)) { | |
480 | Dbprintf("operation failed @ 0x%03.3x", bytes); | |
481 | goto OUT; | |
482 | } | |
483 | } | |
484 | ||
485 | // OK | |
486 | DbpString("Write successful"); | |
487 | ||
488 | OUT: | |
489 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
490 | LED_B_OFF(); | |
491 | LED_C_OFF(); | |
492 | LED_D_OFF(); | |
493 | StopTicks(); | |
494 | } | |
495 | ||
496 | //----------------------------------------------------------------------------- | |
497 | // Legic Simulator | |
498 | //----------------------------------------------------------------------------- | |
499 | ||
add16a62 | 500 | static void setup_timer(void) |
501 | { | |
502 | /* Set up Timer 1 to use for measuring time between pulses. Since we're bit-banging | |
503 | * this it won't be terribly accurate but should be good enough. | |
504 | */ | |
505 | AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); | |
506 | timer = AT91C_BASE_TC1; | |
507 | timer->TC_CCR = AT91C_TC_CLKDIS; | |
0aa4cfc2 | 508 | timer->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; |
add16a62 | 509 | timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; |
510 | ||
3612a8a8 | 511 | /* |
512 | * Set up Timer 2 to use for measuring time between frames in | |
513 | * tag simulation mode. Runs 4x faster as Timer 1 | |
514 | */ | |
515 | AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC2); | |
516 | prng_timer = AT91C_BASE_TC2; | |
517 | prng_timer->TC_CCR = AT91C_TC_CLKDIS; | |
518 | prng_timer->TC_CMR = AT91C_TC_CLKS_TIMER_DIV2_CLOCK; | |
519 | prng_timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
520 | } | |
521 | ||
3612a8a8 | 522 | /* Generate Keystream */ |
523 | static uint32_t get_key_stream(int skip, int count) | |
524 | { | |
525 | uint32_t key=0; int i; | |
526 | ||
527 | /* Use int to enlarge timer tc to 32bit */ | |
528 | legic_prng_bc += prng_timer->TC_CV; | |
529 | prng_timer->TC_CCR = AT91C_TC_SWTRG; | |
530 | ||
531 | /* If skip == -1, forward prng time based */ | |
532 | if(skip == -1) { | |
533 | i = (legic_prng_bc+SIM_SHIFT)/SIM_DIVISOR; /* Calculate Cycles based on timer */ | |
534 | i -= legic_prng_count(); /* substract cycles of finished frames */ | |
535 | i -= count; /* substract current frame length, rewidn to bedinning */ | |
536 | legic_prng_forward(i); | |
537 | } else { | |
538 | legic_prng_forward(skip); | |
539 | } | |
540 | ||
541 | /* Write Time Data into LOG */ | |
117d9ec2 | 542 | uint8_t *BigBuf = BigBuf_get_addr(); |
3612a8a8 | 543 | if(count == 6) { i = -1; } else { i = legic_read_count; } |
117d9ec2 | 544 | BigBuf[OFFSET_LOG+128+i] = legic_prng_count(); |
545 | BigBuf[OFFSET_LOG+256+i*4] = (legic_prng_bc >> 0) & 0xff; | |
546 | BigBuf[OFFSET_LOG+256+i*4+1] = (legic_prng_bc >> 8) & 0xff; | |
547 | BigBuf[OFFSET_LOG+256+i*4+2] = (legic_prng_bc >>16) & 0xff; | |
548 | BigBuf[OFFSET_LOG+256+i*4+3] = (legic_prng_bc >>24) & 0xff; | |
549 | BigBuf[OFFSET_LOG+384+i] = count; | |
3612a8a8 | 550 | |
551 | /* Generate KeyStream */ | |
552 | for(i=0; i<count; i++) { | |
553 | key |= legic_prng_get_bit() << i; | |
554 | legic_prng_forward(1); | |
555 | } | |
556 | return key; | |
557 | } | |
558 | ||
559 | /* Send a frame in tag mode, the FPGA must have been set up by | |
560 | * LegicRfSimulate | |
561 | */ | |
562 | static void frame_send_tag(uint16_t response, int bits, int crypt) | |
563 | { | |
564 | /* Bitbang the response */ | |
565 | AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; | |
566 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; | |
567 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; | |
568 | ||
569 | /* Use time to crypt frame */ | |
570 | if(crypt) { | |
571 | legic_prng_forward(2); /* TAG_TIME_WAIT -> shift by 2 */ | |
572 | int i; int key = 0; | |
573 | for(i=0; i<bits; i++) { | |
574 | key |= legic_prng_get_bit() << i; | |
575 | legic_prng_forward(1); | |
576 | } | |
577 | //Dbprintf("key = 0x%x", key); | |
578 | response = response ^ key; | |
579 | } | |
580 | ||
581 | /* Wait for the frame start */ | |
da05bc6e | 582 | while(timer->TC_CV < (TAG_FRAME_WAIT - 30)) ; |
3612a8a8 | 583 | |
584 | int i; | |
585 | for(i=0; i<bits; i++) { | |
da05bc6e | 586 | int nextbit = timer->TC_CV + TAG_BIT_PERIOD; |
3612a8a8 | 587 | int bit = response & 1; |
588 | response = response >> 1; | |
589 | if(bit) { | |
590 | AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; | |
591 | } else { | |
592 | AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; | |
593 | } | |
594 | while(timer->TC_CV < nextbit) ; | |
595 | } | |
596 | AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; | |
597 | } | |
598 | ||
3612a8a8 | 599 | static void frame_append_bit(struct legic_frame * const f, int bit) |
600 | { | |
601 | if(f->bits >= 31) { | |
602 | return; /* Overflow, won't happen */ | |
603 | } | |
604 | f->data |= (bit<<f->bits); | |
605 | f->bits++; | |
606 | } | |
607 | ||
ccedd6ae | 608 | static void frame_clean(struct legic_frame * const f) |
a7247d85 | 609 | { |
ccedd6ae | 610 | f->data = 0; |
611 | f->bits = 0; | |
a7247d85 | 612 | } |
613 | ||
3612a8a8 | 614 | /* Handle (whether to respond) a frame in tag mode */ |
615 | static void frame_handle_tag(struct legic_frame const * const f) | |
616 | { | |
117d9ec2 | 617 | uint8_t *BigBuf = BigBuf_get_addr(); |
618 | ||
3612a8a8 | 619 | /* First Part of Handshake (IV) */ |
620 | if(f->bits == 7) { | |
621 | if(f->data == SESSION_IV) { | |
622 | LED_C_ON(); | |
623 | prng_timer->TC_CCR = AT91C_TC_SWTRG; | |
624 | legic_prng_init(f->data); | |
625 | frame_send_tag(0x3d, 6, 1); /* 0x3d^0x26 = 0x1b */ | |
626 | legic_state = STATE_IV; | |
627 | legic_read_count = 0; | |
628 | legic_prng_bc = 0; | |
629 | legic_prng_iv = f->data; | |
630 | ||
631 | /* TIMEOUT */ | |
632 | timer->TC_CCR = AT91C_TC_SWTRG; | |
633 | while(timer->TC_CV > 1); | |
634 | while(timer->TC_CV < 280); | |
635 | return; | |
636 | } else if((prng_timer->TC_CV % 50) > 40) { | |
637 | legic_prng_init(f->data); | |
638 | frame_send_tag(0x3d, 6, 1); | |
639 | SpinDelay(20); | |
640 | return; | |
641 | } | |
642 | } | |
643 | ||
644 | /* 0x19==??? */ | |
645 | if(legic_state == STATE_IV) { | |
646 | if((f->bits == 6) && (f->data == (0x19 ^ get_key_stream(1, 6)))) { | |
647 | legic_state = STATE_CON; | |
648 | ||
649 | /* TIMEOUT */ | |
650 | timer->TC_CCR = AT91C_TC_SWTRG; | |
651 | while(timer->TC_CV > 1); | |
652 | while(timer->TC_CV < 200); | |
653 | return; | |
654 | } else { | |
655 | legic_state = STATE_DISCON; | |
656 | LED_C_OFF(); | |
657 | Dbprintf("0x19 - Frame: %03.3x", f->data); | |
658 | return; | |
659 | } | |
660 | } | |
661 | ||
662 | /* Read */ | |
663 | if(f->bits == 11) { | |
664 | if(legic_state == STATE_CON) { | |
665 | int key = get_key_stream(-1, 11); //legic_phase_drift, 11); | |
666 | int addr = f->data ^ key; addr = addr >> 1; | |
117d9ec2 | 667 | int data = BigBuf[addr]; |
da05bc6e | 668 | int hash = calc_crc4(addr, data, 11) << 8; |
117d9ec2 | 669 | BigBuf[OFFSET_LOG+legic_read_count] = (uint8_t)addr; |
3612a8a8 | 670 | legic_read_count++; |
671 | ||
672 | //Dbprintf("Data:%03.3x, key:%03.3x, addr: %03.3x, read_c:%u", f->data, key, addr, read_c); | |
673 | legic_prng_forward(legic_reqresp_drift); | |
674 | ||
675 | frame_send_tag(hash | data, 12, 1); | |
676 | ||
677 | /* SHORT TIMEOUT */ | |
678 | timer->TC_CCR = AT91C_TC_SWTRG; | |
679 | while(timer->TC_CV > 1); | |
680 | legic_prng_forward(legic_frame_drift); | |
681 | while(timer->TC_CV < 180); | |
682 | return; | |
683 | } | |
684 | } | |
685 | ||
686 | /* Write */ | |
687 | if(f->bits == 23) { | |
688 | int key = get_key_stream(-1, 23); //legic_frame_drift, 23); | |
689 | int addr = f->data ^ key; addr = addr >> 1; addr = addr & 0x3ff; | |
690 | int data = f->data ^ key; data = data >> 11; data = data & 0xff; | |
691 | ||
692 | /* write command */ | |
693 | legic_state = STATE_DISCON; | |
694 | LED_C_OFF(); | |
695 | Dbprintf("write - addr: %x, data: %x", addr, data); | |
696 | return; | |
697 | } | |
698 | ||
699 | if(legic_state != STATE_DISCON) { | |
700 | Dbprintf("Unexpected: sz:%u, Data:%03.3x, State:%u, Count:%u", f->bits, f->data, legic_state, legic_read_count); | |
701 | int i; | |
702 | Dbprintf("IV: %03.3x", legic_prng_iv); | |
703 | for(i = 0; i<legic_read_count; i++) { | |
117d9ec2 | 704 | Dbprintf("Read Nb: %u, Addr: %u", i, BigBuf[OFFSET_LOG+i]); |
3612a8a8 | 705 | } |
706 | ||
707 | for(i = -1; i<legic_read_count; i++) { | |
708 | uint32_t t; | |
117d9ec2 | 709 | t = BigBuf[OFFSET_LOG+256+i*4]; |
710 | t |= BigBuf[OFFSET_LOG+256+i*4+1] << 8; | |
711 | t |= BigBuf[OFFSET_LOG+256+i*4+2] <<16; | |
712 | t |= BigBuf[OFFSET_LOG+256+i*4+3] <<24; | |
3612a8a8 | 713 | |
714 | Dbprintf("Cycles: %u, Frame Length: %u, Time: %u", | |
117d9ec2 | 715 | BigBuf[OFFSET_LOG+128+i], |
716 | BigBuf[OFFSET_LOG+384+i], | |
3612a8a8 | 717 | t); |
718 | } | |
719 | } | |
720 | legic_state = STATE_DISCON; | |
721 | legic_read_count = 0; | |
722 | SpinDelay(10); | |
723 | LED_C_OFF(); | |
724 | return; | |
725 | } | |
726 | ||
727 | /* Read bit by bit untill full frame is received | |
728 | * Call to process frame end answer | |
729 | */ | |
730 | static void emit(int bit) | |
731 | { | |
732 | if(bit == -1) { | |
733 | if(current_frame.bits <= 4) { | |
734 | frame_clean(¤t_frame); | |
735 | } else { | |
736 | frame_handle_tag(¤t_frame); | |
737 | frame_clean(¤t_frame); | |
738 | } | |
739 | WDT_HIT(); | |
740 | } else if(bit == 0) { | |
741 | frame_append_bit(¤t_frame, 0); | |
742 | } else if(bit == 1) { | |
743 | frame_append_bit(¤t_frame, 1); | |
744 | } | |
745 | } | |
746 | ||
747 | void LegicRfSimulate(int phase, int frame, int reqresp) | |
748 | { | |
749 | /* ADC path high-frequency peak detector, FPGA in high-frequency simulator mode, | |
750 | * modulation mode set to 212kHz subcarrier. We are getting the incoming raw | |
751 | * envelope waveform on DIN and should send our response on DOUT. | |
752 | * | |
753 | * The LEGIC RF protocol is pulse-pause-encoding from reader to card, so we'll | |
754 | * measure the time between two rising edges on DIN, and no encoding on the | |
755 | * subcarrier from card to reader, so we'll just shift out our verbatim data | |
756 | * on DOUT, 1 bit is 100us. The time from reader to card frame is still unclear, | |
757 | * seems to be 300us-ish. | |
758 | */ | |
759 | ||
760 | if(phase < 0) { | |
761 | int i; | |
762 | for(i=0; i<=reqresp; i++) { | |
763 | legic_prng_init(SESSION_IV); | |
764 | Dbprintf("i=%u, key 0x%3.3x", i, get_key_stream(i, frame)); | |
765 | } | |
766 | return; | |
767 | } | |
768 | ||
769 | legic_phase_drift = phase; | |
770 | legic_frame_drift = frame; | |
771 | legic_reqresp_drift = reqresp; | |
772 | ||
7cc204bf | 773 | FpgaDownloadAndGo(FPGA_BITSTREAM_HF); |
3612a8a8 | 774 | SetAdcMuxFor(GPIO_MUXSEL_HIPKD); |
775 | FpgaSetupSsc(); | |
776 | FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K); | |
777 | ||
778 | /* Bitbang the receiver */ | |
779 | AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN; | |
780 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; | |
781 | ||
782 | setup_timer(); | |
783 | crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); | |
784 | ||
785 | int old_level = 0; | |
786 | int active = 0; | |
787 | legic_state = STATE_DISCON; | |
788 | ||
789 | LED_B_ON(); | |
790 | DbpString("Starting Legic emulator, press button to end"); | |
791 | while(!BUTTON_PRESS()) { | |
792 | int level = !!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN); | |
793 | int time = timer->TC_CV; | |
794 | ||
795 | if(level != old_level) { | |
796 | if(level == 1) { | |
797 | timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; | |
798 | if(FUZZ_EQUAL(time, RWD_TIME_1, RWD_TIME_FUZZ)) { | |
799 | /* 1 bit */ | |
800 | emit(1); | |
801 | active = 1; | |
802 | LED_A_ON(); | |
803 | } else if(FUZZ_EQUAL(time, RWD_TIME_0, RWD_TIME_FUZZ)) { | |
804 | /* 0 bit */ | |
805 | emit(0); | |
806 | active = 1; | |
807 | LED_A_ON(); | |
808 | } else if(active) { | |
809 | /* invalid */ | |
810 | emit(-1); | |
811 | active = 0; | |
812 | LED_A_OFF(); | |
813 | } | |
814 | } | |
815 | } | |
816 | ||
817 | if(time >= (RWD_TIME_1+RWD_TIME_FUZZ) && active) { | |
818 | /* Frame end */ | |
819 | emit(-1); | |
820 | active = 0; | |
821 | LED_A_OFF(); | |
822 | } | |
823 | ||
824 | if(time >= (20*RWD_TIME_1) && (timer->TC_SR & AT91C_TC_CLKSTA)) { | |
825 | timer->TC_CCR = AT91C_TC_CLKDIS; | |
826 | } | |
827 | ||
828 | old_level = level; | |
829 | WDT_HIT(); | |
830 | } | |
831 | DbpString("Stopped"); | |
832 | LED_B_OFF(); | |
833 | LED_A_OFF(); | |
834 | LED_C_OFF(); | |
dcc10e5e | 835 | } |
a2b1414f | 836 |