mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-18 03:00:58 +08:00
CHG: 'hf mf fchk' - no need to send dummy coomand to trigger timeout.
CHG: 'hf mf fchk' - added some debugstatements. These will become optional later. CHG: 'hf mf fchk' - lower re-try from 10 to 5
This commit is contained in:
parent
2fc88b924d
commit
71a500d824
2 changed files with 57 additions and 56 deletions
|
@ -338,10 +338,8 @@ int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, ui
|
||||||
|
|
||||||
uint8_t dummy_answer = 0;
|
uint8_t dummy_answer = 0;
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL);
|
ReaderTransmit(&dummy_answer, 1, NULL);
|
||||||
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
|
|
||||||
|
|
||||||
// wait for the card to become ready again
|
// wait for the card to become ready again
|
||||||
while(GetCountSspClk() < timeout) {};
|
SpinDelayUs(AUTHENTICATION_TIMEOUT);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,17 @@
|
||||||
|
|
||||||
#include "mifarecmd.h"
|
#include "mifarecmd.h"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifndef AUTHENTICATION_TIMEOUT
|
||||||
|
# define AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||||
|
#endif
|
||||||
|
#ifndef PRE_AUTHENTICATION_LEADTIME
|
||||||
|
# define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
|
||||||
|
#endif
|
||||||
|
#ifndef CHK_TIMEOUT
|
||||||
|
# define CHK_TIMEOUT() SpinDelayUs(AUTHENTICATION_TIMEOUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Select, Authenticate, Read a MIFARE tag.
|
// Select, Authenticate, Read a MIFARE tag.
|
||||||
// read block
|
// read block
|
||||||
|
@ -598,9 +609,6 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
|
||||||
(oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;
|
(oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AUTHENTICATION_TIMEOUT 848 //848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
|
||||||
#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
|
|
||||||
|
|
||||||
void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) {
|
void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) {
|
||||||
|
|
||||||
uint32_t cuid = 0;
|
uint32_t cuid = 0;
|
||||||
|
@ -610,11 +618,13 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *
|
||||||
uint8_t par[1] = {0x00};
|
uint8_t par[1] = {0x00};
|
||||||
int16_t isOK = 0;
|
int16_t isOK = 0;
|
||||||
uint8_t buf[USB_CMD_DATA_SIZE] = {0x00};
|
uint8_t buf[USB_CMD_DATA_SIZE] = {0x00};
|
||||||
uint32_t timeout = 0;
|
|
||||||
uint8_t blockNo = arg0 & 0xff;
|
uint8_t blockNo = arg0 & 0xff;
|
||||||
uint8_t keyType = (arg0 >> 8) & 0xff;
|
uint8_t keyType = (arg0 >> 8) & 0xff;
|
||||||
bool initialize = flags & 0x0001;
|
bool initialize = flags & 0x0001;
|
||||||
bool field_off = flags & 0x0004;
|
bool field_off = flags & 0x0004;
|
||||||
|
|
||||||
|
uint16_t num_nonces = 0;
|
||||||
|
bool have_uid = false;
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
|
@ -629,9 +639,6 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *
|
||||||
|
|
||||||
LED_C_ON();
|
LED_C_ON();
|
||||||
|
|
||||||
uint8_t dummy_answer = 0;
|
|
||||||
uint16_t num_nonces = 0;
|
|
||||||
bool have_uid = false;
|
|
||||||
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE-4; i += 4 ) {
|
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE-4; i += 4 ) {
|
||||||
|
|
||||||
// Test if the action was cancelled
|
// Test if the action was cancelled
|
||||||
|
@ -668,9 +675,11 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *
|
||||||
int len = ReaderReceive(answer, par);
|
int len = ReaderReceive(answer, par);
|
||||||
|
|
||||||
// send a dummy byte as reader response in order to trigger the cards authentication timeout
|
// send a dummy byte as reader response in order to trigger the cards authentication timeout
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL);
|
//ReaderTransmit(&dummy_answer, 1, NULL);
|
||||||
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
|
|
||||||
|
|
||||||
|
// wait for the card to become ready again
|
||||||
|
CHK_TIMEOUT();
|
||||||
|
|
||||||
if (len != 4) {
|
if (len != 4) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
|
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
|
||||||
continue;
|
continue;
|
||||||
|
@ -683,9 +692,6 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *
|
||||||
buf[i+1] = answer[1];
|
buf[i+1] = answer[1];
|
||||||
buf[i+2] = answer[2];
|
buf[i+2] = answer[2];
|
||||||
buf[i+3] = answer[3];
|
buf[i+3] = answer[3];
|
||||||
|
|
||||||
// wait for the card to become ready again
|
|
||||||
while (GetCountSspClk() < timeout) {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
|
@ -708,7 +714,6 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *
|
||||||
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
// Computer and Communications Security, 2015
|
// Computer and Communications Security, 2015
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain)
|
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain)
|
||||||
{
|
{
|
||||||
uint64_t ui64Key = 0;
|
uint64_t ui64Key = 0;
|
||||||
|
@ -723,8 +728,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
uint8_t par_enc[1] = {0x00};
|
uint8_t par_enc[1] = {0x00};
|
||||||
uint8_t nt_par_enc = 0;
|
uint8_t nt_par_enc = 0;
|
||||||
uint8_t buf[USB_CMD_DATA_SIZE] = {0x00};
|
uint8_t buf[USB_CMD_DATA_SIZE] = {0x00};
|
||||||
uint32_t timeout = 0;
|
|
||||||
|
|
||||||
uint8_t blockNo = arg0 & 0xff;
|
uint8_t blockNo = arg0 & 0xff;
|
||||||
uint8_t keyType = (arg0 >> 8) & 0xff;
|
uint8_t keyType = (arg0 >> 8) & 0xff;
|
||||||
uint8_t targetBlockNo = arg1 & 0xff;
|
uint8_t targetBlockNo = arg1 & 0xff;
|
||||||
|
@ -734,6 +738,10 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
bool slow = flags & 0x0002;
|
bool slow = flags & 0x0002;
|
||||||
bool field_off = flags & 0x0004;
|
bool field_off = flags & 0x0004;
|
||||||
|
|
||||||
|
// uint8_t dummy_answer = 0;
|
||||||
|
uint16_t num_nonces = 0;
|
||||||
|
bool have_uid = false;
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
|
|
||||||
|
@ -747,9 +755,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
|
|
||||||
LED_C_ON();
|
LED_C_ON();
|
||||||
|
|
||||||
uint8_t dummy_answer = 0;
|
|
||||||
uint16_t num_nonces = 0;
|
|
||||||
bool have_uid = false;
|
|
||||||
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) {
|
for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) {
|
||||||
|
|
||||||
// Test if the action was cancelled
|
// Test if the action was cancelled
|
||||||
|
@ -780,10 +785,8 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slow) {
|
if (slow)
|
||||||
timeout = GetCountSspClk() + PRE_AUTHENTICATION_LEADTIME;
|
SpinDelayUs(PRE_AUTHENTICATION_LEADTIME);
|
||||||
while(GetCountSspClk() < timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t nt1;
|
uint32_t nt1;
|
||||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
||||||
|
@ -795,8 +798,9 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL);
|
uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL);
|
||||||
|
|
||||||
// send a dummy byte as reader response in order to trigger the cards authentication timeout
|
// send a dummy byte as reader response in order to trigger the cards authentication timeout
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL);
|
//ReaderTransmit(&dummy_answer, 1, NULL);
|
||||||
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
|
// wait for the card to become ready again
|
||||||
|
CHK_TIMEOUT();
|
||||||
|
|
||||||
if (len != 4) {
|
if (len != 4) {
|
||||||
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
|
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
|
||||||
|
@ -813,8 +817,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
memcpy(buf+i+8, &nt_par_enc, 1);
|
memcpy(buf+i+8, &nt_par_enc, 1);
|
||||||
i += 9;
|
i += 9;
|
||||||
}
|
}
|
||||||
// wait for the card to become ready again
|
|
||||||
while(GetCountSspClk() < timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
|
@ -1081,17 +1083,9 @@ typedef struct chk_t {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CHK_TIMEOUT
|
|
||||||
# define CHK_TIMEOUT() {\
|
|
||||||
uint8_t dummy_answer = 0; \
|
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL); \
|
|
||||||
uint32_t timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; \
|
|
||||||
while(GetCountSspClk() < timeout); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// checks one key.
|
// checks one key.
|
||||||
// fast select, tries 10times to select
|
// fast select, tries 5 times to select
|
||||||
//
|
//
|
||||||
// return:
|
// return:
|
||||||
// 2 = failed to select.
|
// 2 = failed to select.
|
||||||
|
@ -1100,7 +1094,7 @@ typedef struct chk_t {
|
||||||
uint8_t chkKey( struct chk_t *c ) {
|
uint8_t chkKey( struct chk_t *c ) {
|
||||||
|
|
||||||
uint8_t i = 0, res = 2;
|
uint8_t i = 0, res = 2;
|
||||||
while( i<10 ) {
|
while( i < 5 ) {
|
||||||
// this part is from Piwi's faster nonce collecting part in Hardnested.
|
// this part is from Piwi's faster nonce collecting part in Hardnested.
|
||||||
// assume: fast select
|
// assume: fast select
|
||||||
if(!iso14443a_fast_select_card(c->uid, c->cl)) {
|
if(!iso14443a_fast_select_card(c->uid, c->cl)) {
|
||||||
|
@ -1109,7 +1103,12 @@ uint8_t chkKey( struct chk_t *c ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
res = mifare_classic_authex(c->pcs, c->cuid, c->block, c->keyType, c->key, AUTH_FIRST, NULL, NULL);
|
res = mifare_classic_authex(c->pcs, c->cuid, c->block, c->keyType, c->key, AUTH_FIRST, NULL, NULL);
|
||||||
CHK_TIMEOUT();
|
//CHK_TIMEOUT();
|
||||||
|
|
||||||
|
// if successfull auth, send HALT
|
||||||
|
if ( !res )
|
||||||
|
mifare_classic_halt_ex(c->pcs);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
@ -1126,7 +1125,7 @@ uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) {
|
||||||
uint8_t data[16] = {0x00};
|
uint8_t data[16] = {0x00};
|
||||||
uint8_t res = mifare_classic_readblock(c->pcs, c->cuid, c->block, data);
|
uint8_t res = mifare_classic_readblock(c->pcs, c->cuid, c->block, data);
|
||||||
|
|
||||||
CHK_TIMEOUT();
|
//CHK_TIMEOUT();
|
||||||
|
|
||||||
// successful read
|
// successful read
|
||||||
if ( !res ) {
|
if ( !res ) {
|
||||||
|
@ -1137,6 +1136,7 @@ uint8_t chkKey_readb(struct chk_t *c, uint8_t *keyb) {
|
||||||
} else {
|
} else {
|
||||||
res = 3;
|
res = 3;
|
||||||
}
|
}
|
||||||
|
mifare_classic_halt_ex(c->pcs);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1147,14 +1147,17 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||||
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
||||||
|
|
||||||
// skip already found A keys
|
// skip already found A keys
|
||||||
if( !found[(s*2)] ) {
|
if ( !found[(s*2)] ) {
|
||||||
|
|
||||||
c->block = FirstBlockOfSector( s );
|
c->block = FirstBlockOfSector( s );
|
||||||
|
|
||||||
uint8_t status = chkKey( c );
|
uint8_t status = chkKey( c );
|
||||||
if ( status == 0 ) {
|
if ( status == 0 ) {
|
||||||
num_to_bytes(c->key, 6, k_sector[s].keyA);
|
num_to_bytes(c->key, 6, k_sector[s].keyA);
|
||||||
found[(s*2)] = 1;
|
found[(s*2)] = 1;
|
||||||
++*foundkeys;
|
++*foundkeys;
|
||||||
|
|
||||||
|
Dbprintf("ChkKeys_fast: Scan A (%d)", c->block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1166,7 +1169,7 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||||
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
||||||
|
|
||||||
// skip already found B keys
|
// skip already found B keys
|
||||||
if( !found[(s*2)+1] ) {
|
if ( !found[(s*2)+1] ) {
|
||||||
|
|
||||||
c->block = FirstBlockOfSector( s );
|
c->block = FirstBlockOfSector( s );
|
||||||
uint8_t status = chkKey( c );
|
uint8_t status = chkKey( c );
|
||||||
|
@ -1174,6 +1177,8 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||||
num_to_bytes(c->key, 6, k_sector[s].keyB);
|
num_to_bytes(c->key, 6, k_sector[s].keyB);
|
||||||
found[(s*2)+1] = 1;
|
found[(s*2)+1] = 1;
|
||||||
++*foundkeys;
|
++*foundkeys;
|
||||||
|
|
||||||
|
Dbprintf("ChkKeys_fast: Scan B (%d)", c->block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1183,6 +1188,8 @@ void chkKey_scanA(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, ui
|
||||||
// when A is found but not B, try to read B.
|
// when A is found but not B, try to read B.
|
||||||
void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) {
|
void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found, uint8_t *sectorcnt, uint8_t *foundkeys) {
|
||||||
|
|
||||||
|
Dbprintf("ChkKeys_fast: Loop B only (%d)", c->block);
|
||||||
|
|
||||||
// read Block B, if A is found.
|
// read Block B, if A is found.
|
||||||
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
for (uint8_t s = 0; s < *sectorcnt; ++s) {
|
||||||
c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1);
|
c->block = (FirstBlockOfSector( s ) + NumBlocksPerSector( s ) - 1);
|
||||||
|
@ -1307,6 +1314,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||||
++foundkeys;
|
++foundkeys;
|
||||||
|
|
||||||
chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
chkKey_scanA(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||||
|
|
||||||
|
// read Block B, if A is found.
|
||||||
|
chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1322,11 +1332,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
||||||
chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
chkKey_scanB(&chk_data, k_sector, found, §orcnt, &foundkeys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end loop sectors
|
} // end loop sectors
|
||||||
|
|
||||||
// read Block B, if A is found.
|
|
||||||
chkKey_loopBonly( &chk_data, k_sector, found, §orcnt, &foundkeys);
|
|
||||||
|
|
||||||
// is all keys found?
|
// is all keys found?
|
||||||
if ( foundkeys == allkeys )
|
if ( foundkeys == allkeys )
|
||||||
break;
|
break;
|
||||||
|
@ -1372,7 +1379,6 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
bool have_uid = false;
|
bool have_uid = false;
|
||||||
uint8_t cascade_levels = 0;
|
uint8_t cascade_levels = 0;
|
||||||
uint32_t timeout = 0;
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
byte_t isOK = 0;
|
byte_t isOK = 0;
|
||||||
|
@ -1426,14 +1432,11 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
|
||||||
key = bytes_to_num(datain + i * 6, 6);
|
key = bytes_to_num(datain + i * 6, 6);
|
||||||
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST)) {
|
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST)) {
|
||||||
|
|
||||||
uint8_t dummy_answer = 0;
|
//CHK_TIMEOUT();
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL);
|
|
||||||
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
|
|
||||||
|
|
||||||
// wait for the card to become ready again
|
|
||||||
while(GetCountSspClk() < timeout) {};
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
} else {
|
||||||
|
mifare_classic_halt_ex(pcs);
|
||||||
}
|
}
|
||||||
isOK = 1;
|
isOK = 1;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue