proxmark3/armsrc/mifarecmd.c
iceman1001 5ee53a0e75 ADD: There were lot of calls to enable tracing, but very few to turn it of afterwards in the methods.
Don't know if it has some influence but can't hurt calling  "set_tracing(FALSE);"  when method returns.
2015-10-11 19:14:17 +02:00

1369 lines
35 KiB
C

//-----------------------------------------------------------------------------
// Merlok - June 2011, 2012
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
// Midnitesnake - Dec 2013
// Andy Davies - Apr 2014
// Iceman - May 2014
//
// 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.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
#include "mifarecmd.h"
#include "apps.h"
#include "util.h"
#include "crc.h"
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
ui64Key = bytes_to_num(datain, 6);
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16];
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
break;
};
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
bool turnOffField = (arg0 == 1);
LED_A_ON(); LED_B_OFF(); LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
};
if(!mifare_ultra_auth(keybytes)){
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed");
OnError(1);
return;
}
if (turnOffField) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
cmd_send(CMD_ACK,1,0,0,0,0);
}
// Arg0 = BlockNo,
// Arg1 = UsePwd bool
// datain = PWD bytes,
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
{
uint8_t blockNo = arg0;
byte_t dataout[16] = {0x00};
bool useKey = (arg1 == 1); //UL_C
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
int len = iso14443a_select_card(NULL, NULL, NULL);
if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
OnError(1);
return;
}
// UL-C authentication
if ( useKey ) {
uint8_t key[16] = {0x00};
memcpy(key, datain, sizeof(key) );
if ( !mifare_ultra_auth(key) ) {
OnError(1);
return;
}
}
// UL-EV1 / NTAG authentication
if ( usePwd ) {
uint8_t pwd[4] = {0x00};
memcpy(pwd, datain, 4);
uint8_t pack[4] = {0,0,0,0};
if (!mifare_ul_ev1_auth(pwd, pack)) {
OnError(1);
return;
}
}
if( mifare_ultra_readblock(blockNo, dataout) ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error");
OnError(2);
return;
}
if( mifare_ultra_halt() ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error");
OnError(3);
return;
}
cmd_send(CMD_ACK,1,0,0,dataout,16);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)
//-----------------------------------------------------------------------------
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
// params
uint8_t sectorNo = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
ui64Key = bytes_to_num(datain, 6);
// variables
byte_t isOK = 0;
byte_t dataoutbuf[16 * 16];
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
isOK = 1;
if(!iso14443a_select_card(uid, NULL, &cuid)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
}
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
break;
}
}
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
}
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo));
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
// arg0 = blockNo (start)
// arg1 = Pages (number of blocks)
// arg2 = useKey
// datain = KEY bytes
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
{
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// free eventually allocated BigBuf memory
BigBuf_free();
clear_trace();
// params
uint8_t blockNo = arg0;
uint16_t blocks = arg1;
bool useKey = (arg2 == 1); //UL_C
bool usePwd = (arg2 == 2); //UL_EV1/NTAG
uint32_t countblocks = 0;
uint8_t *dataout = BigBuf_malloc(CARD_MEMORY_SIZE);
if (dataout == NULL){
Dbprintf("out of memory");
OnError(1);
return;
}
int len = iso14443a_select_card(NULL, NULL, NULL);
if (!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len);
OnError(1);
return;
}
// UL-C authentication
if ( useKey ) {
uint8_t key[16] = {0x00};
memcpy(key, datain, sizeof(key) );
if ( !mifare_ultra_auth(key) ) {
OnError(1);
return;
}
}
// UL-EV1 / NTAG authentication
if (usePwd) {
uint8_t pwd[4] = {0x00};
memcpy(pwd, datain, sizeof(pwd));
uint8_t pack[4] = {0,0,0,0};
if (!mifare_ul_ev1_auth(pwd, pack)){
OnError(1);
return;
}
}
for (int i = 0; i < blocks; i++){
if ((i*4) + 4 >= CARD_MEMORY_SIZE) {
Dbprintf("Data exceeds buffer!!");
break;
}
len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i);
if (len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block %d error",i);
// if no blocks read - error out
if (i==0){
OnError(2);
return;
} else {
//stop at last successful read block and return what we got
break;
}
} else {
countblocks++;
}
}
len = mifare_ultra_halt();
if (len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error");
OnError(3);
return;
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks);
countblocks *= 4;
cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
BigBuf_free();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Write a MIFARE tag.
// read block
//-----------------------------------------------------------------------------
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
// params
uint8_t blockNo = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
byte_t blockdata[16];
ui64Key = bytes_to_num(datain, 6);
memcpy(blockdata, datain + 10, 16);
// variables
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
};
if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break;
};
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
isOK = 1;
break;
}
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
// Thats it...
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
/* // Command not needed but left for future testing
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
{
uint8_t blockNo = arg0;
byte_t blockdata[16] = {0x00};
memcpy(blockdata, datain, 16);
uint8_t uid[10] = {0x00};
LED_A_ON(); LED_B_OFF(); LED_C_OFF();
clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if(!iso14443a_select_card(uid, NULL, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0);
return;
};
if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(0);
return; };
if(mifare_ultra_halt()) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
OnError(0);
return;
};
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
*/
// Arg0 : Block to write to.
// Arg1 : 0 = use no authentication.
// 1 = use 0x1A authentication.
// 2 = use 0x1B authentication.
// datain : 4 first bytes is data to be written.
// : 4/16 next bytes is authentication key.
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
{
uint8_t blockNo = arg0;
bool useKey = (arg1 == 1); //UL_C
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
byte_t blockdata[4] = {0x00};
memcpy(blockdata, datain,4);
LEDsoff();
LED_A_ON();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0);
return;
};
// UL-C authentication
if ( useKey ) {
uint8_t key[16] = {0x00};
memcpy(key, datain+4, sizeof(key) );
if ( !mifare_ultra_auth(key) ) {
OnError(1);
return;
}
}
// UL-EV1 / NTAG authentication
if (usePwd) {
uint8_t pwd[4] = {0x00};
memcpy(pwd, datain+4, 4);
uint8_t pack[4] = {0,0,0,0};
if (!mifare_ul_ev1_auth(pwd, pack)) {
OnError(1);
return;
}
}
if(mifare_ultra_writeblock(blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(0);
return;
};
if(mifare_ultra_halt()) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
OnError(0);
return;
};
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
uint8_t pwd[16] = {0x00};
byte_t blockdata[4] = {0x00};
memcpy(pwd, datain, 16);
LED_A_ON(); LED_B_OFF(); LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0);
return;
};
blockdata[0] = pwd[7];
blockdata[1] = pwd[6];
blockdata[2] = pwd[5];
blockdata[3] = pwd[4];
if(mifare_ultra_writeblock( 44, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(44);
return;
};
blockdata[0] = pwd[3];
blockdata[1] = pwd[2];
blockdata[2] = pwd[1];
blockdata[3] = pwd[0];
if(mifare_ultra_writeblock( 45, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(45);
return;
};
blockdata[0] = pwd[15];
blockdata[1] = pwd[14];
blockdata[2] = pwd[13];
blockdata[3] = pwd[12];
if(mifare_ultra_writeblock( 46, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(46);
return;
};
blockdata[0] = pwd[11];
blockdata[1] = pwd[10];
blockdata[2] = pwd[9];
blockdata[3] = pwd[8];
if(mifare_ultra_writeblock( 47, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(47);
return;
};
if(mifare_ultra_halt()) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
OnError(0);
return;
};
cmd_send(CMD_ACK,1,0,0,0,0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
// Return 1 if the nonce is invalid else return 0
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \
(oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \
(oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;
}
//-----------------------------------------------------------------------------
// MIFARE nested authentication.
//
//-----------------------------------------------------------------------------
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain)
{
// params
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
uint8_t targetBlockNo = arg1 & 0xff;
uint8_t targetKeyType = (arg1 >> 8) & 0xff;
uint64_t ui64Key = 0;
ui64Key = bytes_to_num(datain, 6);
// variables
uint16_t rtr, i, j, len;
uint16_t davg;
static uint16_t dmin, dmax;
uint8_t uid[10];
uint32_t cuid, nt1, nt2, nttmp, nttest, ks1;
uint8_t par[1];
uint32_t target_nt[2], target_ks[2];
uint8_t par_array[4];
uint16_t ncount = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint32_t auth1_time, auth2_time;
static uint16_t delta_time;
LED_A_ON();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// free eventually allocated BigBuf memory
BigBuf_free();
if (calibrate) clear_trace();
set_tracing(true);
// statistics on nonce distance
int16_t isOK = 0;
#define NESTED_MAX_TRIES 12
uint16_t unsuccessfull_tries = 0;
if (calibrate) { // for first call only. Otherwise reuse previous calibration
LED_B_ON();
WDT_HIT();
davg = dmax = 0;
dmin = 2000;
delta_time = 0;
for (rtr = 0; rtr < 17; rtr++) {
// Test if the action was cancelled
if(BUTTON_PRESS()) {
isOK = -2;
break;
}
// prepare next select. No need to power down the card.
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
rtr--;
continue;
}
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
rtr--;
continue;
};
auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
rtr--;
continue;
};
if (delta_time) {
auth2_time = auth1_time + delta_time;
} else {
auth2_time = 0;
}
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");
rtr--;
continue;
};
nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160
for (i = 101; i < 1200; i++) {
nttmp = prng_successor(nttmp, 1);
if (nttmp == nt2) break;
}
if (i != 1200) {
if (rtr != 0) {
davg += i;
dmin = MIN(dmin, i);
dmax = MAX(dmax, i);
}
else {
delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing
}
if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i);
} else {
unsuccessfull_tries++;
if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable)
isOK = -3;
}
}
}
davg = (davg + (rtr - 1)/2) / (rtr - 1);
if (MF_DBGLEVEL >= 3) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, dmin, dmax, davg, delta_time);
dmin = davg - 2;
dmax = davg + 2;
LED_B_OFF();
}
// -------------------------------------------------------------------------------------------------
LED_C_ON();
// get crypted nonces for target sector
for(i=0; i < 2 && !isOK; i++) { // look for exactly two different nonces
target_nt[i] = 0;
while(target_nt[i] == 0) { // continue until we have an unambiguous nonce
// prepare next select. No need to power down the card.
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
continue;
}
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
continue;
};
auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
continue;
};
// nested authentication
auth2_time = auth1_time + delta_time;
len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);
if (len != 4) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);
continue;
};
nt2 = bytes_to_num(receivedAnswer, 4);
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]);
// Parity validity check
for (j = 0; j < 4; j++) {
par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01));
}
ncount = 0;
nttest = prng_successor(nt1, dmin - 1);
for (j = dmin; j < dmax + 1; j++) {
nttest = prng_successor(nttest, 1);
ks1 = nt2 ^ nttest;
if (valid_nonce(nttest, nt2, ks1, par_array)){
if (ncount > 0) { // we are only interested in disambiguous nonces, try again
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);
target_nt[i] = 0;
break;
}
target_nt[i] = nttest;
target_ks[i] = ks1;
ncount++;
if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces
target_nt[i] = 0;
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);
break;
}
if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j);
}
}
if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1);
}
}
LED_C_OFF();
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
byte_t buf[4 + 4 * 4];
memcpy(buf, &cuid, 4);
memcpy(buf+4, &target_nt[0], 4);
memcpy(buf+8, &target_ks[0], 4);
memcpy(buf+12, &target_nt[1], 4);
memcpy(buf+16, &target_ks[1], 4);
LED_B_ON();
cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));
LED_B_OFF();
if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(FALSE);
}
//-----------------------------------------------------------------------------
// MIFARE check keys. key count up to 85.
//
//-----------------------------------------------------------------------------
void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
{
// params
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
bool clearTrace = arg1;
uint8_t keyCount = arg2;
uint64_t ui64Key = 0;
// variables
int i;
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// clear debug level
int OLD_MF_DBGLEVEL = MF_DBGLEVEL;
MF_DBGLEVEL = MF_DBG_NONE;
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if (clearTrace) clear_trace();
set_tracing(TRUE);
for (i = 0; i < keyCount; i++) {
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");
}
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");
break;
};
ui64Key = bytes_to_num(datain + i * 6, 6);
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
continue;
};
isOK = 1;
break;
}
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(FALSE);
// restore debug level
MF_DBGLEVEL = OLD_MF_DBGLEVEL;
}
//-----------------------------------------------------------------------------
// MIFARE commands set debug level
//
//-----------------------------------------------------------------------------
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
MF_DBGLEVEL = arg0;
Dbprintf("Debug level: %d", MF_DBGLEVEL);
}
//-----------------------------------------------------------------------------
// Work with emulator memory
//
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) here although FPGA is not
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
//-----------------------------------------------------------------------------
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
emlClearMem();
}
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
//emlSetMem(datain, arg0, arg1); // data, block num, blocks count
emlSetMem_xt(datain, arg0, arg1, arg2); // data, block num, blocks count, block byte width
}
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
byte_t buf[USB_CMD_DATA_SIZE];
emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4)
LED_B_ON();
cmd_send(CMD_ACK,arg0,arg1,0,buf,USB_CMD_DATA_SIZE);
LED_B_OFF();
}
//-----------------------------------------------------------------------------
// Load a card into the emulator memory
//
//-----------------------------------------------------------------------------
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
uint8_t numSectors = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// variables
byte_t dataoutbuf[16];
byte_t dataoutbuf2[16];
uint8_t uid[10];
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(TRUE);
bool isOK = true;
if(!iso14443a_select_card(uid, NULL, &cuid)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
}
for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
ui64Key = emlGetKey(sectorNo, keyType);
if (sectorNo == 0){
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);
break;
}
} else {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
break;
}
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
break;
};
if (isOK) {
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
} else { // sector trailer, keep the keys, set only the AC
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
}
}
}
}
if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
};
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED");
set_tracing(FALSE);
}
//-----------------------------------------------------------------------------
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
//
//-----------------------------------------------------------------------------
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// params
uint8_t needWipe = arg0;
// bit 0 - need get UID
// bit 1 - need wupC
// bit 2 - need HALT after sequence
// bit 3 - need init FPGA and field before sequence
// bit 4 - need reset FPGA and LED
uint8_t workFlags = arg1;
uint8_t blockNo = arg2;
// card commands
uint8_t wupC1[] = { 0x40 };
uint8_t wupC2[] = { 0x43 };
uint8_t wipeC[] = { 0x41 };
// variables
byte_t isOK = 0;
uint8_t uid[10] = {0x00};
uint8_t d_block[18] = {0x00};
uint32_t cuid;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// reset FPGA and LED
if (workFlags & 0x08) {
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(TRUE);
}
while (true) {
// get UID from chip
if (workFlags & 0x01) {
if(!iso14443a_select_card(uid, NULL, &cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
//break;
};
if(mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
//break;
};
};
// reset chip
if (needWipe){
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break;
};
if(mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
};
// write block
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
}
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break;
};
memcpy(d_block, datain, 16);
AppendCrc14443a(d_block, 16);
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break;
};
if (workFlags & 0x04) {
if (mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
}
isOK = 1;
break;
}
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,uid,4);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(FALSE);
}
}
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// params
// bit 1 - need wupC
// bit 2 - need HALT after sequence
// bit 3 - need init FPGA and field before sequence
// bit 4 - need reset FPGA and LED
// bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a)
uint8_t workFlags = arg0;
uint8_t blockNo = arg2;
// card commands
uint8_t wupC1[] = { 0x40 };
uint8_t wupC2[] = { 0x43 };
// variables
byte_t isOK = 0;
uint8_t data[18] = {0x00};
uint32_t cuid = 0;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
if (workFlags & 0x08) {
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(TRUE);
}
while (true) {
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
}
// read block
if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) {
if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error");
break;
};
memcpy(data, receivedAnswer, 18);
if (workFlags & 0x04) {
if (mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break;
};
}
isOK = 1;
break;
}
LED_B_ON();
if (workFlags & 0x20) {
if (isOK)
memcpy(datain, data, 18);
}
else
cmd_send(CMD_ACK,isOK,0,0,data,18);
LED_B_OFF();
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(FALSE);
}
}
void MifareCIdent(){
// card commands
uint8_t wupC1[] = { 0x40 };
uint8_t wupC2[] = { 0x43 };
// variables
byte_t isOK = 1;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
isOK = 0;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
isOK = 0;
};
if (mifare_classic_halt(NULL, 0)) {
isOK = 0;
};
cmd_send(CMD_ACK,isOK,0,0,0,0);
}
void MifareCollectNonces(uint32_t arg0, uint32_t arg1){
BigBuf_free();
uint32_t iterations = arg0;
uint8_t uid[10] = {0x00};
uint8_t *response = BigBuf_malloc(MAX_MIFARE_FRAME_SIZE);
uint8_t *responsePar = BigBuf_malloc(MAX_MIFARE_PARITY_SIZE);
uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b };
// get memory from BigBuf.
uint8_t *nonces = BigBuf_malloc(iterations * 4);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(TRUE);
for (int i = 0; i < iterations; i++) {
WDT_HIT();
// Test if the action was cancelled
if(BUTTON_PRESS()) break;
// if(mifare_classic_halt(pcs, cuid)) {
// if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
//}
if(!iso14443a_select_card(uid, NULL, NULL)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
continue;
};
// Transmit MIFARE_CLASSIC_AUTH.
ReaderTransmit(mf_auth, sizeof(mf_auth), NULL);
// Receive the (4 Byte) "random" nonce
if (!ReaderReceive(response, responsePar)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Couldn't receive tag nonce");
continue;
}
nonces[i*4] = bytes_to_num(response, 4);
}
int packLen = iterations * 4;
int packSize = 0;
int packNum = 0;
while (packLen > 0) {
packSize = MIN(USB_CMD_DATA_SIZE, packLen);
LED_B_ON();
cmd_send(CMD_ACK, 77, 0, packSize, nonces - packLen, packSize);
LED_B_OFF();
packLen -= packSize;
packNum++;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(FALSE);
}
//
// DESFIRE
//
void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
byte_t dataout[11] = {0x00};
uint8_t uid[10] = {0x00};
uint32_t cuid = 0x00;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
int len = iso14443a_select_card(uid, NULL, &cuid);
if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(1);
return;
};
if(mifare_desfire_des_auth1(cuid, dataout)){
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication part1: Fail.");
OnError(4);
return;
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED");
cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout));
}
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){
uint32_t cuid = arg0;
uint8_t key[16] = {0x00};
byte_t dataout[12] = {0x00};
byte_t isOK = 0;
memcpy(key, datain, 16);
isOK = mifare_desfire_des_auth2(cuid, key, dataout);
if( isOK) {
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed");
OnError(4);
return;
}
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED");
cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}