]>
cvs.zerfleddert.de Git - proxmark3-svn/blob - client/mifarehost.c
3e8362c564ffa525ade6950be0a8dd787c330701
   2 // people from mifare@nethemba.com, 2010 
   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 
   7 //----------------------------------------------------------------------------- 
   9 //----------------------------------------------------------------------------- 
  15 #include "mifarehost.h" 
  16 #include "proxmark3.h" 
  17 //#include "radixsort.h" 
  21 int compar_int(const void * a
, const void * b
) { 
  22         // didn't work: (the result is truncated to 32 bits) 
  23         //return (*(uint64_t*)b - *(uint64_t*)a); 
  26         if (*(uint64_t*)b 
> *(uint64_t*)a
) return 1; 
  27         if (*(uint64_t*)b 
< *(uint64_t*)a
) return -1;    
  30         //return (*(uint64_t*)b > *(uint64_t*)a) - (*(uint64_t*)b < *(uint64_t*)a); 
  33 // Compare 16 Bits out of cryptostate 
  34 int Compare16Bits(const void * a
, const void * b
) { 
  35          if ((*(uint64_t*)b 
& 0x00ff000000ff0000) > (*(uint64_t*)a 
& 0x00ff000000ff0000)) return 1;      
  36          if ((*(uint64_t*)b 
& 0x00ff000000ff0000) < (*(uint64_t*)a 
& 0x00ff000000ff0000)) return -1; 
  40                 ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) 
  42                 ((*(uint64_t*)b & 0x00ff000000ff0000) < (*(uint64_t*)a & 0x00ff000000ff0000)) 
  50                         struct Crypto1State 
*slhead
; 
  54                         struct Crypto1State 
*sltail
; 
  66 // wrapper function for multi-threaded lfsr_recovery32 
  67 void* nested_worker_thread(void *arg
) 
  69         struct Crypto1State 
*p1
; 
  70         StateList_t 
*statelist 
= arg
; 
  71         statelist
->head
.slhead 
= lfsr_recovery32(statelist
->ks1
, statelist
->nt 
^ statelist
->uid
);        
  73         for (p1 
= statelist
->head
.slhead
; *(uint64_t *)p1 
!= 0; p1
++); 
  75         statelist
->len 
= p1 
- statelist
->head
.slhead
; 
  76         statelist
->tail
.sltail 
= --p1
; 
  77         qsort(statelist
->head
.slhead
, statelist
->len
, sizeof(uint64_t), Compare16Bits
); 
  78         return statelist
->head
.slhead
; 
  81 int mfnested(uint8_t blockNo
, uint8_t keyType
, uint8_t * key
, uint8_t trgBlockNo
, uint8_t trgKeyType
, uint8_t * resultKey
, bool calibrate
)  
  86         StateList_t statelists
[2]; 
  87         struct Crypto1State 
*p1
, *p2
, *p3
, *p4
; 
  89         UsbCommand c 
= {CMD_MIFARE_NESTED
, {blockNo 
+ keyType 
* 0x100, trgBlockNo 
+ trgKeyType 
* 0x100, calibrate
}}; 
  90         memcpy(c
.d
.asBytes
, key
, 6); 
  93         if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) return -1; 
  95         // error during nested 
  96         if (resp
.arg
[0]) return resp
.arg
[0]; 
  98         memcpy(&uid
, resp
.d
.asBytes
, 4); 
 100         for (i 
= 0; i 
< 2; i
++) { 
 101                 statelists
[i
].blockNo 
= resp
.arg
[2] & 0xff; 
 102                 statelists
[i
].keyType 
= (resp
.arg
[2] >> 8) & 0xff; 
 103                 statelists
[i
].uid 
= uid
; 
 104                 memcpy(&statelists
[i
].nt
,  (void *)(resp
.d
.asBytes 
+ 4 + i 
* 8 + 0), 4); 
 105                 memcpy(&statelists
[i
].ks1
, (void *)(resp
.d
.asBytes 
+ 4 + i 
* 8 + 4), 4); 
 109         pthread_t thread_id
[2]; 
 111         // create and run worker threads 
 112         for (i 
= 0; i 
< 2; i
++) 
 113                 pthread_create(thread_id 
+ i
, NULL
, nested_worker_thread
, &statelists
[i
]); 
 115         // wait for threads to terminate: 
 116         for (i 
= 0; i 
< 2; i
++) 
 117                 pthread_join(thread_id
[i
], (void*)&statelists
[i
].head
.slhead
); 
 119         // the first 16 Bits of the cryptostate already contain part of our key. 
 120         // Create the intersection of the two lists based on these 16 Bits and 
 121         // roll back the cryptostate 
 122         p1 
= p3 
= statelists
[0].head
.slhead
;  
 123         p2 
= p4 
= statelists
[1].head
.slhead
; 
 125         while (p1 
<= statelists
[0].tail
.sltail 
&& p2 
<= statelists
[1].tail
.sltail
) { 
 126                 if (Compare16Bits(p1
, p2
) == 0) { 
 128                         struct Crypto1State savestate
, *savep 
= &savestate
; 
 130                         while(Compare16Bits(p1
, savep
) == 0 && p1 
<= statelists
[0].tail
.sltail
) { 
 132                                 lfsr_rollback_word(p3
, statelists
[0].nt 
^ statelists
[0].uid
, 0); 
 137                         while(Compare16Bits(p2
, savep
) == 0 && p2 
<= statelists
[1].tail
.sltail
) { 
 139                                 lfsr_rollback_word(p4
, statelists
[1].nt 
^ statelists
[1].uid
, 0); 
 145                         while (Compare16Bits(p1
, p2
) == -1) p1
++; 
 146                         while (Compare16Bits(p1
, p2
) == 1) p2
++; 
 150         p3
->even 
= 0; p3
->odd 
= 0; 
 151         p4
->even 
= 0; p4
->odd 
= 0; 
 152         statelists
[0].len 
= p3 
- statelists
[0].head
.slhead
; 
 153         statelists
[1].len 
= p4 
- statelists
[1].head
.slhead
; 
 154         statelists
[0].tail
.sltail
=--p3
; 
 155         statelists
[1].tail
.sltail
=--p4
; 
 157         // the statelists now contain possible keys. The key we are searching for must be in the 
 158         // intersection of both lists. Create the intersection: 
 159         qsort(statelists
[0].head
.keyhead
, statelists
[0].len
, sizeof(uint64_t), compar_int
); 
 160         qsort(statelists
[1].head
.keyhead
, statelists
[1].len
, sizeof(uint64_t), compar_int
); 
 162         uint64_t *p5
, *p6
, *p7
; 
 163         p5 
= p7 
= statelists
[0].head
.keyhead
;  
 164         p6 
= statelists
[1].head
.keyhead
; 
 166         while (p5 
<= statelists
[0].tail
.keytail 
&& p6 
<= statelists
[1].tail
.keytail
) { 
 167                 if (compar_int(p5
, p6
) == 0) { 
 172                         while (compar_int(p5
, p6
) == -1) p5
++; 
 173                         while (compar_int(p5
, p6
) == 1) p6
++; 
 176         statelists
[0].len 
= p7 
- statelists
[0].head
.keyhead
; 
 177         statelists
[0].tail
.keytail 
= --p7
; 
 179         uint32_t numOfCandidates 
= statelists
[0].len
; 
 180         if ( numOfCandidates 
== 0 ) goto out
; 
 182         memset(resultKey
, 0, 6); 
 185         // The list may still contain several key candidates. Test each of them with mfCheckKeys 
 186         // uint32_t max_keys = keycnt > (USB_CMD_DATA_SIZE/6) ? (USB_CMD_DATA_SIZE/6) : keycnt; 
 187         uint8_t keyBlock
[USB_CMD_DATA_SIZE
] = {0x00}; 
 189         for (i 
= 0; i 
< numOfCandidates
; ++i
){ 
 190                 crypto1_get_lfsr(statelists
[0].head
.slhead 
+ i
, &key64
); 
 191                 num_to_bytes(key64
, 6, keyBlock 
+ i 
* 6); 
 194         if (!mfCheckKeys(statelists
[0].blockNo
, statelists
[0].keyType
, false, numOfCandidates
, keyBlock
, &key64
)) {              
 195                 free(statelists
[0].head
.slhead
); 
 196                 free(statelists
[1].head
.slhead
); 
 197                 num_to_bytes(key64
, 6, resultKey
); 
 199                 PrintAndLog("UID: %08x target block:%3u key type: %c  -- Found key [%012"llx
"]", 
 201                         (uint16_t)resp
.arg
[2] & 0xff, 
 202                         (resp
.arg
[2] >> 8) ? 'B' : 'A', 
 209         PrintAndLog("UID: %08x target block:%3u key type: %c", 
 211                         (uint16_t)resp
.arg
[2] & 0xff, 
 212                         (resp
.arg
[2] >> 8) ? 'B' : 'A' 
 215         free(statelists
[0].head
.slhead
); 
 216         free(statelists
[1].head
.slhead
); 
 220 int mfCheckKeys (uint8_t blockNo
, uint8_t keyType
, bool clear_trace
, uint8_t keycnt
, uint8_t * keyBlock
, uint64_t * key
){ 
 222         UsbCommand c 
= {CMD_MIFARE_CHKKEYS
, { (blockNo 
| (keyType
<<8)), clear_trace
, keycnt
}}; 
 223         memcpy(c
.d
.asBytes
, keyBlock
, 6 * keycnt
); 
 224         clearCommandBuffer(); 
 227         if (!WaitForResponseTimeout(CMD_ACK
, &resp
, 2500)) return 1; 
 228         if ((resp
.arg
[0] & 0xff) != 0x01) return 2; 
 229         *key 
= bytes_to_num(resp
.d
.asBytes
, 6); 
 235 int mfEmlGetMem(uint8_t *data
, int blockNum
, int blocksCount
) { 
 236         UsbCommand c 
= {CMD_MIFARE_EML_MEMGET
, {blockNum
, blocksCount
, 0}}; 
 237         clearCommandBuffer(); 
 240         if (!WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) return 1; 
 241         memcpy(data
, resp
.d
.asBytes
, blocksCount 
* 16); 
 245 int mfEmlSetMem(uint8_t *data
, int blockNum
, int blocksCount
) { 
 246         return mfEmlSetMem_xt(data
, blockNum
, blocksCount
, 16); 
 249 int mfEmlSetMem_xt(uint8_t *data
, int blockNum
, int blocksCount
, int blockBtWidth
) { 
 250         UsbCommand c 
= {CMD_MIFARE_EML_MEMSET
, {blockNum
, blocksCount
, blockBtWidth
}}; 
 251         memcpy(c
.d
.asBytes
, data
, blocksCount 
* blockBtWidth
);  
 252         clearCommandBuffer(); 
 258 int mfCSetUID(uint8_t *uid
, uint8_t *atqa
, uint8_t *sak
, uint8_t *oldUID
, uint8_t wipecard
) { 
 260         uint8_t params 
= MAGIC_SINGLE
; 
 262         memset(block0
, 0x00, sizeof(block0
)); 
 264         int old 
= mfCGetBlock(0, block0
, params
); 
 266                 PrintAndLog("old block 0:  %s", sprint_hex(block0
, sizeof(block0
))); 
 268                 PrintAndLog("Couldn't get old data. Will write over the last bytes of Block 0.");        
 270         // fill in the new values 
 272         memcpy(block0
, uid
, 4);  
 274         block0
[4] = block0
[0]^block0
[1]^block0
[2]^block0
[3]; 
 275         // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed) 
 279         if ( atqa 
!= NULL 
) { 
 283         PrintAndLog("new block 0:  %s", sprint_hex(block0
,16)); 
 285         if ( wipecard 
)          params 
|= MAGIC_WIPE
;   
 286         if ( oldUID 
== NULL
) params 
|= MAGIC_UID
; 
 288         return mfCSetBlock(0, block0
, oldUID
, params
); 
 291 int mfCSetBlock(uint8_t blockNo
, uint8_t *data
, uint8_t *uid
, uint8_t params
) { 
 294         UsbCommand c 
= {CMD_MIFARE_CSETBLOCK
, {params
, blockNo
, 0}}; 
 295         memcpy(c
.d
.asBytes
, data
, 16);  
 296         clearCommandBuffer(); 
 299         if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) { 
 300                 isOK  
= resp
.arg
[0] & 0xff; 
 302                         memcpy(uid
, resp
.d
.asBytes
, 4); 
 306                 PrintAndLog("Command execute timeout"); 
 312 int mfCGetBlock(uint8_t blockNo
, uint8_t *data
, uint8_t params
) { 
 314         UsbCommand c 
= {CMD_MIFARE_CGETBLOCK
, {params
, blockNo
, 0}};     
 315         clearCommandBuffer(); 
 318         if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) { 
 319                 isOK  
= resp
.arg
[0] & 0xff; 
 320                 memcpy(data
, resp
.d
.asBytes
, 16); 
 323                 PrintAndLog("Command execute timeout"); 
 330 // [iceman] so many global variables.... 
 333 static uint8_t trailerAccessBytes
[4] = {0x08, 0x77, 0x8F, 0x00}; 
 336 char logHexFileName
[FILE_PATH_SIZE
] = {0x00}; 
 337 static uint8_t traceCard
[4096] = {0x00}; 
 338 static char traceFileName
[FILE_PATH_SIZE
] = {0x00}; 
 339 static int traceState 
= TRACE_IDLE
; 
 340 static uint8_t traceCurBlock 
= 0; 
 341 static uint8_t traceCurKey 
= 0; 
 343 struct Crypto1State 
*traceCrypto1 
= NULL
; 
 344 struct Crypto1State 
*revstate 
= NULL
; 
 350 uint32_t uid 
= 0;     // serial number 
 351 uint32_t nt 
=0;      // tag challenge 
 352 uint32_t nr_enc 
=0;  // encrypted reader challenge 
 353 uint32_t ar_enc 
=0;  // encrypted reader response 
 354 uint32_t at_enc 
=0;  // encrypted tag response 
 356 int isTraceCardEmpty(void) { 
 357         return ((traceCard
[0] == 0) && (traceCard
[1] == 0) && (traceCard
[2] == 0) && (traceCard
[3] == 0)); 
 360 int isBlockEmpty(int blockN
) { 
 361         for (int i 
= 0; i 
< 16; i
++)  
 362                 if (traceCard
[blockN 
* 16 + i
] != 0) return 0; 
 367 int isBlockTrailer(int blockN
) { 
 368         return ((blockN 
& 0x03) == 0x03); 
 371 int loadTraceCard(uint8_t *tuid
) { 
 373         char buf
[64] = {0x00}; 
 374         uint8_t buf8
[64] = {0x00}; 
 377         if (!isTraceCardEmpty())  
 380         memset(traceCard
, 0x00, 4096); 
 381         memcpy(traceCard
, tuid 
+ 3, 4); 
 383         FillFileNameByUID(traceFileName
, tuid
, ".eml", 7); 
 385         f 
= fopen(traceFileName
, "r"); 
 392                 memset(buf
, 0, sizeof(buf
)); 
 393                 if (fgets(buf
, sizeof(buf
), f
) == NULL
) { 
 394                         PrintAndLog("File reading error."); 
 399                 if (strlen(buf
) < 32){ 
 401                         PrintAndLog("File content error. Block data must include 32 HEX symbols"); 
 405                 for (i 
= 0; i 
< 32; i 
+= 2) 
 406                         sscanf(&buf
[i
], "%02x", (unsigned int *)&buf8
[i 
/ 2]); 
 408                 memcpy(traceCard 
+ blockNum 
* 16, buf8
, 16); 
 417 int saveTraceCard(void) { 
 420         if ((!strlen(traceFileName
)) || (isTraceCardEmpty())) return 0; 
 422         f 
= fopen(traceFileName
, "w+"); 
 425         for (int i 
= 0; i 
< 64; i
++) {  // blocks 
 426                 for (int j 
= 0; j 
< 16; j
++)  // bytes 
 427                         fprintf(f
, "%02x", *(traceCard 
+ i 
* 16 + j
));  
 434 int mfTraceInit(uint8_t *tuid
, uint8_t *atqa
, uint8_t sak
, bool wantSaveToEmlFile
) { 
 437                 crypto1_destroy(traceCrypto1
); 
 441         if (wantSaveToEmlFile
)  
 444         traceCard
[4] = traceCard
[0] ^ traceCard
[1] ^ traceCard
[2] ^ traceCard
[3]; 
 446         memcpy(&traceCard
[6], atqa
, 2); 
 448         uid 
= bytes_to_num(tuid 
+ 3, 4); 
 450         traceState 
= TRACE_IDLE
; 
 455 void mf_crypto1_decrypt(struct Crypto1State 
*pcs
, uint8_t *data
, int len
, bool isEncrypted
){ 
 460                 for (i 
= 0; i 
< len
; i
++) 
 461                         data
[i
] = crypto1_byte(pcs
, 0x00, isEncrypted
) ^ data
[i
]; 
 464                 bt 
|= (crypto1_bit(pcs
, 0, isEncrypted
) ^ BIT(data
[0], 0)) << 0; 
 465                 bt 
|= (crypto1_bit(pcs
, 0, isEncrypted
) ^ BIT(data
[0], 1)) << 1; 
 466                 bt 
|= (crypto1_bit(pcs
, 0, isEncrypted
) ^ BIT(data
[0], 2)) << 2; 
 467                 bt 
|= (crypto1_bit(pcs
, 0, isEncrypted
) ^ BIT(data
[0], 3)) << 3;                         
 473 int mfTraceDecode(uint8_t *data_src
, int len
, bool wantSaveToEmlFile
) { 
 476         memset(data
, 0x00, sizeof(data
)); 
 478         if (traceState 
== TRACE_ERROR
) return 1; 
 481                 traceState 
= TRACE_ERROR
; 
 485         memcpy(data
, data_src
, len
); 
 486         if ((traceCrypto1
) && ((traceState 
== TRACE_IDLE
) || (traceState 
> TRACE_AUTH_OK
))) { 
 487                 mf_crypto1_decrypt(traceCrypto1
, data
, len
, 0); 
 488                 PrintAndLog("dec> %s", sprint_hex(data
, len
)); 
 489                 AddLogHex(logHexFileName
, "dec> ", data
, len
);  
 492         switch (traceState
) { 
 494                 // check packet crc16! 
 495                 if ((len 
>= 4) && (!CheckCrc14443(CRC_14443_A
, data
, len
))) { 
 496                         PrintAndLog("dec> CRC ERROR!!!"); 
 497                         AddLogLine(logHexFileName
, "dec> ", "CRC ERROR!!!");  
 498                         traceState 
= TRACE_ERROR
;  // do not decrypt the next commands 
 503                 if ((len 
== 4) && ((data
[0] == MIFARE_AUTH_KEYA
) || (data
[0] == MIFARE_AUTH_KEYB
))) { 
 504                         traceState 
= TRACE_AUTH1
; 
 505                         traceCurBlock 
= data
[1]; 
 506                         traceCurKey 
= data
[0] == 60 ? 1:0; 
 511                 if ((len 
==4) && ((data
[0] == ISO14443A_CMD_READBLOCK
))) { 
 512                         traceState 
= TRACE_READ_DATA
; 
 513                         traceCurBlock 
= data
[1]; 
 518                 if ((len 
==4) && ((data
[0] == ISO14443A_CMD_WRITEBLOCK
))) { 
 519                         traceState 
= TRACE_WRITE_OK
; 
 520                         traceCurBlock 
= data
[1]; 
 525                 if ((len 
==4) && ((data
[0] == ISO14443A_CMD_HALT
) && (data
[1] == 0x00))) { 
 526                         traceState 
= TRACE_ERROR
;  // do not decrypt the next commands 
 533         case TRACE_READ_DATA
:  
 535                         traceState 
= TRACE_IDLE
; 
 537                         if (isBlockTrailer(traceCurBlock
)) { 
 538                                 memcpy(traceCard 
+ traceCurBlock 
* 16 + 6, data 
+ 6, 4); 
 540                                 memcpy(traceCard 
+ traceCurBlock 
* 16, data
, 16); 
 542                         if (wantSaveToEmlFile
) saveTraceCard(); 
 545                         traceState 
= TRACE_ERROR
; 
 551                 if ((len 
== 1) && (data
[0] == 0x0a)) { 
 552                         traceState 
= TRACE_WRITE_DATA
; 
 556                         traceState 
= TRACE_ERROR
; 
 561         case TRACE_WRITE_DATA
:  
 563                         traceState 
= TRACE_IDLE
; 
 565                         memcpy(traceCard 
+ traceCurBlock 
* 16, data
, 16); 
 566                         if (wantSaveToEmlFile
) saveTraceCard(); 
 569                         traceState 
= TRACE_ERROR
; 
 576                         traceState 
= TRACE_AUTH2
; 
 577                         nt 
= bytes_to_num(data
, 4); 
 580                         traceState 
= TRACE_ERROR
; 
 587                         traceState 
= TRACE_AUTH_OK
; 
 589                         nr_enc 
= bytes_to_num(data
, 4); 
 590                         ar_enc 
= bytes_to_num(data 
+ 4, 4); 
 593                         traceState 
= TRACE_ERROR
; 
 600                         traceState 
= TRACE_IDLE
; 
 602                         at_enc 
= bytes_to_num(data
, 4); 
 605                         ks2 
= ar_enc 
^ prng_successor(nt
, 64); 
 606                         ks3 
= at_enc 
^ prng_successor(nt
, 96); 
 607                         revstate 
= lfsr_recovery64(ks2
, ks3
); 
 608                         lfsr_rollback_word(revstate
, 0, 0); 
 609                         lfsr_rollback_word(revstate
, 0, 0); 
 610                         lfsr_rollback_word(revstate
, nr_enc
, 1); 
 611                         lfsr_rollback_word(revstate
, uid 
^ nt
, 0); 
 613                         crypto1_get_lfsr(revstate
, &key
); 
 614                         printf("Key: %012"llx
"\n",key
); 
 615                         AddLogUint64(logHexFileName
, "key: ", key
);  
 617                         int blockShift 
= ((traceCurBlock 
& 0xFC) + 3) * 16; 
 618                         if (isBlockEmpty((traceCurBlock 
& 0xFC) + 3)) memcpy(traceCard 
+ blockShift 
+ 6, trailerAccessBytes
, 4); 
 621                                 num_to_bytes(key
, 6, traceCard 
+ blockShift 
+ 10); 
 623                                 num_to_bytes(key
, 6, traceCard 
+ blockShift
); 
 625                         if (wantSaveToEmlFile
) saveTraceCard(); 
 628                                 crypto1_destroy(traceCrypto1
); 
 631                         // set cryptosystem state 
 632                         traceCrypto1 
= lfsr_recovery64(ks2
, ks3
); 
 634 //      nt = crypto1_word(traceCrypto1, nt ^ uid, 1) ^ nt; 
 636         /*      traceCrypto1 = crypto1_create(key); // key in lfsr 
 637                 crypto1_word(traceCrypto1, nt ^ uid, 0); 
 638                 crypto1_word(traceCrypto1, ar, 1); 
 639                 crypto1_word(traceCrypto1, 0, 0); 
 640                 crypto1_word(traceCrypto1, 0, 0);*/ 
 644                         traceState 
= TRACE_ERROR
; 
 650                 traceState 
= TRACE_ERROR
; 
 657 int tryDecryptWord(uint32_t nt
, uint32_t ar_enc
, uint32_t at_enc
, uint8_t *data
, int len
){ 
 659         uint32_t nt;      // tag challenge 
 660         uint32_t nr_enc;  // encrypted reader challenge 
 661         uint32_t ar_enc;  // encrypted reader response 
 662         uint32_t at_enc;  // encrypted tag response 
 664         struct Crypto1State 
*pcs 
= NULL
; 
 666         ks2 
= ar_enc 
^ prng_successor(nt
, 64); 
 667         ks3 
= at_enc 
^ prng_successor(nt
, 96); 
 669         PrintAndLog("Decrypting data with:"); 
 670         PrintAndLog("      nt: %08x",nt
); 
 671         PrintAndLog("  ar_enc: %08x",ar_enc
); 
 672         PrintAndLog("  at_enc: %08x",at_enc
); 
 673         PrintAndLog("\nEncrypted data: [%s]", sprint_hex(data
,len
) ); 
 675         pcs 
= lfsr_recovery64(ks2
, ks3
); 
 676         mf_crypto1_decrypt(pcs
, data
, len
, FALSE
); 
 677         PrintAndLog("Decrypted data: [%s]", sprint_hex(data
,len
) ); 
 678         crypto1_destroy(pcs
);