]> git.zerfleddert.de Git - proxmark3-svn/blob - armsrc/mifarecmd.c
Merge pull request #125 from pwpiwi/hf_mifare_fix
[proxmark3-svn] / armsrc / mifarecmd.c
1 //-----------------------------------------------------------------------------
2 // Merlok - June 2011, 2012
3 // Gerhard de Koning Gans - May 2008
4 // Hagen Fritsch - June 2010
5 // Midnitesnake - Dec 2013
6 // Andy Davies - Apr 2014
7 // Iceman - May 2014
8 //
9 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
10 // at your option, any later version. See the LICENSE.txt file for the text of
11 // the license.
12 //-----------------------------------------------------------------------------
13 // Routines to support ISO 14443 type A.
14 //-----------------------------------------------------------------------------
15
16 #include "mifarecmd.h"
17 #include "apps.h"
18 #include "util.h"
19 #include "crc.h"
20
21 // the block number for the ISO14443-4 PCB
22 uint8_t pcb_blocknum = 0;
23 // Deselect card by sending a s-block. the crc is precalced for speed
24 static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};
25
26 //-----------------------------------------------------------------------------
27 // Select, Authenticate, Read a MIFARE tag.
28 // read block
29 //-----------------------------------------------------------------------------
30 void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
31 {
32 // params
33 uint8_t blockNo = arg0;
34 uint8_t keyType = arg1;
35 uint64_t ui64Key = 0;
36 ui64Key = bytes_to_num(datain, 6);
37
38 // variables
39 byte_t isOK = 0;
40 byte_t dataoutbuf[16];
41 uint8_t uid[10];
42 uint32_t cuid;
43 struct Crypto1State mpcs = {0, 0};
44 struct Crypto1State *pcs;
45 pcs = &mpcs;
46
47 // clear trace
48 clear_trace();
49 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
50
51 LED_A_ON();
52 LED_B_OFF();
53 LED_C_OFF();
54
55 while (true) {
56 if(!iso14443a_select_card(uid, NULL, &cuid)) {
57 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
58 break;
59 };
60
61 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
62 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
63 break;
64 };
65
66 if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
67 if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
68 break;
69 };
70
71 if(mifare_classic_halt(pcs, cuid)) {
72 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
73 break;
74 };
75
76 isOK = 1;
77 break;
78 }
79
80 // ----------------------------- crypto1 destroy
81 crypto1_destroy(pcs);
82
83 if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
84
85 LED_B_ON();
86 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
87 LED_B_OFF();
88
89 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
90 LEDsoff();
91 }
92
93 void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
94
95 bool turnOffField = (arg0 == 1);
96
97 LED_A_ON(); LED_B_OFF(); LED_C_OFF();
98 clear_trace();
99 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
100
101 if(!iso14443a_select_card(NULL, NULL, NULL)) {
102 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
103 OnError(0);
104 return;
105 };
106
107 if(!mifare_ultra_auth(keybytes)){
108 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed");
109 OnError(1);
110 return;
111 }
112
113 if (turnOffField) {
114 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
115 LEDsoff();
116 }
117 cmd_send(CMD_ACK,1,0,0,0,0);
118 }
119
120 // Arg0 = BlockNo,
121 // Arg1 = UsePwd bool
122 // datain = PWD bytes,
123 void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
124 {
125 uint8_t blockNo = arg0;
126 byte_t dataout[16] = {0x00};
127 bool useKey = (arg1 == 1); //UL_C
128 bool usePwd = (arg1 == 2); //UL_EV1/NTAG
129
130 LEDsoff();
131 LED_A_ON();
132 clear_trace();
133 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
134
135 int len = iso14443a_select_card(NULL, NULL, NULL);
136 if(!len) {
137 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
138 OnError(1);
139 return;
140 }
141
142 // UL-C authentication
143 if ( useKey ) {
144 uint8_t key[16] = {0x00};
145 memcpy(key, datain, sizeof(key) );
146
147 if ( !mifare_ultra_auth(key) ) {
148 OnError(1);
149 return;
150 }
151 }
152
153 // UL-EV1 / NTAG authentication
154 if ( usePwd ) {
155 uint8_t pwd[4] = {0x00};
156 memcpy(pwd, datain, 4);
157 uint8_t pack[4] = {0,0,0,0};
158 if (!mifare_ul_ev1_auth(pwd, pack)) {
159 OnError(1);
160 return;
161 }
162 }
163
164 if( mifare_ultra_readblock(blockNo, dataout) ) {
165 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error");
166 OnError(2);
167 return;
168 }
169
170 if( mifare_ultra_halt() ) {
171 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error");
172 OnError(3);
173 return;
174 }
175
176 cmd_send(CMD_ACK,1,0,0,dataout,16);
177 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
178 LEDsoff();
179 }
180
181 //-----------------------------------------------------------------------------
182 // Select, Authenticate, Read a MIFARE tag.
183 // read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
184 //-----------------------------------------------------------------------------
185 void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
186 {
187 // params
188 uint8_t sectorNo = arg0;
189 uint8_t keyType = arg1;
190 uint64_t ui64Key = 0;
191 ui64Key = bytes_to_num(datain, 6);
192
193 // variables
194 byte_t isOK = 0;
195 byte_t dataoutbuf[16 * 16];
196 uint8_t uid[10];
197 uint32_t cuid;
198 struct Crypto1State mpcs = {0, 0};
199 struct Crypto1State *pcs;
200 pcs = &mpcs;
201
202 // clear trace
203 clear_trace();
204
205 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
206
207 LED_A_ON();
208 LED_B_OFF();
209 LED_C_OFF();
210
211 isOK = 1;
212 if(!iso14443a_select_card(uid, NULL, &cuid)) {
213 isOK = 0;
214 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
215 }
216
217
218 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
219 isOK = 0;
220 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
221 }
222
223 for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
224 if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
225 isOK = 0;
226 if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
227 break;
228 }
229 }
230
231 if(mifare_classic_halt(pcs, cuid)) {
232 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
233 }
234
235 // ----------------------------- crypto1 destroy
236 crypto1_destroy(pcs);
237
238 if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
239
240 LED_B_ON();
241 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo));
242 LED_B_OFF();
243
244 // Thats it...
245 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
246 LEDsoff();
247 }
248
249 // arg0 = blockNo (start)
250 // arg1 = Pages (number of blocks)
251 // arg2 = useKey
252 // datain = KEY bytes
253 void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
254 {
255 // free eventually allocated BigBuf memory
256 BigBuf_free();
257 clear_trace();
258
259 // params
260 uint8_t blockNo = arg0;
261 uint16_t blocks = arg1;
262 bool useKey = (arg2 == 1); //UL_C
263 bool usePwd = (arg2 == 2); //UL_EV1/NTAG
264 uint32_t countblocks = 0;
265 uint8_t *dataout = BigBuf_malloc(CARD_MEMORY_SIZE);
266 if (dataout == NULL){
267 Dbprintf("out of memory");
268 OnError(1);
269 return;
270 }
271
272 LEDsoff();
273 LED_A_ON();
274 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
275
276 int len = iso14443a_select_card(NULL, NULL, NULL);
277 if (!len) {
278 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len);
279 OnError(1);
280 return;
281 }
282
283 // UL-C authentication
284 if ( useKey ) {
285 uint8_t key[16] = {0x00};
286 memcpy(key, datain, sizeof(key) );
287
288 if ( !mifare_ultra_auth(key) ) {
289 OnError(1);
290 return;
291 }
292 }
293
294 // UL-EV1 / NTAG authentication
295 if (usePwd) {
296 uint8_t pwd[4] = {0x00};
297 memcpy(pwd, datain, sizeof(pwd));
298 uint8_t pack[4] = {0,0,0,0};
299
300 if (!mifare_ul_ev1_auth(pwd, pack)){
301 OnError(1);
302 return;
303 }
304 }
305
306 for (int i = 0; i < blocks; i++){
307 if ((i*4) + 4 >= CARD_MEMORY_SIZE) {
308 Dbprintf("Data exceeds buffer!!");
309 break;
310 }
311
312 len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i);
313
314 if (len) {
315 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block %d error",i);
316 // if no blocks read - error out
317 if (i==0){
318 OnError(2);
319 return;
320 } else {
321 //stop at last successful read block and return what we got
322 break;
323 }
324 } else {
325 countblocks++;
326 }
327 }
328
329 len = mifare_ultra_halt();
330 if (len) {
331 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error");
332 OnError(3);
333 return;
334 }
335
336 if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks);
337
338 countblocks *= 4;
339
340 cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0);
341 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
342 LEDsoff();
343 BigBuf_free();
344 }
345
346 //-----------------------------------------------------------------------------
347 // Select, Authenticate, Write a MIFARE tag.
348 // read block
349 //-----------------------------------------------------------------------------
350 void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
351 {
352 // params
353 uint8_t blockNo = arg0;
354 uint8_t keyType = arg1;
355 uint64_t ui64Key = 0;
356 byte_t blockdata[16];
357
358 ui64Key = bytes_to_num(datain, 6);
359 memcpy(blockdata, datain + 10, 16);
360
361 // variables
362 byte_t isOK = 0;
363 uint8_t uid[10];
364 uint32_t cuid;
365 struct Crypto1State mpcs = {0, 0};
366 struct Crypto1State *pcs;
367 pcs = &mpcs;
368
369 // clear trace
370 clear_trace();
371
372 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
373
374 LED_A_ON();
375 LED_B_OFF();
376 LED_C_OFF();
377
378 while (true) {
379 if(!iso14443a_select_card(uid, NULL, &cuid)) {
380 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
381 break;
382 };
383
384 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
385 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
386 break;
387 };
388
389 if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
390 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
391 break;
392 };
393
394 if(mifare_classic_halt(pcs, cuid)) {
395 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
396 break;
397 };
398
399 isOK = 1;
400 break;
401 }
402
403 // ----------------------------- crypto1 destroy
404 crypto1_destroy(pcs);
405
406 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
407
408 LED_B_ON();
409 cmd_send(CMD_ACK,isOK,0,0,0,0);
410 LED_B_OFF();
411
412
413 // Thats it...
414 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
415 LEDsoff();
416 }
417
418 /* // Command not needed but left for future testing
419 void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
420 {
421 uint8_t blockNo = arg0;
422 byte_t blockdata[16] = {0x00};
423
424 memcpy(blockdata, datain, 16);
425
426 uint8_t uid[10] = {0x00};
427
428 LED_A_ON(); LED_B_OFF(); LED_C_OFF();
429
430 clear_trace();
431 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
432
433 if(!iso14443a_select_card(uid, NULL, NULL)) {
434 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
435 OnError(0);
436 return;
437 };
438
439 if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
440 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
441 OnError(0);
442 return; };
443
444 if(mifare_ultra_halt()) {
445 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
446 OnError(0);
447 return;
448 };
449
450 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
451
452 cmd_send(CMD_ACK,1,0,0,0,0);
453 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
454 LEDsoff();
455 }
456 */
457
458 // Arg0 : Block to write to.
459 // Arg1 : 0 = use no authentication.
460 // 1 = use 0x1A authentication.
461 // 2 = use 0x1B authentication.
462 // datain : 4 first bytes is data to be written.
463 // : 4/16 next bytes is authentication key.
464 void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
465 {
466 uint8_t blockNo = arg0;
467 bool useKey = (arg1 == 1); //UL_C
468 bool usePwd = (arg1 == 2); //UL_EV1/NTAG
469 byte_t blockdata[4] = {0x00};
470
471 memcpy(blockdata, datain,4);
472
473 LEDsoff();
474 LED_A_ON();
475 clear_trace();
476 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
477
478 if(!iso14443a_select_card(NULL, NULL, NULL)) {
479 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
480 OnError(0);
481 return;
482 };
483
484 // UL-C authentication
485 if ( useKey ) {
486 uint8_t key[16] = {0x00};
487 memcpy(key, datain+4, sizeof(key) );
488
489 if ( !mifare_ultra_auth(key) ) {
490 OnError(1);
491 return;
492 }
493 }
494
495 // UL-EV1 / NTAG authentication
496 if (usePwd) {
497 uint8_t pwd[4] = {0x00};
498 memcpy(pwd, datain+4, 4);
499 uint8_t pack[4] = {0,0,0,0};
500 if (!mifare_ul_ev1_auth(pwd, pack)) {
501 OnError(1);
502 return;
503 }
504 }
505
506 if(mifare_ultra_writeblock(blockNo, blockdata)) {
507 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
508 OnError(0);
509 return;
510 };
511
512 if(mifare_ultra_halt()) {
513 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
514 OnError(0);
515 return;
516 };
517
518 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
519
520 cmd_send(CMD_ACK,1,0,0,0,0);
521 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
522 LEDsoff();
523 }
524
525 void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
526
527 uint8_t pwd[16] = {0x00};
528 byte_t blockdata[4] = {0x00};
529
530 memcpy(pwd, datain, 16);
531
532 LED_A_ON(); LED_B_OFF(); LED_C_OFF();
533 clear_trace();
534 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
535
536 if(!iso14443a_select_card(NULL, NULL, NULL)) {
537 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
538 OnError(0);
539 return;
540 };
541
542 blockdata[0] = pwd[7];
543 blockdata[1] = pwd[6];
544 blockdata[2] = pwd[5];
545 blockdata[3] = pwd[4];
546 if(mifare_ultra_writeblock( 44, blockdata)) {
547 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
548 OnError(44);
549 return;
550 };
551
552 blockdata[0] = pwd[3];
553 blockdata[1] = pwd[2];
554 blockdata[2] = pwd[1];
555 blockdata[3] = pwd[0];
556 if(mifare_ultra_writeblock( 45, blockdata)) {
557 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
558 OnError(45);
559 return;
560 };
561
562 blockdata[0] = pwd[15];
563 blockdata[1] = pwd[14];
564 blockdata[2] = pwd[13];
565 blockdata[3] = pwd[12];
566 if(mifare_ultra_writeblock( 46, blockdata)) {
567 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
568 OnError(46);
569 return;
570 };
571
572 blockdata[0] = pwd[11];
573 blockdata[1] = pwd[10];
574 blockdata[2] = pwd[9];
575 blockdata[3] = pwd[8];
576 if(mifare_ultra_writeblock( 47, blockdata)) {
577 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
578 OnError(47);
579 return;
580 };
581
582 if(mifare_ultra_halt()) {
583 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
584 OnError(0);
585 return;
586 };
587
588 cmd_send(CMD_ACK,1,0,0,0,0);
589 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
590 LEDsoff();
591 }
592
593 // Return 1 if the nonce is invalid else return 0
594 int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
595 return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \
596 (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \
597 (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;
598 }
599
600
601 //-----------------------------------------------------------------------------
602 // MIFARE nested authentication.
603 //
604 //-----------------------------------------------------------------------------
605 void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain)
606 {
607 // params
608 uint8_t blockNo = arg0 & 0xff;
609 uint8_t keyType = (arg0 >> 8) & 0xff;
610 uint8_t targetBlockNo = arg1 & 0xff;
611 uint8_t targetKeyType = (arg1 >> 8) & 0xff;
612 uint64_t ui64Key = 0;
613
614 ui64Key = bytes_to_num(datain, 6);
615
616 // variables
617 uint16_t rtr, i, j, len;
618 uint16_t davg;
619 static uint16_t dmin, dmax;
620 uint8_t uid[10];
621 uint32_t cuid, nt1, nt2, nttmp, nttest, ks1;
622 uint8_t par[1];
623 uint32_t target_nt[2], target_ks[2];
624
625 uint8_t par_array[4];
626 uint16_t ncount = 0;
627 struct Crypto1State mpcs = {0, 0};
628 struct Crypto1State *pcs;
629 pcs = &mpcs;
630 uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
631
632 uint32_t auth1_time, auth2_time;
633 static uint16_t delta_time;
634
635 // free eventually allocated BigBuf memory
636 BigBuf_free();
637 // clear trace
638 clear_trace();
639 set_tracing(false);
640
641 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
642
643 LED_A_ON();
644 LED_C_OFF();
645
646
647 // statistics on nonce distance
648 int16_t isOK = 0;
649 #define NESTED_MAX_TRIES 12
650 uint16_t unsuccessfull_tries = 0;
651 if (calibrate) { // for first call only. Otherwise reuse previous calibration
652 LED_B_ON();
653 WDT_HIT();
654
655 davg = dmax = 0;
656 dmin = 2000;
657 delta_time = 0;
658
659 for (rtr = 0; rtr < 17; rtr++) {
660
661 // Test if the action was cancelled
662 if(BUTTON_PRESS()) {
663 isOK = -2;
664 break;
665 }
666
667 // prepare next select. No need to power down the card.
668 if(mifare_classic_halt(pcs, cuid)) {
669 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
670 rtr--;
671 continue;
672 }
673
674 if(!iso14443a_select_card(uid, NULL, &cuid)) {
675 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
676 rtr--;
677 continue;
678 };
679
680 auth1_time = 0;
681 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
682 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
683 rtr--;
684 continue;
685 };
686
687 if (delta_time) {
688 auth2_time = auth1_time + delta_time;
689 } else {
690 auth2_time = 0;
691 }
692 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {
693 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");
694 rtr--;
695 continue;
696 };
697
698 nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
699 for (i = 101; i < 1200; i++) {
700 nttmp = prng_successor(nttmp, 1);
701 if (nttmp == nt2) break;
702 }
703
704 if (i != 1200) {
705 if (rtr != 0) {
706 davg += i;
707 dmin = MIN(dmin, i);
708 dmax = MAX(dmax, i);
709 }
710 else {
711 delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing
712 }
713 if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i);
714 } else {
715 unsuccessfull_tries++;
716 if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable)
717 isOK = -3;
718 }
719 }
720 }
721
722 davg = (davg + (rtr - 1)/2) / (rtr - 1);
723
724 if (MF_DBGLEVEL >= 3) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, dmin, dmax, davg, delta_time);
725
726 dmin = davg - 2;
727 dmax = davg + 2;
728
729 LED_B_OFF();
730
731 }
732 // -------------------------------------------------------------------------------------------------
733
734 LED_C_ON();
735
736 // get crypted nonces for target sector
737 for(i=0; i < 2 && !isOK; i++) { // look for exactly two different nonces
738
739 target_nt[i] = 0;
740 while(target_nt[i] == 0) { // continue until we have an unambiguous nonce
741
742 // prepare next select. No need to power down the card.
743 if(mifare_classic_halt(pcs, cuid)) {
744 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
745 continue;
746 }
747
748 if(!iso14443a_select_card(uid, NULL, &cuid)) {
749 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
750 continue;
751 };
752
753 auth1_time = 0;
754 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
755 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
756 continue;
757 };
758
759 // nested authentication
760 auth2_time = auth1_time + delta_time;
761 len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);
762 if (len != 4) {
763 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);
764 continue;
765 };
766
767 nt2 = bytes_to_num(receivedAnswer, 4);
768 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]);
769
770 // Parity validity check
771 for (j = 0; j < 4; j++) {
772 par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01));
773 }
774
775 ncount = 0;
776 nttest = prng_successor(nt1, dmin - 1);
777 for (j = dmin; j < dmax + 1; j++) {
778 nttest = prng_successor(nttest, 1);
779 ks1 = nt2 ^ nttest;
780
781 if (valid_nonce(nttest, nt2, ks1, par_array)){
782 if (ncount > 0) { // we are only interested in disambiguous nonces, try again
783 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);
784 target_nt[i] = 0;
785 break;
786 }
787 target_nt[i] = nttest;
788 target_ks[i] = ks1;
789 ncount++;
790 if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces
791 target_nt[i] = 0;
792 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);
793 break;
794 }
795 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j);
796 }
797 }
798 if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1);
799 }
800 }
801
802 LED_C_OFF();
803
804 // ----------------------------- crypto1 destroy
805 crypto1_destroy(pcs);
806
807 byte_t buf[4 + 4 * 4];
808 memcpy(buf, &cuid, 4);
809 memcpy(buf+4, &target_nt[0], 4);
810 memcpy(buf+8, &target_ks[0], 4);
811 memcpy(buf+12, &target_nt[1], 4);
812 memcpy(buf+16, &target_ks[1], 4);
813
814 LED_B_ON();
815 cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));
816 LED_B_OFF();
817
818 if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");
819
820 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
821 LEDsoff();
822 set_tracing(TRUE);
823 }
824
825 //-----------------------------------------------------------------------------
826 // MIFARE check keys. key count up to 85.
827 //
828 //-----------------------------------------------------------------------------
829 void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
830 {
831 // params
832 uint8_t blockNo = arg0;
833 uint8_t keyType = arg1;
834 uint8_t keyCount = arg2;
835 uint64_t ui64Key = 0;
836
837 // variables
838 int i;
839 byte_t isOK = 0;
840 uint8_t uid[10];
841 uint32_t cuid;
842 struct Crypto1State mpcs = {0, 0};
843 struct Crypto1State *pcs;
844 pcs = &mpcs;
845
846 // clear debug level
847 int OLD_MF_DBGLEVEL = MF_DBGLEVEL;
848 MF_DBGLEVEL = MF_DBG_NONE;
849
850 // clear trace
851 clear_trace();
852 set_tracing(TRUE);
853
854 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
855
856 LED_A_ON();
857 LED_B_OFF();
858 LED_C_OFF();
859
860 for (i = 0; i < keyCount; i++) {
861 if(mifare_classic_halt(pcs, cuid)) {
862 if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");
863 }
864
865 if(!iso14443a_select_card(uid, NULL, &cuid)) {
866 if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");
867 break;
868 };
869
870 ui64Key = bytes_to_num(datain + i * 6, 6);
871 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
872 continue;
873 };
874
875 isOK = 1;
876 break;
877 }
878
879 // ----------------------------- crypto1 destroy
880 crypto1_destroy(pcs);
881
882 LED_B_ON();
883 cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);
884 LED_B_OFF();
885
886 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
887 LEDsoff();
888
889 // restore debug level
890 MF_DBGLEVEL = OLD_MF_DBGLEVEL;
891 }
892
893 //-----------------------------------------------------------------------------
894 // MIFARE commands set debug level
895 //
896 //-----------------------------------------------------------------------------
897 void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
898 MF_DBGLEVEL = arg0;
899 Dbprintf("Debug level: %d", MF_DBGLEVEL);
900 }
901
902 //-----------------------------------------------------------------------------
903 // Work with emulator memory
904 //
905 //-----------------------------------------------------------------------------
906 void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
907 emlClearMem();
908 }
909
910 void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
911 emlSetMem(datain, arg0, arg1); // data, block num, blocks count
912 }
913
914 void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
915 byte_t buf[USB_CMD_DATA_SIZE];
916 emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4)
917
918 LED_B_ON();
919 cmd_send(CMD_ACK,arg0,arg1,0,buf,USB_CMD_DATA_SIZE);
920 LED_B_OFF();
921 }
922
923 //-----------------------------------------------------------------------------
924 // Load a card into the emulator memory
925 //
926 //-----------------------------------------------------------------------------
927 void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
928 uint8_t numSectors = arg0;
929 uint8_t keyType = arg1;
930 uint64_t ui64Key = 0;
931 uint32_t cuid;
932 struct Crypto1State mpcs = {0, 0};
933 struct Crypto1State *pcs;
934 pcs = &mpcs;
935
936 // variables
937 byte_t dataoutbuf[16];
938 byte_t dataoutbuf2[16];
939 uint8_t uid[10];
940
941 // clear trace
942 clear_trace();
943 set_tracing(false);
944
945 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
946
947 LED_A_ON();
948 LED_B_OFF();
949 LED_C_OFF();
950
951 bool isOK = true;
952
953 if(!iso14443a_select_card(uid, NULL, &cuid)) {
954 isOK = false;
955 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
956 }
957
958 for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
959 ui64Key = emlGetKey(sectorNo, keyType);
960 if (sectorNo == 0){
961 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
962 isOK = false;
963 if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);
964 break;
965 }
966 } else {
967 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
968 isOK = false;
969 if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
970 break;
971 }
972 }
973
974 for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
975 if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
976 isOK = false;
977 if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
978 break;
979 };
980 if (isOK) {
981 if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
982 emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
983 } else { // sector trailer, keep the keys, set only the AC
984 emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
985 memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
986 emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
987 }
988 }
989 }
990
991 }
992
993 if(mifare_classic_halt(pcs, cuid)) {
994 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
995 };
996
997 // ----------------------------- crypto1 destroy
998 crypto1_destroy(pcs);
999
1000 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1001 LEDsoff();
1002
1003 if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED");
1004
1005 }
1006
1007
1008 //-----------------------------------------------------------------------------
1009 // Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
1010 //
1011 //-----------------------------------------------------------------------------
1012 void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
1013
1014 // params
1015 uint8_t needWipe = arg0;
1016 // bit 0 - need get UID
1017 // bit 1 - need wupC
1018 // bit 2 - need HALT after sequence
1019 // bit 3 - need init FPGA and field before sequence
1020 // bit 4 - need reset FPGA and LED
1021 uint8_t workFlags = arg1;
1022 uint8_t blockNo = arg2;
1023
1024 // card commands
1025 uint8_t wupC1[] = { 0x40 };
1026 uint8_t wupC2[] = { 0x43 };
1027 uint8_t wipeC[] = { 0x41 };
1028
1029 // variables
1030 byte_t isOK = 0;
1031 uint8_t uid[10] = {0x00};
1032 uint8_t d_block[18] = {0x00};
1033 uint32_t cuid;
1034
1035 uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
1036 uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
1037
1038 // reset FPGA and LED
1039 if (workFlags & 0x08) {
1040 LED_A_ON();
1041 LED_B_OFF();
1042 LED_C_OFF();
1043
1044 clear_trace();
1045 set_tracing(TRUE);
1046 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
1047 }
1048
1049 while (true) {
1050
1051 // get UID from chip
1052 if (workFlags & 0x01) {
1053 if(!iso14443a_select_card(uid, NULL, &cuid)) {
1054 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
1055 break;
1056 };
1057
1058 if(mifare_classic_halt(NULL, cuid)) {
1059 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
1060 break;
1061 };
1062 };
1063
1064 // reset chip
1065 if (needWipe){
1066 ReaderTransmitBitsPar(wupC1,7,0, NULL);
1067 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1068 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
1069 break;
1070 };
1071
1072 ReaderTransmit(wipeC, sizeof(wipeC), NULL);
1073 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1074 if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
1075 break;
1076 };
1077
1078 if(mifare_classic_halt(NULL, cuid)) {
1079 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
1080 break;
1081 };
1082 };
1083
1084 // write block
1085 if (workFlags & 0x02) {
1086 ReaderTransmitBitsPar(wupC1,7,0, NULL);
1087 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1088 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
1089 break;
1090 };
1091
1092 ReaderTransmit(wupC2, sizeof(wupC2), NULL);
1093 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1094 if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
1095 break;
1096 };
1097 }
1098
1099 if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
1100 if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
1101 break;
1102 };
1103
1104 memcpy(d_block, datain, 16);
1105 AppendCrc14443a(d_block, 16);
1106
1107 ReaderTransmit(d_block, sizeof(d_block), NULL);
1108 if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
1109 if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
1110 break;
1111 };
1112
1113 if (workFlags & 0x04) {
1114 if (mifare_classic_halt(NULL, cuid)) {
1115 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
1116 break;
1117 };
1118 }
1119
1120 isOK = 1;
1121 break;
1122 }
1123
1124 LED_B_ON();
1125 cmd_send(CMD_ACK,isOK,0,0,uid,4);
1126 LED_B_OFF();
1127
1128 if ((workFlags & 0x10) || (!isOK)) {
1129 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1130 LEDsoff();
1131 }
1132 }
1133
1134
1135 void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
1136
1137 // params
1138 // bit 1 - need wupC
1139 // bit 2 - need HALT after sequence
1140 // bit 3 - need init FPGA and field before sequence
1141 // bit 4 - need reset FPGA and LED
1142 uint8_t workFlags = arg0;
1143 uint8_t blockNo = arg2;
1144
1145 // card commands
1146 uint8_t wupC1[] = { 0x40 };
1147 uint8_t wupC2[] = { 0x43 };
1148
1149 // variables
1150 byte_t isOK = 0;
1151 uint8_t data[18] = {0x00};
1152 uint32_t cuid = 0;
1153
1154 uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
1155 uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
1156
1157 if (workFlags & 0x08) {
1158 LED_A_ON();
1159 LED_B_OFF();
1160 LED_C_OFF();
1161
1162 clear_trace();
1163 set_tracing(TRUE);
1164 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
1165 }
1166
1167 while (true) {
1168 if (workFlags & 0x02) {
1169 ReaderTransmitBitsPar(wupC1,7,0, NULL);
1170 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1171 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
1172 break;
1173 };
1174
1175 ReaderTransmit(wupC2, sizeof(wupC2), NULL);
1176 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1177 if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
1178 break;
1179 };
1180 }
1181
1182 // read block
1183 if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) {
1184 if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error");
1185 break;
1186 };
1187 memcpy(data, receivedAnswer, 18);
1188
1189 if (workFlags & 0x04) {
1190 if (mifare_classic_halt(NULL, cuid)) {
1191 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
1192 break;
1193 };
1194 }
1195
1196 isOK = 1;
1197 break;
1198 }
1199
1200 LED_B_ON();
1201 cmd_send(CMD_ACK,isOK,0,0,data,18);
1202 LED_B_OFF();
1203
1204 if ((workFlags & 0x10) || (!isOK)) {
1205 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1206 LEDsoff();
1207 }
1208 }
1209
1210 void MifareCIdent(){
1211
1212 // card commands
1213 uint8_t wupC1[] = { 0x40 };
1214 uint8_t wupC2[] = { 0x43 };
1215
1216 // variables
1217 byte_t isOK = 1;
1218
1219 uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
1220 uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
1221
1222 ReaderTransmitBitsPar(wupC1,7,0, NULL);
1223 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1224 isOK = 0;
1225 };
1226
1227 ReaderTransmit(wupC2, sizeof(wupC2), NULL);
1228 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
1229 isOK = 0;
1230 };
1231
1232 if (mifare_classic_halt(NULL, 0)) {
1233 isOK = 0;
1234 };
1235
1236 cmd_send(CMD_ACK,isOK,0,0,0,0);
1237 }
1238
1239 //
1240 // DESFIRE
1241 //
1242
1243 void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
1244
1245 byte_t dataout[11] = {0x00};
1246 uint8_t uid[10] = {0x00};
1247 uint32_t cuid;
1248
1249 clear_trace();
1250 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
1251
1252 int len = iso14443a_select_card(uid, NULL, &cuid);
1253 if(!len) {
1254 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
1255 OnError(1);
1256 return;
1257 };
1258
1259 if(mifare_desfire_des_auth1(cuid, dataout)){
1260 if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication part1: Fail.");
1261 OnError(4);
1262 return;
1263 }
1264
1265 if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED");
1266 cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout));
1267 }
1268
1269 void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
1270
1271 uint32_t cuid = arg0;
1272 uint8_t key[16] = {0x00};
1273 byte_t isOK = 0;
1274 byte_t dataout[12] = {0x00};
1275
1276 memcpy(key, datain, 16);
1277
1278 isOK = mifare_desfire_des_auth2(cuid, key, dataout);
1279
1280 if( isOK) {
1281 if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed");
1282 OnError(4);
1283 return;
1284 }
1285
1286 if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED");
1287
1288 cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout));
1289 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1290 LEDsoff();
1291 }
1292
1293 void OnSuccess(){
1294 pcb_blocknum = 0;
1295 ReaderTransmit(deselect_cmd, 3 , NULL);
1296 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1297 LEDsoff();
1298 }
1299
1300 void OnError(uint8_t reason){
1301 pcb_blocknum = 0;
1302 ReaderTransmit(deselect_cmd, 3 , NULL);
1303 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1304 cmd_send(CMD_ACK,0,reason,0,0,0);
1305 LEDsoff();
1306 }
Impressum, Datenschutz