2014-09-12 05:23:46 +08:00
//-----------------------------------------------------------------------------
// Copyright (C) 2014 Iceman
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Desfire commands
//-----------------------------------------------------------------------------
# include "cmdhfmfdes.h"
2019-08-08 22:57:33 +08:00
# include <stdio.h>
# include <string.h>
2020-04-01 21:54:59 +08:00
# include "commonutil.h" // ARRAYLEN
2019-08-08 22:57:33 +08:00
# include "cmdparser.h" // command_t
# include "comms.h"
# include "ui.h"
2020-04-09 04:44:51 +08:00
# include "cmdhw.h"
2019-08-08 22:57:33 +08:00
# include "cmdhf14a.h"
# include "mbedtls/des.h"
2020-04-12 23:10:27 +08:00
# include "mbedtls/aes.h"
2020-03-17 08:50:27 +08:00
# include "crypto/libpcrypto.h"
# include "protocols.h"
2020-03-17 18:37:38 +08:00
# include "mifare.h" // desfire raw command options
2020-04-07 15:23:34 +08:00
# include "cmdtrace.h"
2020-04-08 19:26:44 +08:00
# include "cliparser/cliparser.h"
# include "emv/apduinfo.h" // APDU manipulation / errorcodes
2020-04-09 04:44:51 +08:00
# include "emv/emvcore.h" // APDU logging
2020-04-08 19:26:44 +08:00
# include "util_posix.h" // msleep
# include "mifare/mifare4.h" // MIFARE Authenticate / MAC
2020-04-12 23:10:27 +08:00
# include "mifare/desfire_crypto.h"
# include "crapto1/crapto1.h"
struct desfire_key defaultkey = { 0 } ;
static desfirekey_t sessionkey = & defaultkey ;
2019-08-08 22:57:33 +08:00
2014-11-26 20:52:39 +08:00
uint8_t key_zero_data [ 16 ] = { 0x00 } ;
uint8_t key_ones_data [ 16 ] = { 0x01 } ;
2019-03-10 07:00:59 +08:00
uint8_t key_defa_data [ 16 ] = { 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f } ;
uint8_t key_picc_data [ 16 ] = { 0x40 , 0x41 , 0x42 , 0x43 , 0x44 , 0x45 , 0x46 , 0x47 , 0x48 , 0x49 , 0x4a , 0x4b , 0x4c , 0x4d , 0x4e , 0x4f } ;
2014-09-12 05:23:46 +08:00
2020-04-11 17:32:31 +08:00
typedef struct {
uint8_t mode ;
uint8_t algo ;
uint8_t keyno ;
uint8_t keylen ;
uint8_t key [ 24 ] ;
} mfdes_authinput_t ;
typedef struct mfdes_auth_res {
uint8_t sessionkeylen ;
uint8_t sessionkey [ 24 ] ;
} mfdes_auth_res_t ;
2020-04-11 03:02:46 +08:00
2020-04-11 17:32:31 +08:00
# define status(x) ( ((uint16_t)(0x91<<8)) + x )
2020-04-11 03:02:46 +08:00
2020-03-24 16:50:17 +08:00
typedef enum {
UNKNOWN = 0 ,
2020-04-10 16:31:18 +08:00
DESFIRE_MF3ICD40 ,
DESFIRE_EV1 ,
DESFIRE_EV2 ,
DESFIRE_EV3 ,
DESFIRE_LIGHT ,
PLUS_EV1 ,
} nxp_cardtype_t ;
2020-03-24 16:50:17 +08:00
2020-04-08 19:26:44 +08:00
typedef struct {
uint8_t aid [ 3 ] ;
uint8_t fid [ 2 ] ;
uint8_t name [ 16 ] ;
} dfname_t ;
2020-03-24 16:50:17 +08:00
2014-09-12 05:23:46 +08:00
static int CmdHelp ( const char * Cmd ) ;
2019-03-10 06:35:06 +08:00
2020-04-09 04:44:51 +08:00
/*
2020-04-10 16:31:18 +08:00
The 7 MSBits ( = n ) code the storage size itself based on 2 ^ n ,
the LSBit is set to ' 0 ' if the size is exactly 2 ^ n
and set to ' 1 ' if the storage size is between 2 ^ n and 2 ^ ( n + 1 ) .
For this version of DESFire the 7 MSBits are set to 0x0C ( 2 ^ 12 = 4096 ) and the LSBit is ' 0 ' .
*/
static char * getCardSizeStr ( uint8_t fsize ) {
2020-04-05 00:23:51 +08:00
2020-04-10 16:31:18 +08:00
static char buf [ 40 ] = { 0x00 } ;
char * retStr = buf ;
uint16_t usize = 1 < < ( ( fsize > > 1 ) + 1 ) ;
uint16_t lsize = 1 < < ( fsize > > 1 ) ;
// is LSB set?
if ( fsize & 1 )
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " %d - %d bytes " ) " ) " , fsize , usize , lsize ) ;
else
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " %d bytes " ) " ) " , fsize , lsize ) ;
return buf ;
}
static char * getProtocolStr ( uint8_t id , bool hw ) {
2020-04-11 08:32:55 +08:00
static char buf [ 50 ] = { 0x00 } ;
2020-04-10 16:31:18 +08:00
char * retStr = buf ;
if ( id = = 0x04 ) {
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " ISO 14443-3 MIFARE, 14443-4 " ) " ) " , id ) ;
} else if ( id = = 0x05 ) {
2020-04-11 08:32:55 +08:00
if ( hw )
2020-04-10 16:31:18 +08:00
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " ISO 14443-2, 14443-3 " ) " ) " , id ) ;
else
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " ISO 14443-3, 14443-4 " ) " ) " , id ) ;
} else {
sprintf ( retStr , " 0x%02X ( " _YELLOW_ ( " Unknown " ) " ) " , id ) ;
}
return buf ;
}
static char * getVersionStr ( uint8_t major , uint8_t minor ) {
static char buf [ 40 ] = { 0x00 } ;
char * retStr = buf ;
if ( major = = 0x00 )
sprintf ( retStr , " %x.%x ( " _YELLOW_ ( " DESFire MF3ICD40 " ) " ) " , major , minor ) ;
else if ( major = = 0x01 & & minor = = 0x00 )
sprintf ( retStr , " %x.%x ( " _YELLOW_ ( " DESFire EV1 " ) " ) " , major , minor ) ;
else if ( major = = 0x12 & & minor = = 0x00 )
sprintf ( retStr , " %x.%x ( " _YELLOW_ ( " DESFire EV2 " ) " ) " , major , minor ) ;
// else if (major == 0x13 && minor == 0x00)
// sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV3") ")", major, minor);
else if ( major = = 0x30 & & minor = = 0x00 )
sprintf ( retStr , " %x.%x ( " _YELLOW_ ( " DESFire Light " ) " ) " , major , minor ) ;
else
sprintf ( retStr , " %x.%x ( " _YELLOW_ ( " Unknown " ) " ) " , major , minor ) ;
return buf ;
}
2020-04-05 00:23:51 +08:00
2020-04-05 06:07:05 +08:00
2020-04-09 04:44:51 +08:00
int DESFIRESendApdu ( bool activate_field , bool leavefield_on , sAPDU apdu , uint8_t * result , int max_result_len , int * result_len , uint16_t * sw ) {
2020-04-10 07:18:48 +08:00
2020-04-09 04:44:51 +08:00
* result_len = 0 ;
if ( sw ) * sw = 0 ;
uint16_t isw = 0 ;
int res = 0 ;
if ( activate_field ) {
2020-04-05 00:23:51 +08:00
DropField ( ) ;
2020-04-09 04:44:51 +08:00
msleep ( 50 ) ;
2020-04-05 00:23:51 +08:00
}
2020-04-09 04:44:51 +08:00
// select?
uint8_t data [ APDU_RES_LEN ] = { 0 } ;
// COMPUTE APDU
int datalen = 0 ;
//if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) {
if ( APDUEncodeS ( & apdu , false , 0x100 , data , & datalen ) ) {
PrintAndLogEx ( ERR , " APDU encoding error. " ) ;
return PM3_EAPDU_ENCODEFAIL ;
}
if ( GetAPDULogging ( ) | | ( g_debugMode > 1 ) )
PrintAndLogEx ( SUCCESS , " >>>> %s " , sprint_hex ( data , datalen ) ) ;
res = ExchangeAPDU14a ( data , datalen , activate_field , leavefield_on , result , max_result_len , result_len ) ;
if ( res ) {
return res ;
2020-04-05 00:23:51 +08:00
}
2020-04-09 04:44:51 +08:00
if ( GetAPDULogging ( ) | | ( g_debugMode > 1 ) )
PrintAndLogEx ( SUCCESS , " <<<< %s " , sprint_hex ( result , * result_len ) ) ;
if ( * result_len < 2 ) {
return PM3_SUCCESS ;
}
* result_len - = 2 ;
isw = ( result [ * result_len ] < < 8 ) + result [ * result_len + 1 ] ;
if ( sw )
* sw = isw ;
2020-04-10 16:31:18 +08:00
if ( isw ! = 0x9000 & & isw ! = status ( MFDES_S_OPERATION_OK ) & & isw ! = status ( MFDES_S_SIGNATURE ) & & isw ! = status ( MFDES_S_ADDITIONAL_FRAME ) & & isw ! = status ( MFDES_S_NO_CHANGES ) ) {
2020-04-09 04:44:51 +08:00
if ( GetAPDULogging ( ) ) {
if ( isw > > 8 = = 0x61 ) {
2020-04-10 01:15:17 +08:00
PrintAndLogEx ( ERR , " APDU chaining len: 0x%02x --> " , isw & 0xff ) ;
2020-04-09 04:44:51 +08:00
} else {
2020-04-10 01:15:17 +08:00
PrintAndLogEx ( ERR , " APDU(%02x%02x) ERROR: [0x%4X] %s " , apdu . CLA , apdu . INS , isw , GetAPDUCodeDescription ( isw > > 8 , isw & 0xff ) ) ;
2020-04-09 04:44:51 +08:00
return PM3_EAPDU_FAIL ;
}
}
2020-04-10 04:08:17 +08:00
return PM3_EAPDU_FAIL ;
2020-04-09 04:44:51 +08:00
}
2020-04-05 00:23:51 +08:00
return PM3_SUCCESS ;
}
2020-04-10 07:18:48 +08:00
static char * getstatus ( uint16_t * sw ) {
if ( sw = = NULL ) return " --> sw argument error. This should never happen ! " ;
if ( ( ( * sw > > 8 ) & 0xFF ) = = 0x91 ) {
switch ( * sw & 0xFF ) {
2020-04-10 04:08:17 +08:00
case MFDES_E_OUT_OF_EEPROM :
return " Out of Eeprom, insufficient NV-Memory to complete command " ;
case MFDES_E_ILLEGAL_COMMAND_CODE :
return " Command code not supported " ;
case MFDES_E_INTEGRITY_ERROR :
return " CRC or MAC does not match data / Padding bytes invalid " ;
case MFDES_E_NO_SUCH_KEY :
return " Invalid key number specified " ;
case MFDES_E_LENGTH :
return " Length of command string invalid " ;
case MFDES_E_PERMISSION_DENIED :
return " Current configuration/status does not allow the requested command " ;
case MFDES_E_PARAMETER_ERROR :
return " Value of the parameter(s) invalid " ;
case MFDES_E_APPLICATION_NOT_FOUND :
return " Requested AID not present on PICC " ;
case MFDES_E_APPL_INTEGRITY :
return " Application integrity error, application will be disabled " ;
case MFDES_E_AUTHENTIFICATION_ERROR :
return " Current authentication status does not allow the requested command " ;
case MFDES_E_BOUNDARY :
return " Attempted to read/write data from/to beyong the file's/record's limit " ;
case MFDES_E_PICC_INTEGRITY :
return " PICC integrity error, PICC will be disabled " ;
case MFDES_E_COMMAND_ABORTED :
return " Previous command was not fully completed / Not all Frames were requested or provided by the PCD " ;
case MFDES_E_PICC_DISABLED :
return " PICC was disabled by an unrecoverable error " ;
case MFDES_E_COUNT :
return " Application count is limited to 28, not addition CreateApplication possible " ;
case MFDES_E_DUPLICATE :
2020-04-11 06:31:55 +08:00
return " Duplicate entry: File/Application/ISO Text does already exist " ;
2020-04-10 04:08:17 +08:00
case MFDES_E_EEPROM :
return " Eeprom error due to loss of power, internal backup/rollback mechanism activated " ;
case MFDES_E_FILE_NOT_FOUND :
return " Specified file number does not exist " ;
case MFDES_E_FILE_INTEGRITY :
return " File integrity error, file will be disabled " ;
default :
return " Unknown error " ;
}
}
return " Unknown error " ;
}
2020-04-10 07:18:48 +08:00
static char * GetErrorString ( int res , uint16_t * sw ) {
switch ( res ) {
2020-04-10 04:08:17 +08:00
case PM3_EAPDU_FAIL :
return getstatus ( sw ) ;
2020-04-09 23:15:45 +08:00
case PM3_EUNDEF :
return " Undefined error " ;
case PM3_EINVARG :
return " Invalid argument(s) " ;
case PM3_EDEVNOTSUPP :
return " Operation not supported by device " ;
case PM3_ETIMEOUT :
return " Operation timed out " ;
case PM3_EOPABORTED :
return " Operation aborted (by user) " ;
case PM3_ENOTIMPL :
return " Not (yet) implemented " ;
case PM3_ERFTRANS :
return " Error while RF transmission " ;
case PM3_EIO :
return " Input / output error " ;
case PM3_EOVFLOW :
return " Buffer overflow " ;
case PM3_ESOFT :
return " Software error " ;
case PM3_EFLASH :
return " Flash error " ;
case PM3_EMALLOC :
return " Memory allocation error " ;
case PM3_EFILE :
return " File error " ;
case PM3_ENOTTY :
return " Generic TTY error " ;
case PM3_EINIT :
return " Initialization error " ;
case PM3_EWRONGANSVER :
return " Expected a different answer error " ;
case PM3_EOUTOFBOUND :
return " Memory out-of-bounds error " ;
case PM3_ECARDEXCHANGE :
return " Exchange with card error " ;
case PM3_EAPDU_ENCODEFAIL :
return " Failed to create APDU " ;
case PM3_ENODATA :
return " No data " ;
case PM3_EFATAL :
return " Fatal error " ;
default :
break ;
}
return " " ;
}
2020-04-10 07:18:48 +08:00
static int send_desfire_cmd ( sAPDU * apdu , bool select , uint8_t * dest , int * recv_len , uint16_t * sw , int splitbysize , bool readalldata ) {
2020-04-10 16:31:18 +08:00
if ( apdu = = NULL ) {
2020-04-11 08:32:55 +08:00
PrintAndLogEx ( DEBUG , " APDU=NULL " ) ;
2020-04-10 16:31:18 +08:00
return PM3_EINVARG ;
}
2020-04-11 05:45:54 +08:00
/*if (dest == NULL) {
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( DEBUG , " DEST=NULL " ) ;
return PM3_EINVARG ;
2020-04-11 05:45:54 +08:00
} */
2020-04-10 16:31:18 +08:00
if ( sw = = NULL ) {
PrintAndLogEx ( DEBUG , " SW=NULL " ) ;
return PM3_EINVARG ;
}
if ( recv_len = = NULL ) {
PrintAndLogEx ( DEBUG , " RECV_LEN=NULL " ) ;
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
2020-04-09 04:44:51 +08:00
* sw = 0 ;
uint8_t data [ 255 * 5 ] = { 0x00 } ;
int resplen = 0 ;
int pos = 0 ;
int i = 1 ;
int res = DESFIRESendApdu ( select , true , * apdu , data , sizeof ( data ) , & resplen , sw ) ;
2020-04-10 04:08:17 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( DEBUG , " %s " , GetErrorString ( res , sw ) ) ;
2020-04-12 23:10:27 +08:00
DropField ( ) ;
2020-04-10 04:08:17 +08:00
return res ;
}
2020-04-09 04:44:51 +08:00
if ( dest ! = NULL ) {
memcpy ( dest , data , resplen ) ;
}
pos + = resplen ;
2020-04-10 07:18:48 +08:00
if ( ! readalldata ) {
if ( * sw = = status ( MFDES_ADDITIONAL_FRAME ) ) {
2020-04-12 23:10:27 +08:00
* recv_len = pos ;
2020-04-10 04:08:17 +08:00
return PM3_SUCCESS ;
}
return res ;
}
2020-04-10 16:31:18 +08:00
2020-04-09 23:15:45 +08:00
while ( * sw = = status ( MFDES_ADDITIONAL_FRAME ) ) {
2020-04-09 04:44:51 +08:00
apdu - > INS = MFDES_ADDITIONAL_FRAME ; //0xAF
2020-04-10 07:18:48 +08:00
apdu - > Lc = 0 ;
apdu - > P1 = 0 ;
apdu - > P2 = 0 ;
2020-04-09 04:44:51 +08:00
res = DESFIRESendApdu ( false , true , * apdu , data , sizeof ( data ) , & resplen , sw ) ;
2020-04-10 07:18:48 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( DEBUG , " %s " , GetErrorString ( res , sw ) ) ;
2020-04-12 23:10:27 +08:00
DropField ( ) ;
2020-04-10 04:08:17 +08:00
return res ;
}
2020-04-11 08:32:55 +08:00
2020-04-09 04:44:51 +08:00
if ( dest ! = NULL ) {
if ( splitbysize ) {
memcpy ( & dest [ i * splitbysize ] , data , resplen ) ;
i + = 1 ;
} else {
memcpy ( & dest [ pos ] , data , resplen ) ;
}
}
pos + = resplen ;
2020-04-10 16:31:18 +08:00
2020-04-10 07:18:48 +08:00
if ( * sw ! = status ( MFDES_ADDITIONAL_FRAME ) ) break ;
2020-04-09 04:44:51 +08:00
}
2020-04-11 08:32:55 +08:00
* recv_len = ( splitbysize ) ? i : pos ;
2020-04-10 16:31:18 +08:00
return PM3_SUCCESS ;
2020-04-09 04:44:51 +08:00
}
2020-04-10 16:31:18 +08:00
static nxp_cardtype_t getCardType ( uint8_t major , uint8_t minor ) {
2020-03-24 16:50:17 +08:00
if ( major = = 0x00 )
2020-04-10 16:31:18 +08:00
return DESFIRE_MF3ICD40 ;
if ( major = = 0x01 & & minor = = 0x00 )
return DESFIRE_EV1 ;
if ( major = = 0x12 & & minor = = 0x00 )
return DESFIRE_EV2 ;
// if (major == 0x13 && minor == 0x00)
// return DESFIRE_EV3;
if ( major = = 0x30 & & minor = = 0x00 )
return DESFIRE_LIGHT ;
2020-04-11 08:32:55 +08:00
if ( major = = 0x11 & & minor = = 0x00 )
2020-04-10 16:31:18 +08:00
return PLUS_EV1 ;
return UNKNOWN ;
2020-03-24 16:50:17 +08:00
}
2020-04-12 23:10:27 +08:00
int get_desfire_auth ( mfdes_authinput_t * payload , mfdes_auth_res_t * rpayload )
{
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
// 3 different communication modes, PLAIN,MAC,CRYPTO
mbedtls_aes_context ctx ;
uint8_t keybytes [ 24 ] ;
// Crypt constants
uint8_t IV [ 16 ] = { 0x00 } ;
uint8_t RndA [ 16 ] = { 0x00 } ;
uint8_t RndB [ 16 ] = { 0x00 } ;
uint8_t encRndB [ 16 ] = { 0x00 } ;
uint8_t rotRndB [ 16 ] = { 0x00 } ; //RndB'
uint8_t both [ 32 + 1 ] = { 0x00 } ; // ek/dk_keyNo(RndA+RndB')
// Generate Random Value
uint32_t ng = msclock ( ) ;
uint32_t value = prng_successor ( ng , 32 ) ;
num_to_bytes ( value , 4 , & RndA [ 0 ] ) ;
value = prng_successor ( ng , 32 ) ;
num_to_bytes ( value , 4 , & RndA [ 4 ] ) ;
value = prng_successor ( ng , 32 ) ;
num_to_bytes ( value , 4 , & RndA [ 8 ] ) ;
value = prng_successor ( ng , 32 ) ;
num_to_bytes ( value , 4 , & RndA [ 12 ] ) ;
// Default Keys
uint8_t PICC_MASTER_KEY8 [ 8 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
uint8_t PICC_MASTER_KEY16 [ 16 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
uint8_t PICC_MASTER_KEY24 [ 24 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
//uint8_t null_key_data16[16] = {0x00};
//uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
//uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
// Part 1
if ( payload - > key = = NULL ) {
if ( payload - > algo = = MFDES_AUTH_DES ) {
memcpy ( keybytes , PICC_MASTER_KEY8 , 8 ) ;
} else if ( payload - > algo = = MFDES_ALGO_AES | | payload - > algo = = MFDES_ALGO_3DES ) {
memcpy ( keybytes , PICC_MASTER_KEY16 , 16 ) ;
} else if ( payload - > algo = = MFDES_ALGO_3DES ) {
memcpy ( keybytes , PICC_MASTER_KEY24 , 24 ) ;
}
} else {
memcpy ( keybytes , payload - > key , payload - > keylen ) ;
}
struct desfire_key defaultkey = { 0 } ;
desfirekey_t key = & defaultkey ;
if ( payload - > algo = = MFDES_ALGO_AES ) {
mbedtls_aes_init ( & ctx ) ;
Desfire_aes_key_new ( keybytes , key ) ;
} else if ( payload - > algo = = MFDES_ALGO_3DES ) {
Desfire_3des_key_new_with_version ( keybytes , key ) ;
} else if ( payload - > algo = = MFDES_ALGO_DES ) {
Desfire_des_key_new ( keybytes , key ) ;
} else if ( payload - > algo = = MFDES_ALGO_3K3DES ) {
Desfire_3k3des_key_new_with_version ( keybytes , key ) ;
}
uint8_t subcommand = MFDES_AUTHENTICATE ;
if ( payload - > mode = = MFDES_AUTH_AES )
subcommand = MFDES_AUTHENTICATE_AES ;
else if ( payload - > mode = = MFDES_AUTH_ISO )
subcommand = MFDES_AUTHENTICATE_ISO ;
int recv_len = 0 ;
uint16_t sw = 0 ;
uint8_t recv_data [ 256 ] = { 0 } ;
if ( payload - > mode ! = MFDES_AUTH_PICC ) {
// Let's send our auth command
uint8_t data [ ] = { payload - > keyno } ;
sAPDU apdu = { 0x90 , subcommand , 0x00 , 0x00 , 0x01 , data } ;
int res = send_desfire_cmd ( & apdu , false , recv_data , & recv_len , & sw , 0 , false ) ;
if ( res ! = PM3_SUCCESS ) {
PrintAndLogEx ( SUCCESS , " Sending auth command %02X " _RED_ ( " failed " ) , subcommand ) ;
return PM3_ESOFT ;
}
} else if ( payload - > mode = = MFDES_AUTH_PICC ) {
/*cmd[0] = AUTHENTICATE;
cmd [ 1 ] = payload - > keyno ;
len = DesfireAPDU ( cmd , 2 , resp ) ;
*/
}
if ( ! recv_len ) {
PrintAndLogEx ( ERR , " Authentication failed. Card timeout. " ) ;
return PM3_ESOFT ;
}
if ( sw ! = status ( MFDES_ADDITIONAL_FRAME ) ) {
PrintAndLogEx ( ERR , " Authentication failed. Invalid key number. " ) ;
return PM3_ESOFT ;
}
int expectedlen = 8 ;
if ( payload - > algo = = MFDES_ALGO_AES | | payload - > algo = = MFDES_ALGO_3K3DES ) {
expectedlen = 16 ;
}
if ( recv_len ! = expectedlen ) {
PrintAndLogEx ( ERR , " Authentication failed. Length of answer %d doesn't match algo length %d. " , recv_len , expectedlen ) ;
return PM3_ESOFT ;
}
int rndlen = recv_len ;
// Part 2
if ( payload - > mode ! = MFDES_AUTH_PICC ) {
memcpy ( encRndB , recv_data , rndlen ) ;
} else {
memcpy ( encRndB , recv_data + 2 , rndlen ) ;
}
// Part 3
if ( payload - > algo = = MFDES_ALGO_AES ) {
if ( mbedtls_aes_setkey_dec ( & ctx , key - > data , 128 ) ! = 0 ) {
PrintAndLogEx ( ERR , " mbedtls_aes_setkey_dec failed " ) ;
return PM3_ESOFT ;
}
mbedtls_aes_crypt_cbc ( & ctx , MBEDTLS_AES_DECRYPT , rndlen , IV , encRndB , RndB ) ;
}
else if ( payload - > algo = = MFDES_ALGO_DES )
des_dec ( RndB , encRndB , key - > data ) ;
else if ( payload - > algo = = MFDES_ALGO_3DES )
tdes_nxp_receive ( encRndB , RndB , rndlen , key - > data , IV , 2 ) ;
else if ( payload - > algo = = MFDES_ALGO_3K3DES ) {
tdes_nxp_receive ( encRndB , RndB , rndlen , key - > data , IV , 3 ) ;
}
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " encRndB: %s " , sprint_hex ( encRndB , 8 ) ) ;
PrintAndLogEx ( INFO , " RndB: %s " , sprint_hex ( RndB , 8 ) ) ;
}
// - Rotate RndB by 8 bits
memcpy ( rotRndB , RndB , rndlen ) ;
rol ( rotRndB , rndlen ) ;
uint8_t encRndA [ 16 ] = { 0x00 } ;
// - Encrypt our response
if ( payload - > mode = = MFDES_AUTH_DES | | payload - > mode = = MFDES_AUTH_PICC ) {
des_dec ( encRndA , RndA , key - > data ) ;
memcpy ( both , encRndA , rndlen ) ;
for ( int x = 0 ; x < rndlen ; x + + ) {
rotRndB [ x ] = rotRndB [ x ] ^ encRndA [ x ] ;
}
des_dec ( encRndB , rotRndB , key - > data ) ;
memcpy ( both + rndlen , encRndB , rndlen ) ;
} else if ( payload - > mode = = MFDES_AUTH_ISO ) {
if ( payload - > algo = = MFDES_ALGO_3DES ) {
uint8_t tmp [ 16 ] = { 0x00 } ;
memcpy ( tmp , RndA , rndlen ) ;
memcpy ( tmp + rndlen , rotRndB , rndlen ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " rotRndB: %s " , sprint_hex ( rotRndB , rndlen ) ) ;
PrintAndLogEx ( INFO , " Both: %s " , sprint_hex ( tmp , 16 ) ) ;
}
tdes_nxp_send ( tmp , both , 16 , key - > data , IV , 2 ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " EncBoth: %s " , sprint_hex ( both , 16 ) ) ;
}
} else if ( payload - > algo = = MFDES_ALGO_3K3DES ) {
uint8_t tmp [ 32 ] = { 0x00 } ;
memcpy ( tmp , RndA , rndlen ) ;
memcpy ( tmp + rndlen , rotRndB , rndlen ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " rotRndB: %s " , sprint_hex ( rotRndB , rndlen ) ) ;
PrintAndLogEx ( INFO , " Both3k3: %s " , sprint_hex ( tmp , 32 ) ) ;
}
tdes_nxp_send ( tmp , both , 32 , key - > data , IV , 3 ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " EncBoth: %s " , sprint_hex ( both , 32 ) ) ;
}
}
} else if ( payload - > mode = = MFDES_AUTH_AES ) {
uint8_t tmp [ 32 ] = { 0x00 } ;
memcpy ( tmp , RndA , rndlen ) ;
memcpy ( tmp + rndlen , rotRndB , rndlen ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " rotRndB: %s " , sprint_hex ( rotRndB , rndlen ) ) ;
PrintAndLogEx ( INFO , " Both3k3: %s " , sprint_hex ( tmp , 32 ) ) ;
}
if ( payload - > algo = = MFDES_ALGO_AES ) {
if ( mbedtls_aes_setkey_enc ( & ctx , key - > data , 128 ) ! = 0 ) {
PrintAndLogEx ( ERR , " mbedtls_aes_setkey_enc failed " ) ;
return PM3_ESOFT ;
}
mbedtls_aes_crypt_cbc ( & ctx , MBEDTLS_AES_ENCRYPT , 32 , IV , tmp , both ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " EncBoth: %s " , sprint_hex ( both , 32 ) ) ;
}
}
}
int bothlen = 16 ;
if ( payload - > algo = = MFDES_ALGO_AES | | payload - > algo = = MFDES_ALGO_3K3DES ) {
bothlen = 32 ;
}
if ( payload - > mode ! = MFDES_AUTH_PICC ) {
sAPDU apdu = { 0x90 , MFDES_ADDITIONAL_FRAME , 0x00 , 0x00 , bothlen , both } ;
int res = send_desfire_cmd ( & apdu , false , recv_data , & recv_len , & sw , 0 , false ) ;
if ( res ! = PM3_SUCCESS ) {
PrintAndLogEx ( SUCCESS , " Sending auth command %02X " _RED_ ( " failed " ) , subcommand ) ;
return PM3_ESOFT ;
}
} else {
/*cmd[0] = ADDITIONAL_FRAME;
memcpy ( cmd + 1 , both , 16 ) ;
len = DesfireAPDU ( cmd , 1 + 16 , resp ) ;
if ( res ! = PM3_SUCCESS ) {
PrintAndLogEx ( SUCCESS , " Sending auth command %02X " _RED_ ( " failed " ) , subcommand ) ;
return PM3_ESOFT ;
} */
}
if ( ! recv_len ) {
PrintAndLogEx ( ERR , " Authentication failed. Card timeout. " ) ;
return PM3_ESOFT ;
}
if ( payload - > mode ! = MFDES_AUTH_PICC ) {
if ( sw ! = status ( MFDES_S_OPERATION_OK ) ) {
PrintAndLogEx ( ERR , " Authentication failed. " ) ;
return PM3_ESOFT ;
}
} else {
/*if (resp[1] != 0x00) {
PrintAndLogEx ( ERR , " Authentication failed. Card timeout. " ) ;
return PM3_ESOFT ;
} */
}
// Part 4
Desfire_session_key_new ( RndA , RndB , key , sessionkey ) ;
if ( payload - > mode ! = MFDES_AUTH_PICC ) {
memcpy ( encRndA , recv_data , rndlen ) ;
} else {
memcpy ( encRndA , recv_data + 2 , rndlen ) ;
}
if ( payload - > mode = = MFDES_AUTH_DES | | payload - > mode = = MFDES_AUTH_ISO | | payload - > mode = = MFDES_AUTH_PICC ) {
if ( payload - > algo = = MFDES_ALGO_DES )
des_dec ( encRndA , encRndA , key - > data ) ;
else if ( payload - > algo = = MFDES_ALGO_3DES )
tdes_nxp_receive ( encRndA , encRndA , rndlen , key - > data , IV , 2 ) ;
else if ( payload - > algo = = MFDES_ALGO_3K3DES )
tdes_nxp_receive ( encRndA , encRndA , rndlen , key - > data , IV , 3 ) ;
} else if ( payload - > mode = = MFDES_AUTH_AES ) {
if ( mbedtls_aes_setkey_dec ( & ctx , key - > data , 128 ) ! = 0 ) {
PrintAndLogEx ( ERR , " mbedtls_aes_setkey_dec failed " ) ;
return PM3_ESOFT ;
}
mbedtls_aes_crypt_cbc ( & ctx , MBEDTLS_AES_DECRYPT , rndlen , IV , encRndA , encRndA ) ;
}
rol ( RndA , rndlen ) ;
for ( int x = 0 ; x < rndlen ; x + + ) {
if ( RndA [ x ] ! = encRndA [ x ] ) {
PrintAndLogEx ( ERR , " Authentication failed. Cannot verify Session Key. " ) ;
if ( g_debugMode > 1 ) {
PrintAndLogEx ( INFO , " Expected_RndA : %s " , sprint_hex ( RndA , rndlen ) ) ;
PrintAndLogEx ( INFO , " Generated_RndA : %s " , sprint_hex ( encRndA , rndlen ) ) ;
}
return PM3_ESOFT ;
}
}
rpayload - > sessionkeylen = payload - > keylen ;
memcpy ( rpayload - > sessionkey , sessionkey - > data , rpayload - > sessionkeylen ) ;
return PM3_SUCCESS ;
}
2020-04-10 16:31:18 +08:00
// -- test if card supports 0x0A
2020-03-19 19:05:29 +08:00
static int test_desfire_authenticate ( ) {
2020-04-10 07:18:48 +08:00
uint8_t data [ ] = { 0x00 } ;
sAPDU apdu = { 0x90 , MFDES_AUTHENTICATE , 0x00 , 0x00 , 0x01 , data } ; // 0x0A, KEY 0
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-12 23:10:27 +08:00
int res = send_desfire_cmd ( & apdu , true , NULL , & recv_len , & sw , 0 , false ) ;
if ( res = = PM3_SUCCESS )
if ( sw = = status ( MFDES_ADDITIONAL_FRAME ) ) {
DropField ( ) ;
return res ;
}
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-09 04:44:51 +08:00
2020-04-10 16:31:18 +08:00
// -- test if card supports 0x1A
2020-03-19 19:05:29 +08:00
static int test_desfire_authenticate_iso ( ) {
2020-04-10 07:18:48 +08:00
uint8_t data [ ] = { 0x00 } ;
sAPDU apdu = { 0x90 , MFDES_AUTHENTICATE_ISO , 0x00 , 0x00 , 0x01 , data } ; // 0x1A, KEY 0
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-12 23:10:27 +08:00
int res = send_desfire_cmd ( & apdu , true , NULL , & recv_len , & sw , 0 , false ) ;
if ( res = = PM3_SUCCESS )
if ( sw = = status ( MFDES_ADDITIONAL_FRAME ) ) {
DropField ( ) ;
return res ;
}
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-09 04:44:51 +08:00
2020-04-10 16:31:18 +08:00
// -- test if card supports 0xAA
2020-03-19 19:05:29 +08:00
static int test_desfire_authenticate_aes ( ) {
2020-04-10 07:18:48 +08:00
uint8_t data [ ] = { 0x00 } ;
sAPDU apdu = { 0x90 , MFDES_AUTHENTICATE_AES , 0x00 , 0x00 , 0x01 , data } ; // 0xAA, KEY 0
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-12 23:10:27 +08:00
int res = send_desfire_cmd ( & apdu , true , NULL , & recv_len , & sw , 0 , false ) ;
if ( res = = PM3_SUCCESS )
if ( sw = = status ( MFDES_ADDITIONAL_FRAME ) ) {
DropField ( ) ;
return res ;
}
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-10 16:31:18 +08:00
// --- GET FREE MEM
2020-03-19 19:05:29 +08:00
static int desfire_print_freemem ( uint32_t free_mem ) {
PrintAndLogEx ( SUCCESS , " Available free memory on card : " _GREEN_ ( " %d bytes " ) , free_mem ) ;
return PM3_SUCCESS ;
}
static int get_desfire_freemem ( uint32_t * free_mem ) {
2020-04-10 07:18:48 +08:00
if ( free_mem = = NULL ) return PM3_EINVARG ;
2020-04-10 16:31:18 +08:00
2020-04-09 23:15:45 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_FREE_MEMORY , 0x00 , 0x00 , 0x00 , NULL } ; // 0x6E
2020-04-10 16:31:18 +08:00
* free_mem = 0 ;
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
uint8_t fmem [ 4 ] = { 0 } ;
2020-04-05 00:23:51 +08:00
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , true , fmem , & recv_len , & sw , 0 , true ) ;
2020-04-10 16:31:18 +08:00
2020-04-11 08:32:55 +08:00
if ( res ! = PM3_SUCCESS )
2020-04-09 04:44:51 +08:00
return res ;
2020-04-11 08:32:55 +08:00
2020-04-10 16:31:18 +08:00
if ( sw ! = status ( MFDES_S_OPERATION_OK ) )
return PM3_ESOFT ;
2020-04-11 08:32:55 +08:00
2020-04-10 16:31:18 +08:00
* free_mem = le24toh ( fmem ) ;
2020-04-09 04:44:51 +08:00
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-10 16:31:18 +08:00
// --- GET SIGNATURE
static int desfire_print_signature ( uint8_t * uid , uint8_t * signature , size_t signature_len , nxp_cardtype_t card_type ) {
2020-03-19 19:05:29 +08:00
2020-04-10 16:31:18 +08:00
if ( uid = = NULL ) {
PrintAndLogEx ( DEBUG , " UID=NULL " ) ;
return PM3_EINVARG ;
}
if ( signature = = NULL ) {
PrintAndLogEx ( DEBUG , " SIGNATURE=NULL " ) ;
return PM3_EINVARG ;
2020-04-10 01:15:17 +08:00
}
2020-04-02 14:25:24 +08:00
// DESFire Ev3 - wanted
2020-03-17 08:50:27 +08:00
// ref: MIFARE Desfire Originality Signature Validation
2020-04-04 18:17:55 +08:00
2020-04-05 00:23:51 +08:00
# define PUBLIC_DESFIRE_ECDA_KEYLEN 57
2020-04-04 18:17:55 +08:00
const ecdsa_publickey_t nxp_desfire_public_keys [ ] = {
2020-04-05 06:07:05 +08:00
{ " NTAG424DNA, DESFire EV2 " , " 048A9B380AF2EE1B98DC417FECC263F8449C7625CECE82D9B916C992DA209D68422B81EC20B65A66B5102A61596AF3379200599316A00A1410 " } ,
{ " NTAG413DNA, DESFire EV1 " , " 04BB5D514F7050025C7D0F397310360EEC91EAF792E96FC7E0F496CB4E669D414F877B7B27901FE67C2E3B33CD39D1C797715189AC951C2ADD " } ,
{ " DESFire EV2 " , " 04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A " } ,
2020-04-06 21:44:58 +08:00
{ " NTAG424DNA, NTAG424DNATT, DESFire Light EV2 " , " 04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3B " } ,
2020-04-10 16:31:18 +08:00
{ " DESFire Light " , " 040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D " } ,
2020-04-09 04:44:51 +08:00
{ " Mifare Plus EV1 " , " 044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E " }
2020-03-17 08:50:27 +08:00
} ;
2020-04-04 18:17:55 +08:00
2020-04-01 21:54:59 +08:00
uint8_t i ;
int res ;
bool is_valid = false ;
2020-03-17 08:50:27 +08:00
2020-04-05 06:07:05 +08:00
for ( i = 0 ; i < ARRAYLEN ( nxp_desfire_public_keys ) ; i + + ) {
2020-04-04 18:17:55 +08:00
int dl = 0 ;
uint8_t key [ PUBLIC_DESFIRE_ECDA_KEYLEN ] ;
param_gethex_to_eol ( nxp_desfire_public_keys [ i ] . value , 0 , key , PUBLIC_DESFIRE_ECDA_KEYLEN , & dl ) ;
res = ecdsa_signature_r_s_verify ( MBEDTLS_ECP_DP_SECP224R1 , key , uid , 7 , signature , signature_len , false ) ;
2020-04-01 21:54:59 +08:00
is_valid = ( res = = 0 ) ;
if ( is_valid )
break ;
}
if ( is_valid = = false ) {
PrintAndLogEx ( SUCCESS , " Signature verification " _RED_ ( " failed " ) ) ;
return PM3_ESOFT ;
}
2020-03-24 16:50:17 +08:00
2020-04-10 16:31:18 +08:00
// PrintAndLogEx(NORMAL, "");
// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
2020-04-08 19:49:18 +08:00
PrintAndLogEx ( INFO , " IC signature public key name: " _GREEN_ ( " %s " ) , nxp_desfire_public_keys [ i ] . desc ) ;
2020-04-05 00:23:51 +08:00
PrintAndLogEx ( INFO , " IC signature public key value: %.32s " , nxp_desfire_public_keys [ i ] . value ) ;
PrintAndLogEx ( INFO , " : %.32s " , nxp_desfire_public_keys [ i ] . value + 16 ) ;
PrintAndLogEx ( INFO , " : %.32s " , nxp_desfire_public_keys [ i ] . value + 32 ) ;
PrintAndLogEx ( INFO , " : %.32s " , nxp_desfire_public_keys [ i ] . value + 48 ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( INFO , " Elliptic curve parameters: NID_secp224r1 " ) ;
2020-04-08 19:37:48 +08:00
PrintAndLogEx ( INFO , " TAG IC Signature: %s " , sprint_hex_inrow ( signature , 16 ) ) ;
PrintAndLogEx ( INFO , " : %s " , sprint_hex_inrow ( signature + 16 , 16 ) ) ;
PrintAndLogEx ( INFO , " : %s " , sprint_hex_inrow ( signature + 32 , 16 ) ) ;
PrintAndLogEx ( INFO , " : %s " , sprint_hex_inrow ( signature + 48 , signature_len - 48 ) ) ;
2020-04-08 19:49:18 +08:00
PrintAndLogEx ( SUCCESS , " Signature verified: " _GREEN_ ( " successful " ) ) ;
2020-03-17 08:50:27 +08:00
return PM3_SUCCESS ;
}
2020-03-19 19:05:29 +08:00
static int get_desfire_signature ( uint8_t * signature , size_t * signature_len ) {
2020-04-10 16:31:18 +08:00
if ( signature = = NULL ) {
PrintAndLogEx ( DEBUG , " SIGNATURE=NULL " ) ;
return PM3_EINVARG ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 16:31:18 +08:00
if ( signature_len = = NULL ) {
PrintAndLogEx ( DEBUG , " SIGNATURE_LEN=NULL " ) ;
return PM3_EINVARG ;
}
uint8_t c [ ] = { 0x00 } ;
sAPDU apdu = { 0x90 , MFDES_READSIG , 0x00 , 0x00 , sizeof ( c ) , c } ; // 0x3C
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , true , signature , & recv_len , & sw , 0 , true ) ;
2020-04-09 04:44:51 +08:00
if ( res = = PM3_SUCCESS ) {
if ( recv_len ! = 56 ) {
* signature_len = 0 ;
2020-04-10 16:31:18 +08:00
res = PM3_ESOFT ;
2020-04-09 04:44:51 +08:00
} else {
* signature_len = recv_len ;
}
2020-03-17 08:50:27 +08:00
}
2020-04-09 04:44:51 +08:00
DropField ( ) ;
return res ;
2020-03-17 08:50:27 +08:00
}
2020-03-19 19:05:29 +08:00
// --- KEY SETTING
static int desfire_print_keysetting ( uint8_t key_settings , uint8_t num_keys ) {
2020-04-10 01:15:17 +08:00
PrintAndLogEx ( SUCCESS , " AID Key settings : 0x%02x " , key_settings ) ;
2020-04-05 06:07:05 +08:00
PrintAndLogEx ( SUCCESS , " Max number of keys in AID : %d " , num_keys ) ;
2020-04-05 00:23:51 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-03-19 19:05:29 +08:00
PrintAndLogEx ( SUCCESS , " Changekey Access rights " ) ;
// Access rights.
uint8_t rights = ( key_settings > > 4 & 0x0F ) ;
switch ( rights ) {
case 0x0 :
PrintAndLogEx ( SUCCESS , " -- AMK authentication is necessary to change any key (default) " ) ;
break ;
case 0xE :
PrintAndLogEx ( SUCCESS , " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key " ) ;
break ;
case 0xF :
PrintAndLogEx ( SUCCESS , " -- All keys (except AMK,see Bit0) within this application are frozen " ) ;
break ;
default :
PrintAndLogEx ( SUCCESS , " -- Authentication with the specified key is necessary to change any key. \n A change key and a PICC master key (CMK) can only be changed after authentication with the master key. \n For keys other then the master or change key, an authentication with the same key is needed. " ) ;
break ;
}
PrintAndLogEx ( SUCCESS , " [0x08] Configuration changeable : %s " , ( key_settings & ( 1 < < 3 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
PrintAndLogEx ( SUCCESS , " [0x04] AMK required for create/delete : %s " , ( key_settings & ( 1 < < 2 ) ) ? " NO " : " YES " ) ;
PrintAndLogEx ( SUCCESS , " [0x02] Directory list access with AMK : %s " , ( key_settings & ( 1 < < 1 ) ) ? " NO " : " YES " ) ;
2020-04-05 00:23:51 +08:00
PrintAndLogEx ( SUCCESS , " [0x01] AMK is changeable : %s " , ( key_settings & ( 1 < < 0 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
2020-03-19 19:05:29 +08:00
return PM3_SUCCESS ;
}
static int get_desfire_keysettings ( uint8_t * key_settings , uint8_t * num_keys ) {
2020-04-10 16:31:18 +08:00
if ( key_settings = = NULL ) {
PrintAndLogEx ( DEBUG , " KEY_SETTINGS=NULL " ) ;
return PM3_EINVARG ;
}
if ( num_keys = = NULL ) {
PrintAndLogEx ( DEBUG , " NUM_KEYS=NULL " ) ;
return PM3_EINVARG ;
2020-04-10 01:15:17 +08:00
}
2020-04-09 23:15:45 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_KEY_SETTINGS , 0x00 , 0x00 , 0x00 , NULL } ; //0x45
2020-04-09 04:44:51 +08:00
int recv_len = 0 ;
uint16_t sw = 0 ;
uint8_t data [ 2 ] = { 0 } ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , false , data , & recv_len , & sw , 0 , true ) ;
2020-04-10 16:31:18 +08:00
2020-04-11 08:32:55 +08:00
if ( res ! = PM3_SUCCESS )
2020-04-10 16:31:18 +08:00
return res ;
if ( sw ! = status ( MFDES_S_OPERATION_OK ) )
return PM3_ESOFT ;
2020-04-09 04:44:51 +08:00
* key_settings = data [ 0 ] ;
* num_keys = data [ 1 ] ;
2020-04-10 16:31:18 +08:00
return res ;
2020-03-19 19:05:29 +08:00
}
// --- KEY VERSION
static int desfire_print_keyversion ( uint8_t key_idx , uint8_t key_version ) {
2020-04-05 06:07:05 +08:00
PrintAndLogEx ( SUCCESS , " Key [%u] Version : %d (0x%02x) " , key_idx , key_version , key_version ) ;
2020-03-19 19:05:29 +08:00
return PM3_SUCCESS ;
}
static int get_desfire_keyversion ( uint8_t curr_key , uint8_t * num_versions ) {
2020-04-10 16:31:18 +08:00
if ( num_versions = = NULL ) {
PrintAndLogEx ( DEBUG , " NUM_VERSIONS=NULL " ) ;
return PM3_EINVARG ;
2020-04-10 01:15:17 +08:00
}
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_KEY_VERSION , 0x00 , 0x00 , 0x01 , & curr_key } ; //0x64
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , false , num_versions , & recv_len , & sw , 0 , true ) ;
2020-04-11 08:32:55 +08:00
if ( res ! = PM3_SUCCESS )
2020-04-10 16:31:18 +08:00
return res ;
if ( sw ! = status ( MFDES_S_OPERATION_OK ) )
return PM3_ESOFT ;
2020-04-09 04:44:51 +08:00
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-10 16:31:18 +08:00
// --- GET APPIDS
2020-03-19 19:05:29 +08:00
static int get_desfire_appids ( uint8_t * dest , uint8_t * app_ids_len ) {
2020-04-10 16:31:18 +08:00
if ( dest = = NULL ) {
2020-04-11 08:32:55 +08:00
PrintAndLogEx ( DEBUG , " DEST=NULL " ) ;
return PM3_EINVARG ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 16:31:18 +08:00
if ( app_ids_len = = NULL ) {
PrintAndLogEx ( DEBUG , " APP_IDS_LEN=NULL " ) ;
return PM3_EINVARG ;
}
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_APPLICATION_IDS , 0x00 , 0x00 , 0x00 , NULL } ; //0x6a
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , true , dest , & recv_len , & sw , 0 , true ) ;
2020-04-11 08:32:55 +08:00
if ( res ! = PM3_SUCCESS )
2020-04-10 16:31:18 +08:00
return res ;
if ( sw ! = status ( MFDES_S_OPERATION_OK ) )
return PM3_ESOFT ;
2020-04-09 04:44:51 +08:00
* app_ids_len = ( uint8_t ) recv_len & 0xFF ;
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-10 16:31:18 +08:00
// --- GET DF NAMES
2020-04-08 03:52:59 +08:00
static int get_desfire_dfnames ( dfname_t * dest , uint8_t * dfname_count ) {
2020-04-10 07:18:48 +08:00
if ( g_debugMode > 1 ) {
if ( dest = = NULL ) PrintAndLogEx ( ERR , " DEST=NULL " ) ;
if ( dfname_count = = NULL ) PrintAndLogEx ( ERR , " DFNAME_COUNT=NULL " ) ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 07:18:48 +08:00
if ( dest = = NULL | | dfname_count = = NULL ) return PM3_EINVARG ;
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_DF_NAMES , 0x00 , 0x00 , 0x00 , NULL } ; //0x6d
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , true , ( uint8_t * ) dest , & recv_len , & sw , sizeof ( dfname_t ) , true ) ;
2020-04-10 16:31:18 +08:00
if ( res ! = PM3_SUCCESS )
return res ;
if ( sw ! = status ( MFDES_S_OPERATION_OK ) )
return PM3_ESOFT ;
2020-04-09 04:44:51 +08:00
* dfname_count = recv_len ;
return res ;
2020-04-08 03:30:12 +08:00
}
2020-04-09 04:44:51 +08:00
static int get_desfire_select_application ( uint8_t * aid ) {
2020-04-10 07:18:48 +08:00
if ( g_debugMode > 1 ) {
if ( aid = = NULL ) PrintAndLogEx ( ERR , " AID=NULL " ) ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 07:18:48 +08:00
if ( aid = = NULL ) return PM3_EINVARG ;
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_SELECT_APPLICATION , 0x00 , 0x00 , 0x03 , aid } ; //0x5a
int recv_len = 0 ;
uint16_t sw = 0 ;
2020-04-11 05:45:54 +08:00
int res = send_desfire_cmd ( & apdu , true , NONE , & recv_len , & sw , sizeof ( dfname_t ) , true ) ;
2020-04-09 23:15:45 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-11 06:31:55 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't select AID 0x%X -> %s " ) , ( aid [ 2 ] < < 16 ) + ( aid [ 1 ] < < 8 ) + aid [ 0 ] , GetErrorString ( res , & sw ) ) ;
2020-04-09 23:15:45 +08:00
DropField ( ) ;
return res ;
}
return PM3_SUCCESS ;
2020-04-09 04:44:51 +08:00
}
2020-04-10 01:15:17 +08:00
// none, verified
2020-03-19 19:05:29 +08:00
static int get_desfire_fileids ( uint8_t * dest , uint8_t * file_ids_len ) {
2020-04-10 07:18:48 +08:00
if ( g_debugMode > 1 ) {
if ( dest = = NULL ) PrintAndLogEx ( ERR , " DEST=NULL " ) ;
if ( file_ids_len = = NULL ) PrintAndLogEx ( ERR , " FILE_IDS_LEN=NULL " ) ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 07:18:48 +08:00
if ( dest = = NULL | | file_ids_len = = NULL ) return PM3_EINVARG ;
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_FILE_IDS , 0x00 , 0x00 , 0x00 , NULL } ; //0x6f
int recv_len = 0 ;
uint16_t sw = 0 ;
* file_ids_len = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , false , dest , & recv_len , & sw , 0 , true ) ;
2020-04-09 23:15:45 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 07:18:48 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't get file ids -> %s " ) , GetErrorString ( res , & sw ) ) ;
2020-04-09 23:15:45 +08:00
DropField ( ) ;
return res ;
}
2020-04-09 04:44:51 +08:00
* file_ids_len = recv_len ;
return res ;
2020-03-19 19:05:29 +08:00
}
2020-04-10 01:15:17 +08:00
// none, verified
2020-04-09 04:44:51 +08:00
static int get_desfire_filesettings ( uint8_t file_id , uint8_t * dest , int * destlen ) {
2020-04-10 07:18:48 +08:00
if ( g_debugMode > 1 ) {
if ( dest = = NULL ) PrintAndLogEx ( ERR , " DEST=NULL " ) ;
if ( destlen = = NULL ) PrintAndLogEx ( ERR , " DESTLEN=NULL " ) ;
2020-04-10 01:15:17 +08:00
}
2020-04-10 07:18:48 +08:00
if ( dest = = NULL | | destlen = = NULL ) return PM3_EINVARG ;
2020-04-09 04:44:51 +08:00
sAPDU apdu = { 0x90 , MFDES_GET_FILE_SETTINGS , 0x00 , 0x00 , 0x01 , & file_id } ; // 0xF5
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int res = send_desfire_cmd ( & apdu , false , dest , destlen , & sw , 0 , true ) ;
2020-04-09 23:15:45 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 07:18:48 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't get file settings -> %s " ) , GetErrorString ( res , & sw ) ) ;
2020-04-09 23:15:45 +08:00
DropField ( ) ;
return res ;
}
return res ;
}
typedef struct {
uint8_t aid [ 3 ] ;
uint8_t keysetting1 ;
uint8_t keysetting2 ;
uint8_t fid [ 2 ] ;
uint8_t name [ 16 ] ;
} aidhdr_t ;
2020-04-10 07:18:48 +08:00
static int get_desfire_createapp ( aidhdr_t * aidhdr ) {
if ( aidhdr = = NULL ) return PM3_EINVARG ;
sAPDU apdu = { 0x90 , MFDES_CREATE_APPLICATION , 0x00 , 0x00 , sizeof ( aidhdr_t ) , ( uint8_t * ) aidhdr } ; // 0xCA
2020-04-09 23:15:45 +08:00
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int recvlen = 0 ;
2020-04-10 16:31:18 +08:00
int res = send_desfire_cmd ( & apdu , false , NULL , & recvlen , & sw , 0 , true ) ;
2020-04-09 23:15:45 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 07:18:48 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't create aid -> %s " ) , GetErrorString ( res , & sw ) ) ;
2020-04-09 23:15:45 +08:00
DropField ( ) ;
return res ;
}
return res ;
}
2020-04-10 07:18:48 +08:00
static int get_desfire_deleteapp ( uint8_t * aid ) {
if ( aid = = NULL ) return PM3_EINVARG ;
2020-04-10 01:51:35 +08:00
sAPDU apdu = { 0x90 , MFDES_DELETE_APPLICATION , 0x00 , 0x00 , 3 , aid } ; // 0xDA
uint16_t sw = 0 ;
2020-04-10 07:18:48 +08:00
int recvlen = 0 ;
2020-04-10 16:31:18 +08:00
int res = send_desfire_cmd ( & apdu , false , NULL , & recvlen , & sw , 0 , true ) ;
2020-04-10 01:51:35 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-04-10 07:18:48 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't delete aid -> %s " ) , GetErrorString ( res , & sw ) ) ;
2020-04-10 01:51:35 +08:00
DropField ( ) ;
return res ;
}
return res ;
}
2020-04-10 16:31:18 +08:00
int getKeySettings ( uint8_t * aid ) {
if ( aid = = NULL ) return PM3_EINVARG ;
int res = 0 ;
if ( memcmp ( aid , " \x00 \x00 \x00 " , 3 ) = = 0 ) {
// CARD MASTER KEY
//PrintAndLogEx(INFO, "--- " _CYAN_("CMK - PICC, Card Master Key settings"));
res = get_desfire_select_application ( aid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
// KEY Settings - AMK
uint8_t num_keys = 0 ;
uint8_t key_setting = 0 ;
res = get_desfire_keysettings ( & key_setting , & num_keys ) ;
if ( res = = PM3_SUCCESS ) {
// number of Master keys (0x01)
PrintAndLogEx ( SUCCESS , " Number of Masterkeys : " _YELLOW_ ( " %u " ) , ( num_keys & 0x3F ) ) ;
PrintAndLogEx ( SUCCESS , " [0x08] Configuration changeable : %s " , ( key_setting & ( 1 < < 3 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
PrintAndLogEx ( SUCCESS , " [0x04] CMK required for create/delete : %s " , ( key_setting & ( 1 < < 2 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
PrintAndLogEx ( SUCCESS , " [0x02] Directory list access with CMK : %s " , ( key_setting & ( 1 < < 1 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
PrintAndLogEx ( SUCCESS , " [0x01] CMK is changeable : %s " , ( key_setting & ( 1 < < 0 ) ) ? _GREEN_ ( " YES " ) : " NO " ) ;
} else {
PrintAndLogEx ( WARNING , _RED_ ( " Can't read Application Master key settings " ) ) ;
}
const char * str = " Operation of PICC master key : " _YELLOW_ ( " %s " ) ;
// 2 MSB denotes
switch ( num_keys > > 6 ) {
case 0 :
PrintAndLogEx ( SUCCESS , str , " (3)DES " ) ;
break ;
case 1 :
PrintAndLogEx ( SUCCESS , str , " 3K3DES " ) ;
break ;
case 2 :
PrintAndLogEx ( SUCCESS , str , " AES " ) ;
break ;
default :
break ;
}
uint8_t cmk_num_versions = 0 ;
if ( get_desfire_keyversion ( 0 , & cmk_num_versions ) = = PM3_SUCCESS ) {
PrintAndLogEx ( SUCCESS , " PICC Master key Version : " _YELLOW_ ( " %d (0x%02x) " ) , cmk_num_versions , cmk_num_versions ) ;
PrintAndLogEx ( INFO , " ---------------------------------------------------------- " ) ;
}
// Authentication tests
int res = test_desfire_authenticate ( ) ;
if ( res = = PM3_ETIMEOUT ) return res ;
PrintAndLogEx ( SUCCESS , " [0x0A] Authenticate : %s " , ( res = = PM3_SUCCESS ) ? _YELLOW_ ( " YES " ) : " NO " ) ;
res = test_desfire_authenticate_iso ( ) ;
if ( res = = PM3_ETIMEOUT ) return res ;
PrintAndLogEx ( SUCCESS , " [0x1A] Authenticate ISO : %s " , ( res = = PM3_SUCCESS ) ? _YELLOW_ ( " YES " ) : " NO " ) ;
res = test_desfire_authenticate_aes ( ) ;
if ( res = = PM3_ETIMEOUT ) return res ;
PrintAndLogEx ( SUCCESS , " [0xAA] Authenticate AES : %s " , ( res = = PM3_SUCCESS ) ? _YELLOW_ ( " YES " ) : " NO " ) ;
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
} else {
// AID - APPLICATION MASTER KEYS
//PrintAndLogEx(SUCCESS, "--- " _CYAN_("AMK - Application Master Key settings"));
res = get_desfire_select_application ( aid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
// KEY Settings - AMK
uint8_t num_keys = 0 ;
uint8_t key_setting = 0 ;
res = get_desfire_keysettings ( & key_setting , & num_keys ) ;
if ( res = = PM3_SUCCESS ) {
desfire_print_keysetting ( key_setting , num_keys ) ;
} else {
PrintAndLogEx ( WARNING , _RED_ ( " Can't read Application Master key settings " ) ) ;
}
// KEY VERSION - AMK
uint8_t num_version = 0 ;
if ( get_desfire_keyversion ( 0 , & num_version ) = = PM3_SUCCESS ) {
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
PrintAndLogEx ( INFO , " Application keys " ) ;
desfire_print_keyversion ( 0 , num_version ) ;
} else {
PrintAndLogEx ( WARNING , " Can't read AID master key version. Trying all keys " ) ;
}
// From 0x01 to numOfKeys. We already got 0x00. (AMK)
num_keys & = 0x3F ;
if ( num_keys > 1 ) {
for ( uint8_t i = 0x01 ; i < num_keys ; + + i ) {
if ( get_desfire_keyversion ( i , & num_version ) = = PM3_SUCCESS ) {
desfire_print_keyversion ( i , num_version ) ;
} else {
PrintAndLogEx ( WARNING , " Can't read key %d (0x%02x) version " , i , i ) ;
}
}
}
}
DropField ( ) ;
return PM3_SUCCESS ;
}
2020-04-11 08:32:55 +08:00
static void swap24 ( uint8_t * data ) {
if ( data = = NULL ) return ;
uint8_t tmp = data [ 0 ] ;
data [ 0 ] = data [ 2 ] ;
data [ 2 ] = tmp ;
2020-04-11 06:31:55 +08:00
} ;
2020-04-11 08:32:55 +08:00
static void swap16 ( uint8_t * data ) {
if ( data = = NULL ) return ;
uint8_t tmp = data [ 0 ] ;
data [ 0 ] = data [ 1 ] ;
data [ 1 ] = tmp ;
2020-04-11 06:31:55 +08:00
} ;
2020-04-10 16:31:18 +08:00
2020-04-09 23:15:45 +08:00
2020-04-11 06:31:55 +08:00
static int CmdHF14ADesCreateApp ( const char * Cmd ) {
2020-04-10 01:22:57 +08:00
CLIParserInit ( " hf mfdes createaid " ,
2020-04-09 23:15:45 +08:00
" Create Application ID " ,
2020-04-11 06:31:55 +08:00
" Usage: \n \t hf mfdes createaid -a 123456 -f 1122 -k 0F -l 2E -n AppName \n "
2020-04-10 07:18:48 +08:00
) ;
2020-04-09 23:15:45 +08:00
void * argtable [ ] = {
2020-04-10 07:18:48 +08:00
arg_param_begin ,
2020-04-11 06:31:55 +08:00
arg_strx0 ( " aA " , " aid " , " <aid> " , " App ID to create as hex bytes ( " ) ,
arg_strx0 ( " fF " , " fid " , " <fid> " , " File ID to create " ) ,
2020-04-10 07:18:48 +08:00
arg_strx0 ( " kK " , " keysetting1 " , " <keysetting1> " , " Key Setting 1 (Application Master Key Settings) " ) ,
arg_strx0 ( " lL " , " keysetting2 " , " <keysetting2> " , " Key Setting 2 " ) ,
arg_str0 ( " nN " , " name " , " <name> " , " App ISO-4 Name " ) ,
arg_param_end
2020-04-09 23:15:45 +08:00
} ;
2020-04-11 06:31:55 +08:00
CLIExecWithReturn ( Cmd , argtable , false ) ;
2020-04-09 23:15:45 +08:00
/* KeySetting 1 (AMK Setting):
0 : Allow change master key
1 : Free Directory list access without master key
0 : AMK auth needed for GetFileSettings and GetKeySettings
1 : No AMK auth needed for GetFileIDs , GetISOFileIDs , GetFileSettings , GetKeySettings
2 : Free create / delete without master key
0 : CreateFile / DeleteFile only with AMK auth
1 : CreateFile / DeleteFile always
3 : Configuration changable
0 : Configuration frozen
1 : Configuration changable if authenticated with AMK ( default )
4 - 7 : ChangeKey Access Rights
0 : Application master key needed ( default )
0x1 . .0 xD : Auth with specific key needed to change any key
0xE : Auth with the key to be changed ( same KeyNo ) is necessary to change a key
0xF : All Keys within this application are frozen
*/
/* KeySetting 2:
0. .3 : Number of keys stored within the application ( max . 14 keys
4 : RFU
5 : Use of 2 byte ISO FID , 0 : No , 1 : Yes
6. .7 : Crypto Method 00 : DES / 3 DES , 01 : 3 K3DES , 10 : AES
Example :
2 E = FID , DES , 14 keys
6 E = FID , 3 K3DES , 14 keys
AE = FID , AES , 14 keys
*/
int aidlength = 3 ;
int fidlength = 2 ;
uint8_t aid [ 3 ] = { 0 } ;
uint8_t fid [ 2 ] = { 0 } ;
uint8_t name [ 16 ] = { 0 } ;
2020-04-10 07:18:48 +08:00
uint8_t keysetting1 = 0 ;
uint8_t keysetting2 = 0 ;
int keylen1 = 1 ;
int keylen2 = 1 ;
int namelen = 16 ;
2020-04-09 23:15:45 +08:00
CLIGetHexWithReturn ( 1 , aid , & aidlength ) ;
2020-04-11 06:31:55 +08:00
swap24 ( aid ) ;
2020-04-09 23:15:45 +08:00
CLIGetHexWithReturn ( 2 , fid , & fidlength ) ;
2020-04-11 06:31:55 +08:00
swap16 ( fid ) ;
2020-04-09 23:15:45 +08:00
CLIGetHexWithReturn ( 3 , & keysetting1 , & keylen1 ) ;
CLIGetHexWithReturn ( 4 , & keysetting2 , & keylen2 ) ;
2020-04-10 02:03:59 +08:00
CLIGetStrWithReturn ( 5 , name , & namelen ) ;
2020-04-09 23:15:45 +08:00
CLIParserFree ( ) ;
if ( aidlength < 3 ) {
PrintAndLogEx ( ERR , " AID must have 3 bytes length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
if ( fidlength < 2 ) {
PrintAndLogEx ( ERR , " FID must have 2 bytes length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
if ( keylen1 < 1 ) {
PrintAndLogEx ( ERR , " Keysetting1 must have 1 byte length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
2020-04-10 01:15:17 +08:00
if ( keylen1 < 1 ) {
2020-04-09 23:15:45 +08:00
PrintAndLogEx ( ERR , " Keysetting2 must have 1 byte length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
if ( namelen > 16 ) {
PrintAndLogEx ( ERR , " Name has a max. of 16 bytes length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-09 23:15:45 +08:00
}
//90 ca 00 00 0e 3cb849 09 22 10e1 d27600 00850101 00
/*char name[]="Test";
uint8_t aid [ ] = { 0x12 , 0x34 , 0x56 } ;
uint8_t fid [ ] = { 0x11 , 0x22 } ;
uint8_t keysetting1 = 0xEE ;
uint8_t keysetting2 = 0xEE ; */
if ( memcmp ( aid , " \x00 \x00 \x00 " , 3 ) = = 0 ) {
PrintAndLogEx ( WARNING , _RED_ ( " Creating root aid 000000 is forbidden. " ) ) ;
return PM3_ESOFT ;
}
aidhdr_t aidhdr ;
2020-04-10 07:18:48 +08:00
memcpy ( aidhdr . aid , aid , sizeof ( aid ) ) ;
aidhdr . keysetting1 = keysetting1 ;
aidhdr . keysetting2 = keysetting2 ;
memcpy ( aidhdr . fid , fid , sizeof ( fid ) ) ;
memcpy ( aidhdr . name , name , sizeof ( name ) ) ;
uint8_t rootaid [ 3 ] = { 0x00 , 0x00 , 0x00 } ;
int res = get_desfire_select_application ( rootaid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
2020-04-10 02:03:59 +08:00
2020-04-09 23:15:45 +08:00
return get_desfire_createapp ( & aidhdr ) ;
}
2020-04-10 01:51:35 +08:00
static int CmdHF14ADesDeleteApp ( const char * Cmd ) {
CLIParserInit ( " hf mfdes deleteaid " ,
" Delete Application ID " ,
" Usage: \n \t -a aid (3 bytes) \n \n "
" Example: \n \t hf mfdes deleteaid -a 123456 \n "
2020-04-10 07:18:48 +08:00
) ;
2020-04-10 01:51:35 +08:00
void * argtable [ ] = {
2020-04-10 07:18:48 +08:00
arg_param_begin ,
arg_strx0 ( " aA " , " aid " , " <aid> " , " App ID to delete " ) ,
arg_param_end
2020-04-10 01:51:35 +08:00
} ;
2020-04-11 06:31:55 +08:00
CLIExecWithReturn ( Cmd , argtable , false ) ;
2020-04-10 01:51:35 +08:00
int aidlength = 3 ;
uint8_t aid [ 3 ] = { 0 } ;
CLIGetHexWithReturn ( 1 , aid , & aidlength ) ;
CLIParserFree ( ) ;
2020-04-12 23:10:27 +08:00
swap24 ( aid ) ;
2020-04-10 01:51:35 +08:00
if ( aidlength < 3 ) {
PrintAndLogEx ( ERR , " AID must have 3 bytes length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-10 01:51:35 +08:00
}
if ( memcmp ( aid , " \x00 \x00 \x00 " , 3 ) = = 0 ) {
PrintAndLogEx ( WARNING , _RED_ ( " Deleting root aid 000000 is forbidden. " ) ) ;
return PM3_ESOFT ;
}
2020-04-10 07:18:48 +08:00
uint8_t rootaid [ 3 ] = { 0x00 , 0x00 , 0x00 } ;
int res = get_desfire_select_application ( rootaid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
2020-04-10 01:51:35 +08:00
return get_desfire_deleteapp ( aid ) ;
}
2020-04-09 23:15:45 +08:00
static int CmdHF14ADesFormatPICC ( const char * Cmd ) {
2020-04-10 06:36:15 +08:00
CLIParserInit ( " hf mfdes formatpicc " ,
" Formats MIFARE DESFire PICC to factory state " ,
" Usage: \n \t -k PICC key (8 bytes) \n \n "
" Example: \n \t hf mfdes formatpicc -k 0000000000000000 \n "
2020-04-10 07:18:48 +08:00
) ;
2020-04-09 23:15:45 +08:00
2020-04-10 06:36:15 +08:00
void * argtable [ ] = {
2020-04-10 07:18:48 +08:00
arg_param_begin ,
arg_str0 ( " kK " , " key " , " <Key> " , " Key for checking (HEX 16 bytes) " ) ,
arg_param_end
2020-04-10 06:36:15 +08:00
} ;
2020-04-11 06:31:55 +08:00
CLIExecWithReturn ( Cmd , argtable , false ) ;
2020-04-10 04:08:17 +08:00
2020-04-10 06:36:15 +08:00
uint8_t key [ 8 ] = { 0 } ;
int keylen = 8 ;
CLIGetHexWithReturn ( 1 , key , & keylen ) ;
CLIParserFree ( ) ;
2020-04-10 04:08:17 +08:00
2020-04-10 06:36:15 +08:00
if ( ( keylen < 8 ) | | ( keylen > 8 ) ) {
PrintAndLogEx ( ERR , " Specified key must have 8 bytes length. " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-10 06:36:15 +08:00
}
DropField ( ) ;
2020-04-10 07:18:48 +08:00
uint8_t aid [ 3 ] = { 0 } ;
int res = get_desfire_select_application ( aid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
2020-04-11 17:32:31 +08:00
mfdes_authinput_t payload ;
2020-04-11 04:59:55 +08:00
payload . keylen = keylen ;
memcpy ( payload . key , key , keylen ) ;
payload . mode = MFDES_AUTH_PICC ;
payload . algo = MFDES_ALGO_DES ;
payload . keyno = 0 ;
SendCommandNG ( CMD_HF_DESFIRE_AUTH1 , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
2020-04-10 04:08:17 +08:00
PacketResponseNG resp ;
2020-04-11 03:02:46 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_DESFIRE_AUTH1 , & resp , 3000 ) ) {
2020-04-10 04:08:17 +08:00
PrintAndLogEx ( WARNING , " Client command execute timeout " ) ;
DropField ( ) ;
return PM3_ETIMEOUT ;
}
2020-04-11 04:59:55 +08:00
uint8_t isOK = ( resp . status = = PM3_SUCCESS ) ;
2020-04-10 04:08:17 +08:00
if ( isOK ) {
2020-04-11 04:52:16 +08:00
struct {
uint8_t flags ;
uint8_t datalen ;
uint8_t datain [ FRAME_PAYLOAD_SIZE ] ;
} PACKED payload ;
2020-04-11 04:59:55 +08:00
payload . datain [ 0 ] = 0xFC ;
payload . flags = NONE ;
payload . datalen = 1 ;
SendCommandNG ( CMD_HF_DESFIRE_COMMAND , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
2020-04-11 04:52:16 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_DESFIRE_COMMAND , & resp , 3000 ) ) {
2020-04-10 06:36:15 +08:00
PrintAndLogEx ( WARNING , " Client reset command execute timeout " ) ;
DropField ( ) ;
return PM3_ETIMEOUT ;
}
2020-04-11 04:59:55 +08:00
if ( resp . status = = PM3_SUCCESS ) {
2020-04-11 04:52:16 +08:00
/*struct r {
uint8_t len ;
uint8_t data [ RECEIVE_SIZE ] ;
} PACKED ;
struct r * rpayload = ( struct r * ) & resp . data . asBytes ; */
2020-04-10 06:36:15 +08:00
PrintAndLogEx ( INFO , " Card successfully reset " ) ;
return PM3_SUCCESS ;
}
2020-04-10 04:08:17 +08:00
} else {
2020-04-10 06:36:15 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Auth command failed. " ) ) ;
2020-04-09 23:15:45 +08:00
}
return PM3_SUCCESS ;
2020-04-07 00:23:42 +08:00
}
2020-04-10 06:36:15 +08:00
2020-04-09 23:15:45 +08:00
2019-04-13 00:41:14 +08:00
static int CmdHF14ADesInfo ( const char * Cmd ) {
2019-04-10 18:23:40 +08:00
( void ) Cmd ; // Cmd is not used so far
2020-04-11 04:56:45 +08:00
DropField ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_DESFIRE_INFO , NULL , 0 ) ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
2020-03-17 04:51:45 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_DESFIRE_INFO , & resp , 1500 ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Command execute timeout " ) ;
2020-03-19 19:05:29 +08:00
DropField ( ) ;
2019-12-02 18:47:43 +08:00
return PM3_ETIMEOUT ;
2019-03-10 06:35:06 +08:00
}
2020-04-05 00:23:51 +08:00
2020-03-17 04:51:45 +08:00
struct p {
uint8_t isOK ;
uint8_t uid [ 7 ] ;
uint8_t versionHW [ 7 ] ;
uint8_t versionSW [ 7 ] ;
uint8_t details [ 14 ] ;
} PACKED ;
struct p * package = ( struct p * ) resp . data . asBytes ;
2020-04-05 00:23:51 +08:00
2020-03-17 04:51:45 +08:00
if ( resp . status ! = PM3_SUCCESS ) {
switch ( package - > isOK ) {
2019-03-10 06:35:06 +08:00
case 1 :
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( WARNING , " Can't select card " ) ;
break ;
2019-03-10 06:35:06 +08:00
case 2 :
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( WARNING , " Card is most likely not DESFire. Wrong size UID " ) ;
2019-03-10 07:00:59 +08:00
break ;
2019-03-10 06:35:06 +08:00
case 3 :
default :
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Command unsuccessful " ) ) ;
2019-03-10 07:00:59 +08:00
break ;
2019-03-10 06:35:06 +08:00
}
2019-12-02 18:47:43 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2020-04-11 08:32:55 +08:00
2020-04-10 16:31:18 +08:00
nxp_cardtype_t cardtype = getCardType ( package - > versionHW [ 3 ] , package - > versionHW [ 4 ] ) ;
if ( cardtype = = PLUS_EV1 ) {
PrintAndLogEx ( INFO , " Card seems to be MIFARE Plus EV1. Try " _YELLOW_ ( " `hf mfp info` " ) ) ;
return PM3_SUCCESS ;
}
2020-03-17 04:51:45 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Tag Information " ) " --------------------------- " ) ;
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( SUCCESS , " UID: " _GREEN_ ( " %s " ) , sprint_hex ( package - > uid , sizeof ( package - > uid ) ) ) ;
PrintAndLogEx ( SUCCESS , " Batch number: " _GREEN_ ( " %s " ) , sprint_hex ( package - > details + 7 , 5 ) ) ;
PrintAndLogEx ( SUCCESS , " Production date: week " _GREEN_ ( " %02x " ) " / " _GREEN_ ( " 20%02x " ) , package - > details [ 12 ] , package - > details [ 13 ] ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Hardware Information " ) ) ;
PrintAndLogEx ( INFO , " Vendor Id: " _YELLOW_ ( " %s " ) , getTagInfo ( package - > versionHW [ 0 ] ) ) ;
2020-04-10 07:26:37 +08:00
PrintAndLogEx ( INFO , " Type: " _YELLOW_ ( " 0x%02X " ) , package - > versionHW [ 1 ] ) ;
PrintAndLogEx ( INFO , " Subtype: " _YELLOW_ ( " 0x%02X " ) , package - > versionHW [ 2 ] ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( INFO , " Version: %s " , getVersionStr ( package - > versionHW [ 3 ] , package - > versionHW [ 4 ] ) ) ;
PrintAndLogEx ( INFO , " Storage size: %s " , getCardSizeStr ( package - > versionHW [ 5 ] ) ) ;
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( INFO , " Protocol: %s " , getProtocolStr ( package - > versionHW [ 6 ] , true ) ) ;
2020-04-09 23:21:22 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Software Information " ) ) ;
PrintAndLogEx ( INFO , " Vendor Id: " _YELLOW_ ( " %s " ) , getTagInfo ( package - > versionSW [ 0 ] ) ) ;
2020-04-10 07:26:37 +08:00
PrintAndLogEx ( INFO , " Type: " _YELLOW_ ( " 0x%02X " ) , package - > versionSW [ 1 ] ) ;
PrintAndLogEx ( INFO , " Subtype: " _YELLOW_ ( " 0x%02X " ) , package - > versionSW [ 2 ] ) ;
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( INFO , " Version: " _YELLOW_ ( " %d.%d " ) , package - > versionSW [ 3 ] , package - > versionSW [ 4 ] ) ;
PrintAndLogEx ( INFO , " Storage size: %s " , getCardSizeStr ( package - > versionSW [ 5 ] ) ) ;
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( INFO , " Protocol: %s " , getProtocolStr ( package - > versionSW [ 6 ] , false ) ) ;
2019-03-10 06:35:06 +08:00
2020-04-04 18:39:22 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Card capabilities " ) ) ;
2020-03-19 19:05:29 +08:00
uint8_t major = package - > versionSW [ 3 ] ;
uint8_t minor = package - > versionSW [ 4 ] ;
if ( major = = 0 & & minor = = 4 )
PrintAndLogEx ( INFO , " \t 0.4 - DESFire MF3ICD40, No support for APDU (only native commands) " ) ;
if ( major = = 0 & & minor = = 5 )
PrintAndLogEx ( INFO , " \t 0.5 - DESFire MF3ICD40, Support for wrapping commands inside ISO 7816 style APDUs " ) ;
if ( major = = 0 & & minor = = 6 )
PrintAndLogEx ( INFO , " \t 0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility " ) ;
if ( major = = 1 & & minor = = 3 )
2020-04-07 00:23:42 +08:00
PrintAndLogEx ( INFO , " \t 1.3 - DESFire Ev1 MF3ICD21/41/81, Support extended APDU commands, EAL4+ " ) ;
2020-03-19 19:05:29 +08:00
if ( major = = 1 & & minor = = 4 )
2020-04-07 00:23:42 +08:00
PrintAndLogEx ( INFO , " \t 1.4 - DESFire Ev1 MF3ICD21/41/81, EAL4+, N/A (report to iceman!) " ) ;
2020-03-19 19:05:29 +08:00
if ( major = = 2 & & minor = = 0 )
2020-04-07 00:23:42 +08:00
PrintAndLogEx ( INFO , " \t 2.0 - DESFire Ev2, Originality check, proximity check, EAL5 " ) ;
2020-04-06 21:44:58 +08:00
// if (major == 3 && minor == 0)
2020-04-07 00:23:42 +08:00
// PrintAndLogEx(INFO, "\t3.0 - DESFire Ev3, Originality check, proximity check, badass EAL5");
2020-03-19 19:05:29 +08:00
if ( major = = 0 & & minor = = 2 )
PrintAndLogEx ( INFO , " \t 0.2 - DESFire Light, Originality check, " ) ;
2020-04-05 00:23:51 +08:00
2020-04-10 16:31:18 +08:00
if ( cardtype = = DESFIRE_EV2 | | cardtype = = DESFIRE_LIGHT | | cardtype = = DESFIRE_EV3 ) {
// Signature originality check
uint8_t signature [ 56 ] = { 0 } ;
size_t signature_len = 0 ;
2020-04-05 00:23:51 +08:00
2020-04-10 16:31:18 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-04-11 08:32:55 +08:00
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Tag Signature " ) ) ;
2020-04-10 16:31:18 +08:00
if ( get_desfire_signature ( signature , & signature_len ) = = PM3_SUCCESS ) {
desfire_print_signature ( package - > uid , signature , signature_len , cardtype ) ;
} else {
PrintAndLogEx ( WARNING , " --- Card doesn't support GetSignature cmd " ) ;
}
2020-04-10 06:56:37 +08:00
}
2020-03-17 08:50:27 +08:00
2019-03-10 06:35:06 +08:00
// Master Key settings
2020-03-19 19:05:29 +08:00
uint8_t master_aid [ 3 ] = { 0x00 , 0x00 , 0x00 } ;
getKeySettings ( master_aid ) ;
2019-03-10 06:35:06 +08:00
2020-04-10 16:31:18 +08:00
if ( cardtype ! = DESFIRE_LIGHT ) {
// Free memory on card
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Free memory " ) ) ;
uint32_t free_mem = 0 ;
if ( get_desfire_freemem ( & free_mem ) = = PM3_SUCCESS ) {
desfire_print_freemem ( free_mem ) ;
} else {
PrintAndLogEx ( SUCCESS , " Card doesn't support 'free mem' cmd " ) ;
}
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-03-17 04:51:45 +08:00
}
2019-03-10 06:35:06 +08:00
/*
Card Master key ( CMK ) 0x00 AID = 00 00 00 ( card level )
Application Master Key ( AMK ) 0x00 AID ! = 00 00 00
Application keys ( APK ) 0x01 - 0x0D
Application free 0x0E
Application never 0x0F
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
ACCESS RIGHTS :
keys 0 , 1 , 2 , 3 C
keys 4 , 5 , 6 , 7 RW
keys 8 , 9 , 10 , 11 W
keys 12 , 13 , 14 , 15 R
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
*/
2020-03-19 19:05:29 +08:00
DropField ( ) ;
2019-12-02 18:47:43 +08:00
return PM3_SUCCESS ;
2014-09-12 05:23:46 +08:00
}
2014-10-07 01:42:50 +08:00
2020-04-10 07:18:48 +08:00
static void DecodeFileType ( uint8_t filetype ) {
switch ( filetype ) {
2020-04-10 01:15:17 +08:00
case 0x00 :
PrintAndLogEx ( INFO , " File Type: 0x%02X -> Standard Data File " , filetype ) ;
break ;
case 0x01 :
PrintAndLogEx ( INFO , " File Type: 0x%02X -> Backup Data File " , filetype ) ;
break ;
case 0x02 :
PrintAndLogEx ( INFO , " File Type: 0x%02X -> Value Files with Backup " , filetype ) ;
break ;
case 0x03 :
PrintAndLogEx ( INFO , " File Type: 0x%02X -> Linear Record Files with Backup " , filetype ) ;
break ;
case 0x04 :
PrintAndLogEx ( INFO , " File Type: 0x%02X -> Cyclic Record Files with Backup " , filetype ) ;
break ;
default :
PrintAndLogEx ( INFO , " File Type: 0x%02X " , filetype ) ;
break ;
}
}
2020-04-10 07:18:48 +08:00
static void DecodeComSet ( uint8_t comset ) {
switch ( comset ) {
2020-04-10 01:15:17 +08:00
case 0x00 :
PrintAndLogEx ( INFO , " Com.Setting: 0x%02X -> Plain " , comset ) ;
break ;
case 0x01 :
PrintAndLogEx ( INFO , " Com.Setting: 0x%02X -> Plain + MAC " , comset ) ;
break ;
case 0x03 :
PrintAndLogEx ( INFO , " Com.Setting: 0x%02X -> Enciphered " , comset ) ;
break ;
default :
PrintAndLogEx ( INFO , " Com.Setting: 0x%02X " , comset ) ;
break ;
}
}
2020-04-10 07:18:48 +08:00
static char * DecodeAccessValue ( uint8_t value ) {
2020-04-10 16:31:18 +08:00
char * car = ( char * ) calloc ( 255 , sizeof ( char ) ) ;
if ( car = = NULL )
return NULL ;
2020-04-10 07:18:48 +08:00
switch ( value ) {
2020-04-10 01:15:17 +08:00
case 0xE :
strcat ( car , " (Free Access) " ) ;
break ;
case 0xF :
strcat ( car , " (Denied Access) " ) ;
break ;
default :
2020-04-10 07:18:48 +08:00
sprintf ( car , " (Access Key: %d) " , value ) ;
2020-04-10 01:15:17 +08:00
break ;
}
return car ;
}
2020-04-10 07:18:48 +08:00
static void DecodeAccessRights ( uint16_t accrights ) {
int change_access_rights = accrights & 0xF ;
int read_write_access = ( accrights > > 4 ) & 0xF ;
int write_access = ( accrights > > 8 ) & 0xF ;
int read_access = ( accrights > > 12 ) & 0xF ;
char * car = DecodeAccessValue ( change_access_rights ) ;
2020-04-10 16:31:18 +08:00
if ( car = = NULL ) return ;
2020-04-10 07:18:48 +08:00
char * rwa = DecodeAccessValue ( read_write_access ) ;
2020-04-10 16:31:18 +08:00
if ( rwa = = NULL ) return ;
2020-04-11 08:32:55 +08:00
2020-04-10 07:18:48 +08:00
char * wa = DecodeAccessValue ( write_access ) ;
2020-04-10 16:31:18 +08:00
if ( wa = = NULL ) return ;
2020-04-10 07:18:48 +08:00
char * ra = DecodeAccessValue ( read_access ) ;
2020-04-10 16:31:18 +08:00
if ( ra = = NULL ) return ;
2020-04-10 07:18:48 +08:00
PrintAndLogEx ( INFO , " Access Rights: 0x%04X - Change %s - RW %s - W %s - R %s " , accrights , car , rwa , wa , ra ) ;
2020-04-10 01:15:17 +08:00
free ( car ) ;
free ( rwa ) ;
free ( wa ) ;
free ( ra ) ;
}
2020-04-10 16:31:18 +08:00
static int DecodeFileSettings ( uint8_t * src , int src_len , int maclen ) {
uint8_t filetype = src [ 0 ] ;
uint8_t comset = src [ 1 ] ;
2020-04-10 01:15:17 +08:00
2020-04-10 16:31:18 +08:00
uint16_t accrights = ( src [ 4 ] < < 8 ) + src [ 3 ] ;
if ( src_len = = 1 + 1 + 2 + 3 + maclen ) {
int filesize = ( src [ 7 ] < < 16 ) + ( src [ 6 ] < < 8 ) + src [ 5 ] ;
2020-04-10 01:15:17 +08:00
DecodeFileType ( filetype ) ;
DecodeComSet ( comset ) ;
DecodeAccessRights ( accrights ) ;
PrintAndLogEx ( INFO , " Filesize: %d " , filesize ) ;
return PM3_SUCCESS ;
2020-04-10 16:31:18 +08:00
} else if ( src_len = = 1 + 1 + 2 + 4 + 4 + 4 + 1 + maclen ) {
int lowerlimit = ( src [ 8 ] < < 24 ) + ( src [ 7 ] < < 16 ) + ( src [ 6 ] < < 8 ) + src [ 5 ] ;
int upperlimit = ( src [ 12 ] < < 24 ) + ( src [ 11 ] < < 16 ) + ( src [ 10 ] < < 8 ) + src [ 9 ] ;
int limitcredvalue = ( src [ 16 ] < < 24 ) + ( src [ 15 ] < < 16 ) + ( src [ 14 ] < < 8 ) + src [ 13 ] ;
uint8_t limited_credit_enabled = src [ 17 ] ;
2020-04-10 01:15:17 +08:00
DecodeFileType ( filetype ) ;
DecodeComSet ( comset ) ;
DecodeAccessRights ( accrights ) ;
PrintAndLogEx ( INFO , " Lower limit: %d - Upper limit: %d - limited credit value: %d - limited credit enabled: %d " , lowerlimit , upperlimit , limitcredvalue , limited_credit_enabled ) ;
return PM3_SUCCESS ;
2020-04-11 09:10:02 +08:00
} else if ( src_len = = 1 + 1 + 2 + 3 + 3 + 3 + maclen ) {
int recordsize = ( src [ 7 ] < < 16 ) + ( src [ 6 ] < < 8 ) + src [ 5 ] ;
int maxrecords = ( src [ 10 ] < < 16 ) + ( src [ 9 ] < < 8 ) + src [ 8 ] ;
int currentrecord = ( src [ 13 ] < < 16 ) + ( src [ 12 ] < < 8 ) + src [ 11 ] ;
DecodeFileType ( filetype ) ;
DecodeComSet ( comset ) ;
DecodeAccessRights ( accrights ) ;
PrintAndLogEx ( INFO , " Record size: %d - MaxNumberRecords: %d - Current Number Records: %d " , recordsize , maxrecords , currentrecord ) ;
return PM3_SUCCESS ;
2020-04-10 01:15:17 +08:00
}
return PM3_ESOFT ;
}
2019-04-13 00:41:14 +08:00
static int CmdHF14ADesEnumApplications ( const char * Cmd ) {
2019-04-10 18:23:40 +08:00
( void ) Cmd ; // Cmd is not used so far
2020-04-11 04:56:45 +08:00
DropField ( ) ;
2020-03-19 19:05:29 +08:00
// uint8_t isOK = 0x00;
2020-04-09 04:44:51 +08:00
uint8_t aid [ 3 ] = { 0 } ;
2020-03-19 19:05:29 +08:00
uint8_t app_ids [ 78 ] = { 0 } ;
uint8_t app_ids_len = 0 ;
2020-04-05 00:23:51 +08:00
2020-03-19 19:05:29 +08:00
uint8_t file_ids [ 33 ] = { 0 } ;
uint8_t file_ids_len = 0 ;
2020-04-05 00:23:51 +08:00
2020-04-10 07:18:48 +08:00
dfname_t dfnames [ 255 ] ;
2020-04-08 03:52:59 +08:00
uint8_t dfname_count = 0 ;
2020-04-08 03:30:12 +08:00
2020-04-10 07:18:48 +08:00
int res = 0 ;
2020-04-09 23:15:45 +08:00
2020-03-19 19:05:29 +08:00
if ( get_desfire_appids ( app_ids , & app_ids_len ) ! = PM3_SUCCESS ) {
PrintAndLogEx ( ERR , " Can't get list of applications on tag " ) ;
2020-04-09 04:44:51 +08:00
DropField ( ) ;
2019-12-02 18:47:43 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2020-04-05 00:23:51 +08:00
2020-04-08 03:52:59 +08:00
if ( get_desfire_dfnames ( dfnames , & dfname_count ) ! = PM3_SUCCESS ) {
2020-04-08 03:30:12 +08:00
PrintAndLogEx ( WARNING , _RED_ ( " Can't get DF Names " ) ) ;
DropField ( ) ;
return PM3_ESOFT ;
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-03-19 19:05:29 +08:00
PrintAndLogEx ( INFO , " -- Mifare DESFire Enumerate applications -------------------- " ) ;
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-04-05 00:23:51 +08:00
PrintAndLogEx ( SUCCESS , " Tag report " _GREEN_ ( " %d " ) " application%c " , app_ids_len / 3 , ( app_ids_len = = 3 ) ? ' ' : ' s ' ) ;
2020-03-19 19:05:29 +08:00
for ( int i = 0 ; i < app_ids_len ; i + = 3 ) {
2019-03-10 06:35:06 +08:00
2020-03-19 19:05:29 +08:00
aid [ 0 ] = app_ids [ i ] ;
aid [ 1 ] = app_ids [ i + 1 ] ;
aid [ 2 ] = app_ids [ i + 2 ] ;
2020-04-05 00:23:51 +08:00
2020-04-08 03:30:12 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
if ( memcmp ( aid , " \x00 \x00 \x00 " , 3 ) = = 0 ) {
// CARD MASTER KEY
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " CMK - PICC, Card Master Key settings " ) ) ;
2020-04-08 03:52:59 +08:00
} else {
2020-04-08 03:30:12 +08:00
PrintAndLogEx ( SUCCESS , " --- " _CYAN_ ( " AMK - Application Master Key settings " ) ) ;
}
2020-04-11 06:31:55 +08:00
PrintAndLogEx ( SUCCESS , " AID : " _GREEN_ ( " %02X%02X%02X " ) , aid [ 2 ] , aid [ 1 ] , aid [ 0 ] ) ;
2020-04-08 03:52:59 +08:00
for ( int m = 0 ; m < dfname_count ; m + + ) {
if ( dfnames [ m ] . aid [ 0 ] = = aid [ 0 ] & & dfnames [ m ] . aid [ 1 ] = = aid [ 1 ] & & dfnames [ m ] . aid [ 2 ] = = aid [ 2 ] ) {
2020-04-11 06:31:55 +08:00
PrintAndLogEx ( SUCCESS , " - DF " _YELLOW_ ( " %02X%02X " ) " Name : " _YELLOW_ ( " %s " ) , dfnames [ m ] . fid [ 1 ] , dfnames [ m ] . fid [ 0 ] , dfnames [ m ] . name ) ;
2020-04-08 03:52:59 +08:00
}
2020-04-08 03:30:12 +08:00
}
2019-03-10 06:35:06 +08:00
2020-04-10 07:18:48 +08:00
res = getKeySettings ( aid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
2019-03-10 06:35:06 +08:00
2020-04-10 07:18:48 +08:00
res = get_desfire_select_application ( aid ) ;
2020-04-10 04:08:17 +08:00
2020-04-07 00:23:42 +08:00
2019-03-10 06:35:06 +08:00
// Get File IDs
2020-03-19 19:05:29 +08:00
if ( get_desfire_fileids ( file_ids , & file_ids_len ) = = PM3_SUCCESS ) {
2020-04-05 00:23:51 +08:00
PrintAndLogEx ( SUCCESS , " Tag report " _GREEN_ ( " %d " ) " file%c " , file_ids_len , ( file_ids_len = = 1 ) ? ' ' : ' s ' ) ;
2020-03-24 20:06:09 +08:00
for ( int j = 0 ; j < file_ids_len ; + + j ) {
PrintAndLogEx ( SUCCESS , " Fileid %d (0x%02x) " , file_ids [ j ] , file_ids [ j ] ) ;
2020-04-08 03:30:12 +08:00
2020-04-07 00:23:42 +08:00
uint8_t filesettings [ 20 ] = { 0 } ;
2020-04-09 04:44:51 +08:00
int fileset_len = 0 ;
2020-04-11 19:14:16 +08:00
int res = get_desfire_filesettings ( file_ids [ j ] , filesettings , & fileset_len ) ;
2020-04-10 07:18:48 +08:00
int maclen = 0 ; // To be implemented
2020-04-07 00:23:42 +08:00
if ( res = = PM3_SUCCESS ) {
2020-04-10 07:18:48 +08:00
if ( DecodeFileSettings ( filesettings , fileset_len , maclen ) ! = PM3_SUCCESS ) {
2020-04-10 01:15:17 +08:00
PrintAndLogEx ( INFO , " Settings [%u] %s " , fileset_len , sprint_hex ( filesettings , fileset_len ) ) ;
}
2020-04-07 00:23:42 +08:00
}
2019-03-10 06:35:06 +08:00
}
}
2020-04-08 03:52:59 +08:00
2020-04-05 06:07:05 +08:00
/*
// Get ISO File IDs
{
uint8_t data [ ] = { GET_ISOFILE_IDS , 0x00 , 0x00 , 0x00 } ; // 0x61
SendCommandMIX ( CMD_HF_DESFIRE_COMMAND , DISCONNECT , sizeof ( data ) , 0 , data , sizeof ( data ) ) ;
}
2019-03-10 06:35:06 +08:00
2020-04-05 06:07:05 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & respFiles , 1500 ) ) {
PrintAndLogEx ( WARNING , _RED_ ( " Timed-out " ) ) ;
continue ;
} else {
isOK = respFiles . data . asBytes [ 2 ] & 0xff ;
if ( ! isOK ) {
PrintAndLogEx ( WARNING , _RED_ ( " Can't get ISO file ids " ) ) ;
} else {
int respfileLen = resp . oldarg [ 1 ] - 3 - 2 ;
for ( int j = 0 ; j < respfileLen ; + + j ) {
PrintAndLogEx ( SUCCESS , " ISO Fileid %d : " , resp . data . asBytes [ j + 3 ] ) ;
}
}
2019-03-10 06:35:06 +08:00
}
2020-04-05 06:07:05 +08:00
*/
2019-03-10 06:35:06 +08:00
}
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-03-19 19:05:29 +08:00
DropField ( ) ;
2019-12-02 18:47:43 +08:00
return PM3_SUCCESS ;
2014-09-12 05:23:46 +08:00
}
2020-04-08 19:26:44 +08:00
2020-03-19 19:05:29 +08:00
// MIAFRE DESFire Authentication
2014-09-12 05:23:46 +08:00
//
2019-03-09 15:59:13 +08:00
# define BUFSIZE 256
2019-04-13 00:41:14 +08:00
static int CmdHF14ADesAuth ( const char * Cmd ) {
2020-04-10 07:18:48 +08:00
int res = 0 ;
2020-04-10 06:36:15 +08:00
DropField ( ) ;
2019-03-10 06:35:06 +08:00
// NR DESC KEYLENGHT
// ------------------------
// 1 = DES 8
// 2 = 3DES 16
// 3 = 3K 3DES 24
// 4 = AES 16
uint8_t keylength = 8 ;
2019-03-09 15:59:13 +08:00
2020-04-09 04:44:51 +08:00
CLIParserInit ( " hf mfdes auth " ,
" Authenticates Mifare DESFire using Key " ,
2020-04-12 23:10:27 +08:00
" Usage: \n \t -m Auth type (1=normal, 2=iso, 3=aes) \n \t -t Crypt algo (1=DES, 2=3DES(2K2DES), 3=3K3DES, 5=AES) \n \t -a aid (3 bytes) \n \t -n keyno \n \t -k key (8-24 bytes) \n \n "
" Example: \n \t hf mfdes auth -m 3 -t 4 -a 808301 -n 0 -k 00000000000000000000000000000000 (AES) "
" \n \t hf mfdes auth -m 2 -t 2 -a 000000 -n 0 -k 00000000000000000000000000000000 (3DES) "
" \n \t hf mfdes auth -m 1 -t 1 -a 000000 -n 0 -k 0000000000000000 (DES) "
2020-04-09 04:44:51 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-04-11 07:41:39 +08:00
arg_int0 ( " mM " , " type " , " Auth type (1=normal, 2=iso, 3=aes, 4=picc) " , NULL ) ,
2020-04-12 23:10:27 +08:00
arg_int0 ( " tT " , " algo " , " Crypt algo (1=DES, 2=3DES(2K2DES), 4=3K3DES, 5=AES) " , NULL ) ,
2020-04-11 07:38:47 +08:00
arg_strx0 ( " aA " , " aid " , " <aid> " , " AID used for authentification (HEX 3 bytes) " ) ,
2020-04-09 04:44:51 +08:00
arg_int0 ( " nN " , " keyno " , " Key number used for authentification " , NULL ) ,
arg_str0 ( " kK " , " key " , " <Key> " , " Key for checking (HEX 16 bytes) " ) ,
arg_param_end
} ;
2020-04-11 06:31:55 +08:00
CLIExecWithReturn ( Cmd , argtable , false ) ;
2020-04-09 04:44:51 +08:00
uint8_t cmdAuthMode = arg_get_int_def ( 1 , 0 ) ;
uint8_t cmdAuthAlgo = arg_get_int_def ( 2 , 0 ) ;
int aidlength = 3 ;
uint8_t aid [ 3 ] = { 0 } ;
CLIGetHexWithReturn ( 3 , aid , & aidlength ) ;
2020-04-11 17:32:31 +08:00
swap24 ( aid ) ;
2020-04-09 04:44:51 +08:00
uint8_t cmdKeyNo = arg_get_int_def ( 4 , 0 ) ;
uint8_t key [ 24 ] = { 0 } ;
int keylen = 0 ;
CLIGetHexWithReturn ( 5 , key , & keylen ) ;
CLIParserFree ( ) ;
if ( ( keylen < 8 ) | | ( keylen > 24 ) ) {
2020-04-11 08:32:55 +08:00
PrintAndLogEx ( ERR , " Specified key must have %d bytes length. " , keylen ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-09 15:59:13 +08:00
}
2020-04-09 04:44:51 +08:00
2020-04-07 15:14:44 +08:00
// AID
2020-04-09 04:44:51 +08:00
if ( aidlength ! = 3 ) {
2020-04-07 15:14:44 +08:00
PrintAndLogEx ( WARNING , " aid must include %d HEX symbols " , 3 ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-07 15:14:44 +08:00
}
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
switch ( cmdAuthMode ) {
2020-04-11 08:56:08 +08:00
case MFDES_AUTH_DES :
if ( cmdAuthAlgo ! = MFDES_ALGO_DES & & cmdAuthAlgo ! = MFDES_ALGO_3DES ) {
PrintAndLogEx ( NORMAL , " Crypto algo not valid for the auth des mode " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
break ;
2020-04-11 08:56:08 +08:00
case MFDES_AUTH_ISO :
2020-04-12 23:10:27 +08:00
if ( cmdAuthAlgo ! = MFDES_ALGO_3DES & & cmdAuthAlgo ! = MFDES_ALGO_3K3DES ) {
2020-04-11 08:56:08 +08:00
PrintAndLogEx ( NORMAL , " Crypto algo not valid for the auth iso mode " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
break ;
2020-04-11 08:56:08 +08:00
case MFDES_AUTH_AES :
if ( cmdAuthAlgo ! = MFDES_ALGO_AES ) {
PrintAndLogEx ( NORMAL , " Crypto algo not valid for the auth aes mode " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2020-04-11 08:56:08 +08:00
}
break ;
case MFDES_AUTH_PICC :
if ( cmdAuthAlgo ! = MFDES_AUTH_DES ) {
PrintAndLogEx ( NORMAL , " Crypto algo not valid for the auth picc mode " ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
break ;
default :
2020-04-09 04:44:51 +08:00
PrintAndLogEx ( WARNING , " Wrong Auth mode (%d) -> (1=normal, 2=iso, 3=aes) " , cmdAuthMode ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
switch ( cmdAuthAlgo ) {
2020-04-11 08:56:08 +08:00
case MFDES_ALGO_3DES :
2019-03-10 06:35:06 +08:00
keylength = 16 ;
2020-04-12 23:10:27 +08:00
PrintAndLogEx ( NORMAL , " 2 key 3DES selected " ) ;
2019-03-10 06:35:06 +08:00
break ;
2020-04-11 08:56:08 +08:00
case MFDES_ALGO_3K3DES :
2019-03-10 06:35:06 +08:00
keylength = 24 ;
PrintAndLogEx ( NORMAL , " 3 key 3DES selected " ) ;
break ;
2020-04-11 08:56:08 +08:00
case MFDES_ALGO_AES :
2019-03-10 06:35:06 +08:00
keylength = 16 ;
PrintAndLogEx ( NORMAL , " AES selected " ) ;
break ;
default :
2020-04-11 08:56:08 +08:00
cmdAuthAlgo = MFDES_ALGO_DES ;
2019-03-10 06:35:06 +08:00
keylength = 8 ;
PrintAndLogEx ( NORMAL , " DES selected " ) ;
break ;
}
2020-04-09 04:44:51 +08:00
// KEY
if ( keylen ! = keylength ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Key must include %d HEX symbols " , keylength ) ;
2020-04-11 17:32:31 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
2019-12-02 18:47:43 +08:00
2020-04-09 04:44:51 +08:00
2020-04-10 07:18:48 +08:00
res = get_desfire_select_application ( aid ) ;
if ( res ! = PM3_SUCCESS ) return res ;
2020-04-10 06:36:15 +08:00
2020-04-10 07:18:48 +08:00
if ( memcmp ( aid , " \x00 \x00 \x00 " , 3 ) ! = 0 ) {
2020-04-10 04:08:17 +08:00
uint8_t file_ids [ 33 ] = { 0 } ;
uint8_t file_ids_len = 0 ;
res = get_desfire_fileids ( file_ids , & file_ids_len ) ;
if ( res ! = PM3_SUCCESS ) return res ;
}
2020-04-07 15:14:44 +08:00
2020-04-11 17:32:31 +08:00
mfdes_authinput_t payload ;
2020-04-11 04:59:55 +08:00
payload . keylen = keylength ;
memcpy ( payload . key , key , keylength ) ;
payload . mode = cmdAuthMode ;
payload . algo = cmdAuthAlgo ;
payload . keyno = cmdKeyNo ;
2020-04-12 23:10:27 +08:00
/*SendCommandNG(CMD_HF_DESFIRE_AUTH1, (uint8_t *)&payload, sizeof(payload));
2020-04-11 03:02:46 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
2020-04-11 03:02:46 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_DESFIRE_AUTH1 , & resp , 3000 ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Client command execute timeout " ) ;
2020-04-09 04:44:51 +08:00
DropField ( ) ;
2019-12-02 18:47:43 +08:00
return PM3_ETIMEOUT ;
2019-03-10 06:35:06 +08:00
}
2020-04-12 23:10:27 +08:00
*/
mfdes_auth_res_t rpayload ;
if ( get_desfire_auth ( & payload , & rpayload ) = = PM3_SUCCESS )
{
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( SUCCESS , " Key : " _GREEN_ ( " %s " ) , sprint_hex ( key , keylength ) ) ;
2020-04-12 23:10:27 +08:00
PrintAndLogEx ( SUCCESS , " SESSION : " _GREEN_ ( " %s " ) , sprint_hex ( rpayload . sessionkey , keylength ) ) ;
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2019-03-10 07:00:59 +08:00
} else {
2020-04-12 23:10:27 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2020-03-15 20:32:53 +08:00
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2019-12-02 18:47:43 +08:00
return PM3_SUCCESS ;
2014-09-12 05:23:46 +08:00
}
2020-04-07 15:23:34 +08:00
static int CmdHF14ADesList ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
return CmdTraceList ( " des " ) ;
}
2020-04-12 23:10:27 +08:00
static int CmdTest ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
uint8_t IV [ 8 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
uint8_t key [ 16 ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 } ;
/*[=] encRndB: 1A BE 10 8D 09 E0 18 13
[ = ] RndB : 57 9 B 94 21 40 2 C C6 D7
[ = ] 3 keyenc : 6 E 6 A EB 86 6 E 6 A EB 86 9 B 94 21 40 2 C C6 D7 00
6 E 6 A EB 86 6 E 6 A EB 86 9 B 94 21 40 2 C C6 D7 57
[ = ] Both : 32 B2 E4 1 A 14 CF 8 B 34 B4 F9 30 43 5 B 68 A3 FD
[ = ] RndA : 6 E 6 A EB 86 6 E 6 A EB 86
*/
uint8_t encRndB [ 8 ] = { 0x1A , 0xBE , 0x10 , 0x8D , 0x09 , 0xE0 , 0x18 , 0x13 } ;
/*
* RndB_enc : DE 50 F9 23 10 CA F5 A5
* RndB : 4 C 64 7 E 56 72 E2 A6 51
* RndB_rot : 64 7 E 56 72 E2 A6 51 4 C
* RndA : C9 6 C E3 5 E 4 D 60 87 F2
* RndAB : C9 6 C E3 5 E 4 D 60 87 F2 64 7 E 56 72 E2 A6 51 4 C
* RndAB_enc : E0 06 16 66 87 04 D5 54 9 C 8 D 6 A 13 A0 F8 FC ED
*/
uint8_t RndB [ 8 ] = { 0 } ;
uint8_t RndA [ 8 ] = { 0x6E , 0x6A , 0xEB , 0x86 , 0x6E , 0x6A , 0xEB , 0x86 } ;
tdes_nxp_receive ( encRndB , RndB , 8 , key , IV , 2 ) ;
uint8_t rotRndB [ 8 ] = { 0 } ;
memcpy ( rotRndB , RndB , 8 ) ;
rol ( rotRndB , 8 ) ;
uint8_t tmp [ 16 ] = { 0x00 } ;
uint8_t both [ 16 ] = { 0x00 } ;
memcpy ( tmp , RndA , 8 ) ;
memcpy ( tmp + 8 , rotRndB , 8 ) ;
PrintAndLogEx ( INFO , " 3keyenc: %s " , sprint_hex ( tmp , 16 ) ) ;
PrintAndLogEx ( SUCCESS , " Res : " _GREEN_ ( " %s " ) , sprint_hex ( IV , 8 ) ) ;
tdes_nxp_send ( tmp , both , 16 , key , IV , 2 ) ;
PrintAndLogEx ( SUCCESS , " Res : " _GREEN_ ( " %s " ) , sprint_hex ( both , 16 ) ) ;
return PM3_SUCCESS ;
}
2016-01-13 05:30:22 +08:00
static command_t CommandTable [ ] = {
2020-04-05 06:07:05 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2020-04-12 23:10:27 +08:00
{ " test " , CmdTest , AlwaysAvailable , " Test " } ,
2020-04-05 06:07:05 +08:00
{ " info " , CmdHF14ADesInfo , IfPm3Iso14443a , " Tag information " } ,
2020-04-07 15:23:34 +08:00
{ " list " , CmdHF14ADesList , AlwaysAvailable , " List DESFire (ISO 14443A) history " } ,
2020-04-05 06:07:05 +08:00
{ " enum " , CmdHF14ADesEnumApplications , IfPm3Iso14443a , " Tries enumerate all applications " } ,
{ " auth " , CmdHF14ADesAuth , IfPm3Iso14443a , " Tries a MIFARE DesFire Authentication " } ,
2020-04-10 01:22:57 +08:00
{ " createaid " , CmdHF14ADesCreateApp , IfPm3Iso14443a , " Create Application ID " } ,
2020-04-10 01:51:35 +08:00
{ " deleteaid " , CmdHF14ADesDeleteApp , IfPm3Iso14443a , " Delete Application ID " } ,
2020-04-10 06:36:15 +08:00
{ " formatpicc " , CmdHF14ADesFormatPICC , IfPm3Iso14443a , " Format PICC " } ,
2019-05-02 05:38:57 +08:00
// {"rdbl", CmdHF14ADesRb, IfPm3Iso14443a, "Read MIFARE DesFire block"},
// {"wrbl", CmdHF14ADesWb, IfPm3Iso14443a, "write MIFARE DesFire block"},
2020-04-11 08:32:55 +08:00
/*
ISO / IEC 7816 Cmds
' A4 ' Select
' B0 ' Read Binary
' D6 ' Update Binary
' B2 ' Read Records
' E2 ' Append Records
' 84 ' Get Challenge
' 88 ' Internal Authenticate
' 82 ' External Authenticate
2020-04-11 07:38:47 +08:00
2020-04-11 08:32:55 +08:00
*/
2020-04-05 06:07:05 +08:00
{ NULL , NULL , NULL , NULL }
2014-09-12 05:23:46 +08:00
} ;
2019-04-13 00:41:14 +08:00
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
2019-12-02 18:47:43 +08:00
return PM3_SUCCESS ;
2019-04-13 00:41:14 +08:00
}
2019-03-10 18:20:22 +08:00
int CmdHFMFDes ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2014-09-12 05:23:46 +08:00
}