1 //----------------------------------------------------------------------------- 
   2 // Copyright (C) 2014 Iceman 
   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 //----------------------------------------------------------------------------- 
   8 // High frequency MIFARE Desfire commands 
   9 //----------------------------------------------------------------------------- 
  15 #include "loclass/des.h" 
  17 #include "proxmark3.h" 
  18 #include "../include/common.h" 
  19 #include "../include/mifare.h" 
  20 #include "../common/iso14443crc.h" 
  23 #include "cmdparser.h" 
  25 #include "cmdhfmfdes.h" 
  32 uint8_t key_zero_data
[16] = { 0x00 }; 
  33 uint8_t key_ones_data
[16] = { 0x01 }; 
  34 uint8_t key_defa_data
[16] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }; 
  35 uint8_t key_picc_data
[16] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f }; 
  37 static int CmdHelp(const char *Cmd
); 
  39 int CmdHF14ADesWb(const char *Cmd
) 
  41 /*      uint8_t blockNo = 0; 
  43         uint8_t key[6] = {0, 0, 0, 0, 0, 0}; 
  44         uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 
  49                 PrintAndLog("Usage:  hf mf wrbl    <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>"); 
  50                 PrintAndLog("        sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); 
  54         blockNo = param_get8(Cmd, 0); 
  55         cmdp = param_getchar(Cmd, 1); 
  57                 PrintAndLog("Key type must be A or B"); 
  60         if (cmdp != 'A' && cmdp != 'a') keyType = 1; 
  61         if (param_gethex(Cmd, 2, key, 12)) { 
  62                 PrintAndLog("Key must include 12 HEX symbols"); 
  65         if (param_gethex(Cmd, 3, bldata, 32)) { 
  66                 PrintAndLog("Block data must include 32 HEX symbols"); 
  69         PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); 
  70         PrintAndLog("--data: %s", sprint_hex(bldata, 16)); 
  72   UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; 
  73         memcpy(c.d.asBytes, key, 6); 
  74         memcpy(c.d.asBytes + 10, bldata, 16); 
  78         if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { 
  79                 uint8_t isOK  = resp.arg[0] & 0xff; 
  80                 PrintAndLog("isOk:%02x", isOK); 
  82                 PrintAndLog("Command execute timeout"); 
  88 int CmdHF14ADesRb(const char *Cmd
) 
  90         // uint8_t blockNo = 0; 
  91         // uint8_t keyType = 0; 
  92         // uint8_t key[6] = {0, 0, 0, 0, 0, 0}; 
  97         // if (strlen(Cmd)<3) { 
  98                 // PrintAndLog("Usage:  hf mf rdbl    <block number> <key A/B> <key (12 hex symbols)>"); 
  99                 // PrintAndLog("        sample: hf mf rdbl 0 A FFFFFFFFFFFF "); 
 103         // blockNo = param_get8(Cmd, 0); 
 104         // cmdp = param_getchar(Cmd, 1); 
 105         // if (cmdp == 0x00) { 
 106                 // PrintAndLog("Key type must be A or B"); 
 109         // if (cmdp != 'A' && cmdp != 'a') keyType = 1; 
 110         // if (param_gethex(Cmd, 2, key, 12)) { 
 111                 // PrintAndLog("Key must include 12 HEX symbols"); 
 114         // PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); 
 116   // UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; 
 117         // memcpy(c.d.asBytes, key, 6); 
 121         // if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { 
 122                 // uint8_t                isOK  = resp.arg[0] & 0xff; 
 123                 // uint8_t              * data  = resp.d.asBytes; 
 126                         // PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); 
 128                         // PrintAndLog("isOk:%02x", isOK); 
 130                 // PrintAndLog("Command execute timeout"); 
 136 int CmdHF14ADesInfo(const char *Cmd
){ 
 138         UsbCommand c 
= {CMD_MIFARE_DESFIRE_INFO
}; 
 142         if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1500) ) { 
 143                 PrintAndLog("Command execute timeout"); 
 146         uint8_t isOK  
= resp
.arg
[0] & 0xff; 
 148                 PrintAndLog("Command unsuccessful"); 
 152         PrintAndLog("-- Desfire Information --------------------------------------"); 
 153         PrintAndLog("-------------------------------------------------------------"); 
 154         PrintAndLog("  UID                : %s",sprint_hex(resp
.d
.asBytes
, 7)); 
 155         PrintAndLog("  Batch number       : %s",sprint_hex(resp
.d
.asBytes
+28,5)); 
 156         PrintAndLog("  Production date    : week %02x, 20%02x",resp
.d
.asBytes
[33], resp
.d
.asBytes
[34]); 
 157         PrintAndLog("  -----------------------------------------------------------"); 
 158         PrintAndLog("  Hardware Information"); 
 159         PrintAndLog("      Vendor Id      : %s", getTagInfo(resp
.d
.asBytes
[7])); 
 160         PrintAndLog("      Type           : 0x%02X",resp
.d
.asBytes
[8]); 
 161         PrintAndLog("      Subtype        : 0x%02X",resp
.d
.asBytes
[9]); 
 162         PrintAndLog("      Version        : %d.%d",resp
.d
.asBytes
[10], resp
.d
.asBytes
[11]); 
 163         PrintAndLog("      Storage size   : %s",GetCardSizeStr(resp
.d
.asBytes
[12])); 
 164         PrintAndLog("      Protocol       : %s",GetProtocolStr(resp
.d
.asBytes
[13])); 
 165         PrintAndLog("  -----------------------------------------------------------"); 
 166         PrintAndLog("  Software Information"); 
 167         PrintAndLog("      Vendor Id      : %s", getTagInfo(resp
.d
.asBytes
[14])); 
 168         PrintAndLog("      Type           : 0x%02X",resp
.d
.asBytes
[15]); 
 169         PrintAndLog("      Subtype        : 0x%02X",resp
.d
.asBytes
[16]); 
 170         PrintAndLog("      Version        : %d.%d",resp
.d
.asBytes
[17], resp
.d
.asBytes
[18]); 
 171         PrintAndLog("      storage size   : %s", GetCardSizeStr(resp
.d
.asBytes
[19])); 
 172         PrintAndLog("      Protocol       : %s", GetProtocolStr(resp
.d
.asBytes
[20])); 
 173         PrintAndLog("-------------------------------------------------------------"); 
 175         // Master Key settings 
 176         GetKeySettings(NULL
); 
 178         // Free memory on card 
 179         c
.cmd 
= CMD_MIFARE_DESFIRE
; 
 180         c
.arg
[0] = (INIT 
| DISCONNECT
); 
 182         c
.d
.asBytes
[0] = GET_FREE_MEMORY
; 
 184         if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) { 
 189         memcpy(tmp
, resp
.d
.asBytes
+3,3);  
 191         PrintAndLog("   Available free memory on card       : %d bytes", le24toh( tmp 
)); 
 192         PrintAndLog("-------------------------------------------------------------"); 
 195                 Card Master key (CMK)        0x00 AID = 00 00 00 (card level) 
 196                 Application Master Key (AMK) 0x00 AID != 00 00 00 
 197                 Application keys (APK)       0x01-0x0D 
 198                 Application free             0x0E 
 199                 Application never            0x0F 
 213   The 7 MSBits (= n) code the storage size itself based on 2^n,  
 214   the LSBit is set to '0' if the size is exactly 2^n 
 215         and set to '1' if the storage size is between 2^n and 2^(n+1).  
 216         For this version of DESFire the 7 MSBits are set to 0x0C (2^12 = 4096) and the LSBit is '0'. 
 218 char * GetCardSizeStr( uint8_t fsize 
){ 
 223         uint16_t usize 
= 1 << ((fsize 
>>1) + 1); 
 224         uint16_t lsize 
= 1 << (fsize 
>>1); 
 228                 sprintf(retStr
, "0x%02X (%d - %d bytes)",fsize
, usize
, lsize
); 
 230                 sprintf(retStr
, "0x%02X (%d bytes)", fsize
, lsize
);              
 234 char * GetProtocolStr(uint8_t id
){ 
 240                 sprintf(retStr
,"0x%02X (ISO 14443-3, 14443-4)", id
); 
 242                 sprintf(retStr
,"0x%02X (Unknown)", id
);  
 246 void GetKeySettings( uint8_t *aid
){ 
 248         char messStr
[512] = {0x00}; 
 251         uint32_t options 
= NONE
; 
 255         //memset(messStr, 0x00, 512); 
 257         c
.cmd 
= CMD_MIFARE_DESFIRE
; 
 260                 PrintAndLog(" CMK - PICC, Card Master Key settings "); 
 262                 c
.arg
[CMDPOS
] = (INIT 
| DISCONNECT
); 
 263                 c
.arg
[LENPOS
] =  0x01; 
 264                 c
.d
.asBytes
[0] = GET_KEY_SETTINGS
;  // 0x45 
 266                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1000) ) {return;}   
 267                 isOK  
= resp
.arg
[0] & 0xff; 
 269                         PrintAndLog("   Can't select master application");       
 273                 str 
= (resp
.d
.asBytes
[3] & (1 << 3 )) ? "YES":"NO";      
 274                 PrintAndLog("   [0x08] Configuration changeable       : %s", str
); 
 275                 str 
= (resp
.d
.asBytes
[3] & (1 << 2 )) ? "NO":"YES"; 
 276                 PrintAndLog("   [0x04] CMK required for create/delete : %s",str
); 
 277                 str 
= (resp
.d
.asBytes
[3] & (1 << 1 )) ? "NO":"YES"; 
 278                 PrintAndLog("   [0x02] Directory list access with CMK : %s",str
); 
 279                 str 
= (resp
.d
.asBytes
[3] & (1 << 0 )) ? "YES" : "NO"; 
 280                 PrintAndLog("   [0x01] CMK is changeable              : %s", str
); 
 282                 c
.arg
[LENPOS
] = 0x02; //LEN 
 283                 c
.d
.asBytes
[0] = GET_KEY_VERSION
; //0x64 
 284                 c
.d
.asBytes
[1] = 0x00; 
 286                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1000) ) { 
 289                 isOK  
= resp
.arg
[0] & 0xff; 
 291                         PrintAndLog("   Can't read key-version"); 
 295                 PrintAndLog("   Max number of keys       : %d", resp
.d
.asBytes
[4]); 
 296                 PrintAndLog("   Master key Version       : %d (0x%02x)", resp
.d
.asBytes
[3], resp
.d
.asBytes
[3]); 
 297                 PrintAndLog("   ----------------------------------------------------------"); 
 299                 c
.arg
[LENPOS
] = 0x02; //LEN 
 300                 c
.d
.asBytes
[0] = AUTHENTICATE
; //0x0A 
 301                 c
.d
.asBytes
[1] = 0x00; // KEY 0 
 303                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1000) ) {return;} 
 304                 isOK  
= resp
.d
.asBytes
[2] & 0xff; 
 305                 PrintAndLog("   [0x0A] Authenticate      : %s", ( isOK
==0xAE ) ? "NO":"YES"); 
 307                 c
.d
.asBytes
[0] = AUTHENTICATE_ISO
; //0x1A 
 309                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1000) ) {return;} 
 310                 isOK  
= resp
.d
.asBytes
[2] & 0xff; 
 311                 PrintAndLog("   [0x1A] Authenticate ISO  : %s", ( isOK
==0xAE ) ? "NO":"YES"); 
 313                 c
.d
.asBytes
[0] = AUTHENTICATE_AES
; //0xAA 
 315                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1000) ) {return;} 
 316                 isOK  
= resp
.d
.asBytes
[2] & 0xff; 
 317                 PrintAndLog("   [0xAA] Authenticate AES  : %s", ( isOK
==0xAE ) ? "NO":"YES"); 
 319                 PrintAndLog("   ----------------------------------------------------------"); 
 322                 PrintAndLog(" AMK - Application Master Key settings"); 
 325                 c
.arg
[0] = (INIT 
| CLEARTRACE
); 
 326                 c
.arg
[LENPOS
] = 0x04; 
 327                 c
.d
.asBytes
[0] = SELECT_APPLICATION
;  // 0x5a 
 328                 memcpy(c
.d
.asBytes
+1, aid
, 3); 
 331                 if (!WaitForResponseTimeout(CMD_ACK
,&resp
,1500) ) { 
 332                         PrintAndLog("   Timed-out"); 
 335                 isOK  
= resp
.arg
[0] & 0xff; 
 337                         PrintAndLog("   Can't select AID: %s",sprint_hex(aid
,3));        
 344                 c
.arg
[LENPOS
] = 0x01; 
 345                 c
.d
.asBytes
[0] = GET_KEY_SETTINGS
; // 0x45               
 347                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1500) ) { 
 350                 isOK  
= resp
.arg
[0] & 0xff; 
 352                         PrintAndLog("   Can't read Application Master key settings"); 
 355                         uint8_t rights 
= (resp
.d
.asBytes
[3] >> 4 & 0xff); 
 358                                         str 
= "AMK authentication is necessary to change any key (default)"; 
 361                                         str 
= "Authentication with the key to be changed (same KeyNo) is necessary to change a key"; 
 364                                         str 
= "All keys (except AMK,see Bit0) within this application are frozen"; 
 367                                         str 
= "Authentication with the specified key is necessary to change any ley. A change key and a PICC master key (CMK) can only be changed after authentication with the master key. For keys other then the master or change key, an authentication with the same key is needed."; 
 370                         PrintAndLog("Changekey Access rights"); 
 371                         PrintAndLog("-- %s",str
); 
 374                         str 
= (resp
.d
.asBytes
[3] & (1 << 3 )) ? "YES":"NO";      
 375                         PrintAndLog("   0x08 Configuration changeable       : %s", str
); 
 376                         str 
= (resp
.d
.asBytes
[3] & (1 << 2 )) ? "NO":"YES"; 
 377                         PrintAndLog("   0x04 AMK required for create/delete : %s",str
); 
 378                         str 
= (resp
.d
.asBytes
[3] & (1 << 1 )) ? "NO":"YES"; 
 379                         PrintAndLog("   0x02 Directory list access with AMK : %s",str
); 
 380                         str 
= (resp
.d
.asBytes
[3] & (1 << 0 )) ? "YES" : "NO"; 
 381                         PrintAndLog("   0x01 AMK is changeable              : %s", str
); 
 386                 c
.arg
[LENPOS
] = 0x02; 
 387                 c
.d
.asBytes
[0] = GET_KEY_VERSION
; //0x64 
 388                 c
.d
.asBytes
[1] = 0x00; 
 390                 if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1500) ) { 
 391                         PrintAndLog("   Timed-out"); 
 397                 isOK  
= resp
.arg
[0] & 0xff; 
 399                         PrintAndLog("   Can't read Application Master key version. Trying all keys"); 
 400                         numOfKeys 
= MAX_NUM_KEYS
; 
 403                         numOfKeys 
= resp
.d
.asBytes
[4]; 
 405                         PrintAndLog("     Max number of keys  : %d", numOfKeys 
); 
 406                         PrintAndLog("     Application Master key Version  : %d (0x%02x)", resp
.d
.asBytes
[3], resp
.d
.asBytes
[3]); 
 407                         PrintAndLog("-------------------------------------------------------------");                    
 410                 // LOOP over numOfKeys that we got before.  
 411                 // From 0x01 to numOfKeys.  We already got 0x00. (AMK) 
 412                 for(int i
=0x01; i
<=0x0f; ++i
){ 
 420 int CmdHF14ADesEnumApplications(const char *Cmd
){ 
 424         uint32_t options 
= (INIT 
| DISCONNECT
); 
 426         UsbCommand c 
= {CMD_MIFARE_DESFIRE
, {options 
, 0x01 }}; 
 427         c
.d
.asBytes
[0] = GET_APPLICATION_IDS
;  //0x6a 
 432         if ( !WaitForResponseTimeout(CMD_ACK
,&resp
,1500) ) { 
 435         isOK  
= resp
.arg
[0] & 0xff; 
 437                 PrintAndLog("Command unsuccessful"); 
 441         PrintAndLog("-- Desfire Enumerate Applications ---------------------------"); 
 442         PrintAndLog("-------------------------------------------------------------"); 
 445         UsbCommand respFiles
; 
 448         int max 
= resp
.arg
[1] -3 -2; 
 450         for(int i
=3; i
<=max
; i
+=3){ 
 451                 PrintAndLog(" Aid %d : %02X %02X %02X ",num 
,resp
.d
.asBytes
[i
],resp
.d
.asBytes
[i
+1],resp
.d
.asBytes
[i
+2]); 
 454                 aid
[0] = resp
.d
.asBytes
[i
]; 
 455                 aid
[1] = resp
.d
.asBytes
[i
+1]; 
 456                 aid
[2] = resp
.d
.asBytes
[i
+2]; 
 459                 // Select Application 
 460                 c
.arg
[CMDPOS
] = INIT
; 
 461                 c
.arg
[LENPOS
] = 0x04;  
 462                 c
.d
.asBytes
[0] = SELECT_APPLICATION
;  // 0x5a 
 463                 c
.d
.asBytes
[1] = resp
.d
.asBytes
[i
]; 
 464                 c
.d
.asBytes
[2] = resp
.d
.asBytes
[i
+1];            
 465                 c
.d
.asBytes
[3] = resp
.d
.asBytes
[i
+2]; 
 468                 if (!WaitForResponseTimeout(CMD_ACK
,&respAid
,1500) ) { 
 469                         PrintAndLog("   Timed-out"); 
 472                 isOK  
= respAid
.d
.asBytes
[2] & 0xff; 
 474                         PrintAndLog("   Can't select AID: %s",sprint_hex(resp
.d
.asBytes
+i
,3));   
 479                 c
.arg
[CMDPOS
] = NONE
; 
 480                 c
.arg
[LENPOS
] = 0x01; 
 481                 c
.d
.asBytes
[0] = GET_FILE_IDS
; // 0x6f 
 484                 if ( !WaitForResponseTimeout(CMD_ACK
,&respFiles
,1500) ) { 
 485                         PrintAndLog("   Timed-out"); 
 488                         isOK  
= respFiles
.d
.asBytes
[2] & 0xff; 
 490                                 PrintAndLog("   Can't get file ids "); 
 492                                 int respfileLen 
= resp
.arg
[1]-3-2;                       
 493                                 for (int j
=0; j
< respfileLen
; ++j
){ 
 494                                         PrintAndLog("   Fileid %d :", resp
.d
.asBytes
[j
+3]); 
 500                 c
.arg
[CMDPOS
] = DISCONNECT
; 
 501                 c
.arg
[LENPOS
] = 0x01; 
 502                 c
.d
.asBytes
[0] = GET_ISOFILE_IDS
; // 0x61 
 505                 if ( !WaitForResponseTimeout(CMD_ACK
,&respFiles
,1500) ) { 
 506                         PrintAndLog("   Timed-out"); 
 509                         isOK  
= respFiles
.d
.asBytes
[2] & 0xff; 
 511                                 PrintAndLog("   Can't get ISO file ids "); 
 513                                 int respfileLen 
= resp
.arg
[1]-3-2;                       
 514                                 for (int j
=0; j
< respfileLen
; ++j
){ 
 515                                         PrintAndLog(" ISO  Fileid %d :", resp
.d
.asBytes
[j
+3]); 
 522         PrintAndLog("-------------------------------------------------------------"); 
 528 // MIAFRE DesFire Authentication 
 531 int CmdHF14ADesAuth(const char *Cmd
){ 
 534         // ------------------------ 
 540         uint8_t keylength 
= 8; 
 541         unsigned char key
[24];   
 544         PrintAndLog("Usage:  hf mfdes auth <1|2|3> <1|2|3|4> <keyno> <key> "); 
 545                 PrintAndLog("               Auth modes"); 
 546                 PrintAndLog("                 1 = normal, 2 = iso, 3 = aes"); 
 547                 PrintAndLog("               Crypto"); 
 548                 PrintAndLog("                 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES"); 
 550         PrintAndLog("        sample: hf mfdes auth 1 1 0 11223344"); 
 551                 PrintAndLog("        sample: hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"); 
 554         uint8_t cmdAuthMode     
= param_get8(Cmd
,0); 
 555         uint8_t cmdAuthAlgo     
= param_get8(Cmd
,1); 
 556         uint8_t cmdKeyNo        
= param_get8(Cmd
,2); 
 561                         if ( cmdAuthAlgo 
!= 1 && cmdAuthAlgo 
!= 2) { 
 562                                 PrintAndLog("Crypto algo not valid for the auth mode"); 
 567                         if ( cmdAuthAlgo 
!= 1 && cmdAuthAlgo 
!= 2 && cmdAuthAlgo 
!= 3) { 
 568                                 PrintAndLog("Crypto algo not valid for the auth mode"); 
 573                         if ( cmdAuthAlgo 
!= 4) { 
 574                                 PrintAndLog("Crypto algo not valid for the auth mode"); 
 579                         PrintAndLog("Wrong Auth mode"); 
 584         switch (cmdAuthAlgo
){ 
 587                         PrintAndLog("3DES selected"); 
 591                         PrintAndLog("3 key 3DES selected"); 
 595                         PrintAndLog("AES selected"); 
 600                         PrintAndLog("DES selected"); 
 605         if (param_gethex(Cmd
, 3, key
, keylength
*2)) { 
 606                 PrintAndLog("Key must include %d HEX symbols", keylength
); 
 609         // algo, nyckellängd,  
 610         UsbCommand c 
= {CMD_MIFARE_DESFIRE_AUTH1
, { cmdAuthMode
, cmdAuthAlgo
, cmdKeyNo 
}}; 
 612         c
.d
.asBytes
[0] = keylength
; 
 613         memcpy(c
.d
.asBytes
+1, key
, keylength
); 
 614         clearCommandBuffer(); 
 618         if (!WaitForResponseTimeout(CMD_ACK
,&resp
,3000)) { 
 619                 PrintAndLog("Client command execute timeout"); 
 623         uint8_t isOK  
= resp
.arg
[0] & 0xff; 
 625                 uint8_t * data
= resp
.d
.asBytes
; 
 627                 PrintAndLog("  Key        :%s",sprint_hex(key
, keylength
)); 
 628                 PrintAndLog("  SESSION    :%s",sprint_hex(data
, keylength
)); 
 629                 PrintAndLog("-------------------------------------------------------------"); 
 630                 //PrintAndLog("  Expected   :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); 
 632                 PrintAndLog("Client command failed."); 
 634         PrintAndLog("-------------------------------------------------------------");    
 639 static command_t CommandTable
[] = { 
 640   {"help",              CmdHelp
,                                        1, "This help"}, 
 641   {"info",              CmdHF14ADesInfo
,                        0, "Get MIFARE DesFire information"}, 
 642   {"enum",              CmdHF14ADesEnumApplications
,0, "Tries enumerate all applications"}, 
 643   {"auth",              CmdHF14ADesAuth
,                        0, "Tries a MIFARE DesFire Authentication"}, 
 644   {"rdbl",              CmdHF14ADesRb
,                          0, "Read MIFARE DesFire block"}, 
 645   {"wrbl",              CmdHF14ADesWb
,                          0, "write MIFARE DesFire block"}, 
 646   {NULL
, NULL
, 0, NULL
} 
 649 int CmdHFMFDes(const char *Cmd
) { 
 651         clearCommandBuffer(); 
 652         //WaitForResponseTimeout(CMD_ACK,NULL,100); 
 653         CmdsParse(CommandTable
, Cmd
); 
 657 int CmdHelp(const char *Cmd
) { 
 658         CmdsHelp(CommandTable
);