Merge branch 'master' into iclass_MAC_speedup

This commit is contained in:
pwpiwi 2019-08-24 18:27:01 +02:00
commit a1ff338bd5
18 changed files with 1555 additions and 1284 deletions

View file

@ -42,6 +42,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` - Added downlink reference mode option r <mode> [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce`
- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password - Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password
- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi) - `hf mfu info` now checks the NXP Originality Signature if availabe (piwi)
- Added `hf mf personalize` to personalize the UID option of Mifare Classic EV1 cards (piwi)
## [v3.1.0][2018-10-10] ## [v3.1.0][2018-10-10]

View file

@ -29,6 +29,7 @@
#include "iso15693.h" #include "iso15693.h"
#include "lfsampling.h" #include "lfsampling.h"
#include "BigBuf.h" #include "BigBuf.h"
#include "mifarecmd.h"
#include "mifareutil.h" #include "mifareutil.h"
#include "mifaresim.h" #include "mifaresim.h"
#include "pcf7931.h" #include "pcf7931.h"
@ -1243,6 +1244,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
case CMD_MIFARE_WRITEBL: case CMD_MIFARE_WRITEBL:
MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break; break;
case CMD_MIFARE_PERSONALIZE_UID:
MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes);
break;
//case CMD_MIFAREU_WRITEBL_COMPAT: //case CMD_MIFAREU_WRITEBL_COMPAT:
//MifareUWriteBlockCompat(c->arg[0], c->d.asBytes); //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
//break; //break;

View file

@ -16,7 +16,6 @@
#include <stddef.h> #include <stddef.h>
#include "common.h" #include "common.h"
#include "usb_cmd.h" #include "usb_cmd.h"
#include "hitag2.h"
#include "hitagS.h" #include "hitagS.h"
#include "mifare.h" #include "mifare.h"
#include "../common/crc32.h" #include "../common/crc32.h"
@ -104,41 +103,14 @@ void RAMFUNC SniffMifare(uint8_t param);
void EPA_PACE_Collect_Nonce(UsbCommand * c); void EPA_PACE_Collect_Nonce(UsbCommand * c);
void EPA_PACE_Replay(UsbCommand *c); void EPA_PACE_Replay(UsbCommand *c);
// mifarecmd.h
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCIdent(); // is "magic chinese" card?
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
//desfire
void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// mifaredesfire.h // mifaredesfire.h
bool InitDesfireCard(); bool InitDesfireCard();
void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain);
void MifareDesfireGetInformation(); void MifareDesfireGetInformation();
void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain);
void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain);
int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout);
size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout);
// cmd.h // cmd.h
bool cmd_receive(UsbCommand* cmd); bool cmd_receive(UsbCommand* cmd);

File diff suppressed because it is too large Load diff

View file

@ -16,9 +16,9 @@
#include <stdbool.h> #include <stdbool.h>
#include "hitag.h" #include "hitag.h"
void SnoopHitag(uint32_t type); extern void SnoopHitag(uint32_t type);
void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data);
void ReaderHitag(hitag_function htf, hitag_data* htd); extern void ReaderHitag(hitag_function htf, hitag_data* htd);
void WriterHitag(hitag_function htf, hitag_data* htd, int page); extern void WriterHitag(hitag_function htf, hitag_data* htd, int page);
#endif #endif

View file

@ -26,18 +26,6 @@
#define CRC_PRESET 0xFF #define CRC_PRESET 0xFF
#define CRC_POLYNOM 0x1D #define CRC_POLYNOM 0x1D
#define u8 uint8_t
#define u32 uint32_t
#define u64 uint64_t
#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7))
#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8))
#define rev32(x) (rev16(x)+(rev16(x>>16)<<16))
#define rev64(x) (rev32(x)+(rev32(x>>32)<<32))
#define bit(x,n) (((x)>>(n))&1)
#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1)
#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31))
#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63)))
static bool bQuiet; static bool bQuiet;
static bool bSuccessful; static bool bSuccessful;
static struct hitagS_tag tag; static struct hitagS_tag tag;
@ -57,17 +45,17 @@ size_t blocknr;
bool end=false; bool end=false;
// Single bit Hitag2 functions: // Single bit Hitag2 functions:
#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) #define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) #define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b))
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) #define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b)))
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) #define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c))))
#define uf20bs u32 #define uf20bs uint32_t
static u32 f20(const u64 x) { static uint32_t f20(const uint64_t x) {
u32 i5; uint32_t i5;
i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
+ ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2 + ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
@ -77,8 +65,19 @@ static u32 f20(const u64 x) {
return (ht2_f5c >> i5) & 1; return (ht2_f5c >> i5) & 1;
} }
static u64 hitag2_round(u64 *state) {
u64 x = *state; static uint64_t hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
uint32_t i;
uint64_t x = ((key & 0xFFFF) << 32) + serial;
for (i = 0; i < 32; i++) {
x >>= 1;
x += (uint64_t) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
}
return x;
}
static uint64_t hitag2_round(uint64_t *state) {
uint64_t x = *state;
x = (x >> 1) x = (x >> 1)
+ ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8) + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8)
@ -89,20 +88,12 @@ static u64 hitag2_round(u64 *state) {
*state = x; *state = x;
return f20(x); return f20(x);
} }
static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) {
u32 i; static uint32_t hitag2_byte(uint64_t *x) {
u64 x = ((key & 0xFFFF) << 32) + serial; uint32_t i, c;
for (i = 0; i < 32; i++) {
x >>= 1;
x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
}
return x;
}
static u32 hitag2_byte(u64 *x) {
u32 i, c;
for (i = 0, c = 0; i < 8; i++) for (i = 0, c = 0; i < 8; i++)
c += (u32) hitag2_round(x) << (i ^ 7); c += (uint32_t) hitag2_round(x) << (i ^ 7);
return c; return c;
} }
@ -858,7 +849,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen,
byte_t rx_air[HITAG_FRAME_LEN]; byte_t rx_air[HITAG_FRAME_LEN];
byte_t page; byte_t page;
int i; int i;
u64 state; uint64_t state;
unsigned char crc; unsigned char crc;
// Copy the (original) received frame how it is send over the air // Copy the (original) received frame how it is send over the air
@ -956,8 +947,8 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen,
//challenge message received //challenge message received
Dbprintf("Challenge for UID: %X", temp_uid); Dbprintf("Challenge for UID: %X", temp_uid);
temp2++; temp2++;
state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]), state = hitag2_init(REV64(tag.key), REV32(tag.pages[0][0]),
rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0])));
Dbprintf( Dbprintf(
",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", ",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
@ -1216,7 +1207,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
unsigned char uid[32]; unsigned char uid[32];
byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00; byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00;
unsigned char crc; unsigned char crc;
u64 state; uint64_t state;
byte_t auth_ks[4]; byte_t auth_ks[4];
byte_t conf_pages[3]; byte_t conf_pages[3];
memcpy(rx_air, rx, nbytes(rxlen)); memcpy(rx_air, rx, nbytes(rxlen));
@ -1356,11 +1347,11 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
*txlen = 64; *txlen = 64;
if(end!=true){ if(end!=true){
if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY
state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
/* /*
Dbprintf("key: %02X %02X\n\n", key, rev64(key)); Dbprintf("key: %02X %02X\n\n", key, REV64(key));
Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, REV32(tag.uid));
Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); Dbprintf("rnd: %02X %02X\n\n", rnd, REV32(rnd));
*/ */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
auth_ks[i] = hitag2_byte(&state) ^ 0xff; auth_ks[i] = hitag2_byte(&state) ^ 0xff;
@ -1404,7 +1395,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr
pwdl0=0; pwdl0=0;
pwdl1=0; pwdl1=0;
if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY
state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
hitag2_byte(&state); hitag2_byte(&state);
} }

View file

@ -15,13 +15,23 @@
#include "mifarecmd.h" #include "mifarecmd.h"
#include <stdint.h>
#include "proxmark3.h"
#include "cmd.h"
#include "crapto1/crapto1.h"
#include "iso14443a.h"
#include "BigBuf.h"
#include "mifareutil.h"
#include "apps.h"
#include "protocols.h"
#include "util.h" #include "util.h"
#include "parity.h" #include "parity.h"
#include "crc.h" #include "crc.h"
#include "fpgaloader.h" #include "fpgaloader.h"
#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication #define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
/* /*
// the block number for the ISO14443-4 PCB // the block number for the ISO14443-4 PCB
@ -73,22 +83,22 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
while (true) { while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; break;
}; };
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break; break;
}; };
if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");
break; break;
}; };
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break; break;
}; };
@ -99,7 +109,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// ----------------------------- crypto1 destroy // ----------------------------- crypto1 destroy
crypto1_destroy(pcs); crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");
LED_B_ON(); LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);
@ -230,25 +240,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
isOK = 1; isOK = 1;
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = 0; isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
} }
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = 0; isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
} }
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
isOK = 0; isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
break; break;
} }
} }
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
} }
// ----------------------------- crypto1 destroy // ----------------------------- crypto1 destroy
@ -393,22 +403,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
while (true) { while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break; break;
}; };
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break; break;
}; };
if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
break; break;
}; };
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
break; break;
}; };
@ -419,7 +429,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// ----------------------------- crypto1 destroy // ----------------------------- crypto1 destroy
crypto1_destroy(pcs); crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
LED_B_ON(); LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0); cmd_send(CMD_ACK,isOK,0,0,0,0);
@ -455,7 +465,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");
OnError(0); OnError(0);
return; }; return; };
if(mifare_ultra_halt()) { if(mifare_ultra_halt()) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
@ -672,7 +682,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
if (!have_uid) { // need a full select cycle to get the uid first if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info; iso14a_card_select_t card_info;
if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue; continue;
} }
switch (card_info.uidlen) { switch (card_info.uidlen) {
@ -684,7 +694,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
have_uid = true; have_uid = true;
} else { // no need for anticollision. We can directly select the card } else { // no need for anticollision. We can directly select the card
if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) { if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
continue; continue;
} }
} }
@ -696,14 +706,14 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
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)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
continue; continue;
} }
// nested authentication // nested authentication
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);
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);
continue; continue;
} }
@ -737,7 +747,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_B_OFF(); LED_B_OFF();
if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished");
if (field_off) { if (field_off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -794,7 +804,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
int16_t isOK = 0; int16_t isOK = 0;
#define NESTED_MAX_TRIES 12 #define NESTED_MAX_TRIES 12
uint16_t unsuccessfull_tries = 0; uint16_t unsuccessfull_tries = 0;
if (calibrate) { // for first call only. Otherwise reuse previous calibration if (calibrate) { // for first call only. Otherwise reuse previous calibration
LED_B_ON(); LED_B_ON();
WDT_HIT(); WDT_HIT();
@ -812,20 +822,20 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
// prepare next select. No need to power down the card. // prepare next select. No need to power down the card.
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
rtr--; rtr--;
continue; continue;
} }
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
rtr--; rtr--;
continue; continue;
}; };
auth1_time = 0; auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
rtr--; rtr--;
continue; continue;
}; };
@ -836,12 +846,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
auth2_time = 0; auth2_time = 0;
} }
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");
rtr--; rtr--;
continue; continue;
}; };
nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 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++) { for (i = 101; i < 1200; i++) {
nttmp = prng_successor(nttmp, 1); nttmp = prng_successor(nttmp, 1);
if (nttmp == nt2) break; if (nttmp == nt2) break;
@ -859,7 +869,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i); if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i);
} else { } else {
unsuccessfull_tries++; unsuccessfull_tries++;
if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable)
isOK = -3; isOK = -3;
} }
} }
@ -887,18 +897,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
// prepare next select. No need to power down the card. // prepare next select. No need to power down the card.
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");
continue; continue;
} }
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
continue; continue;
}; };
auth1_time = 0; auth1_time = 0;
if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");
continue; continue;
}; };
@ -906,7 +916,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
auth2_time = auth1_time + delta_time; auth2_time = auth1_time + delta_time;
len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);
if (len != 4) { if (len != 4) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);
continue; continue;
}; };
@ -925,7 +935,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
ks1 = nt2 ^ nttest; ks1 = nt2 ^ nttest;
if (valid_nonce(nttest, nt2, ks1, par_array)){ if (valid_nonce(nttest, nt2, ks1, par_array)){
if (ncount > 0) { // we are only interested in disambiguous nonces, try again 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); if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);
target_nt[i] = 0; target_nt[i] = 0;
break; break;
@ -961,7 +971,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));
LED_B_OFF(); LED_B_OFF();
if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
@ -1026,6 +1036,60 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
LED_A_OFF(); LED_A_OFF();
} }
//-----------------------------------------------------------------------------
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
//-----------------------------------------------------------------------------
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *data) {
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
LED_A_ON();
clear_trace();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
bool isOK = false;
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
}
uint8_t block_number = 0;
uint64_t key = bytes_to_num(data, 6);
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");
break;
}
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
break;;
}
isOK = true;
break;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
crypto1_destroy(pcs);
if (MF_DBGLEVEL >= 2) DbpString("PERSONALIZE UID FINISHED");
cmd_send(CMD_ACK, isOK, 0, 0, NULL, 0);
LED_A_OFF();
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// MIFARE commands set debug level // MIFARE commands set debug level
// //
@ -1093,7 +1157,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = false; isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
} }
for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
@ -1101,13 +1165,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (sectorNo == 0){ if (sectorNo == 0){
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = false; isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);
break; break;
} }
} else { } else {
if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
isOK = false; isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
break; break;
} }
} }
@ -1115,13 +1179,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
isOK = false; isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
break; break;
}; };
if (isOK) { if (isOK) {
if (blockNo < NumBlocksPerSector(sectorNo) - 1) { if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
} else { // sector trailer, keep the keys, set only the AC } else { // sector trailer, keep the keys, set only the AC
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
@ -1132,7 +1196,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
} }
if(mifare_classic_halt(pcs, cuid)) { if(mifare_classic_halt(pcs, cuid)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");
}; };
// ----------------------------- crypto1 destroy // ----------------------------- crypto1 destroy
@ -1201,19 +1265,19 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// wipe // wipe
if (needWipe){ if (needWipe){
ReaderTransmitBitsPar(wupC1,7,0, NULL); ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break; break;
}; };
ReaderTransmit(wipeC, sizeof(wipeC), NULL); ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break; break;
}; };
if(mifare_classic_halt(NULL, 0)) { if(mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
}; };
}; };
@ -1222,25 +1286,25 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// select commands // select commands
ReaderTransmitBitsPar(wupC1, 7, 0, NULL); ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
if (!gen1b) { if (!gen1b) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break; break;
}; };
ReaderTransmit(wupC2, sizeof(wupC2), NULL); ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break; break;
}; };
} }
// send blocks command // send blocks command
for (int blockNo = 0; blockNo < numBlocks; blockNo++) { for (int blockNo = 0; blockNo < numBlocks; blockNo++) {
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break; break;
}; };
@ -1257,8 +1321,8 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// send write command // send write command
ReaderTransmit(d_block, sizeof(d_block), NULL); ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break; break;
}; };
} }
@ -1267,7 +1331,7 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// do no issue halt command for gen1b // do no issue halt command for gen1b
if (!gen1b) { if (!gen1b) {
if (mifare_classic_halt(NULL, 0)) { if (mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
break; break;
} }
} }
@ -1330,13 +1394,13 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// get UID from chip // get UID from chip
if (workFlags & 0x01) { if (workFlags & 0x01) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
// Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work. // Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work.
//break; //break;
}; };
if(mifare_classic_halt(NULL, cuid)) { if(mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it. // Continue, some magic tags misbehavies and send an answer to it.
// break; // break;
}; };
@ -1346,21 +1410,21 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// Wipe command don't work with gen1b // Wipe command don't work with gen1b
if (needWipe && !(workFlags & 0x40)){ if (needWipe && !(workFlags & 0x40)){
ReaderTransmitBitsPar(wupC1,7,0, NULL); ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break; break;
}; };
ReaderTransmit(wipeC, sizeof(wipeC), NULL); ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break; break;
}; };
if(mifare_classic_halt(NULL, 0)) { if(mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it. // Continue, some magic tags misbehavies and send an answer to it.
// break; // break;
}; };
}; };
@ -1368,24 +1432,24 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (workFlags & 0x02) { if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL); ReaderTransmitBitsPar(wupC1,7,0, NULL);
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
if (!(workFlags & 0x40)) { if (!(workFlags & 0x40)) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break; break;
}; };
ReaderTransmit(wupC2, sizeof(wupC2), NULL); ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break; break;
}; };
} }
} }
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break; break;
}; };
@ -1393,8 +1457,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
AppendCrc14443a(d_block, 16); AppendCrc14443a(d_block, 16);
ReaderTransmit(d_block, sizeof(d_block), NULL); ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break; break;
}; };
@ -1402,7 +1466,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1)
if (!(workFlags & 0x40)) { if (!(workFlags & 0x40)) {
if (mifare_classic_halt(NULL, 0)) { if (mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it. // Continue, some magic tags misbehavies and send an answer to it.
// break; // break;
} }
@ -1461,15 +1525,15 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
while (true) { while (true) {
if (workFlags & 0x02) { if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1,7,0, NULL); ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break; break;
}; };
// do no issue for gen1b magic tag // do no issue for gen1b magic tag
if (!(workFlags & 0x40)) { if (!(workFlags & 0x40)) {
ReaderTransmit(wupC2, sizeof(wupC2), NULL); ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break; break;
}; };
} }
@ -1477,7 +1541,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// read block // read block
if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) {
if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error");
break; break;
}; };
memcpy(data, receivedAnswer, 18); memcpy(data, receivedAnswer, 18);
@ -1486,9 +1550,9 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1)
if (!(workFlags & 0x40)) { if (!(workFlags & 0x40)) {
if (mifare_classic_halt(NULL, cuid)) { if (mifare_classic_halt(NULL, cuid)) {
if (MF_DBGLEVEL > 1) Dbprintf("Halt error"); if (MF_DBGLEVEL > 1) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it. // Continue, some magic tags misbehavies and send an answer to it.
// break; // break;
} }
} }
} }
@ -1533,11 +1597,11 @@ void MifareCIdent(){
set_tracing(true); set_tracing(true);
ReaderTransmitBitsPar(wupC1,7,0, NULL); ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
isOK = 2; isOK = 2;
ReaderTransmit(wupC2, sizeof(wupC2), NULL); ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) {
isOK = 1; isOK = 1;
}; };
}; };
@ -1580,7 +1644,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
} }
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED"); if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED");
cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout)); cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout));
} }
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){

View file

@ -10,18 +10,36 @@
// Routines to support ISO 14443 type A. // Routines to support ISO 14443 type A.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifndef __MIFARECMD_H #ifndef MIFARECMD_H__
#define __MIFARECMD_H #define MIFARECMD_H__
#include "proxmark3.h" #include <stdint.h>
#include "apps.h"
#include "util.h"
#include "iso14443crc.h" extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
#include "iso14443a.h" extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
#include "crapto1/crapto1.h" extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
#include "mifareutil.h" extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
#include "common.h" extern void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
extern void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
//extern void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
extern void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
extern void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
extern void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
extern void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
extern void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
extern void MifareCIdent(); // is "magic chinese" card?
extern void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
extern void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *datain);
//desfire
extern void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
extern void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
#endif #endif

View file

@ -22,6 +22,7 @@
#include "iso14443a.h" #include "iso14443a.h"
#include "crapto1/crapto1.h" #include "crapto1/crapto1.h"
#include "mbedtls/des.h" #include "mbedtls/des.h"
#include "protocols.h"
int MF_DBGLEVEL = MF_DBG_INFO; int MF_DBGLEVEL = MF_DBG_INFO;
@ -163,7 +164,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// Transmit MIFARE_CLASSIC_AUTH // Transmit MIFARE_CLASSIC_AUTH
len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); len = mifare_sendcmd_short(pcs, isNested, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, timing);
if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len);
if (len != 4) return 1; if (len != 4) return 1;
@ -250,7 +251,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// command MIFARE_CLASSIC_READBLOCK // command MIFARE_CLASSIC_READBLOCK
len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) { if (len == 1) {
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1; return 1;
@ -282,7 +283,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){
if (MF_DBGLEVEL >= MF_DBG_EXTENDED) if (MF_DBGLEVEL >= MF_DBG_EXTENDED)
Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]);
len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL); len = mifare_sendcmd(MIFARE_ULEV1_AUTH, key, sizeof(key), resp, respPar, NULL);
//len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL);
if (len != 4) { if (len != 4) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len);
@ -314,7 +315,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
uint8_t respPar[3] = {0,0,0}; uint8_t respPar[3] = {0,0,0};
// REQUEST AUTHENTICATION // REQUEST AUTHENTICATION
len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, resp, respPar ,NULL); len = mifare_sendcmd_short(NULL, 1, MIFARE_ULC_AUTH_1, 0x00, resp, respPar ,NULL);
if (len != 11) { if (len != 11) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
return 0; return 0;
@ -364,7 +365,7 @@ int mifare_ultra_auth(uint8_t *keybytes){
); );
//len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL);
len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL);
if (len != 11) { if (len != 11) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]);
return 0; return 0;
@ -421,7 +422,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
int result = 0; int result = 0;
for (retries = 0; retries < MFU_MAX_RETRIES; retries++) { for (retries = 0; retries < MFU_MAX_RETRIES; retries++) {
len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(NULL, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) { if (len == 1) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
result = 1; result = 1;
@ -468,7 +469,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// command MIFARE_CLASSIC_WRITEBLOCK // command MIFARE_CLASSIC_WRITEBLOCK
len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
@ -511,7 +512,7 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData)
uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswer[MAX_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(NULL, true, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (MF_DBGLEVEL >= MF_DBG_ERROR) if (MF_DBGLEVEL >= MF_DBG_ERROR)
@ -563,7 +564,7 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid)
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
if (len != 0) { if (len != 0) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) if (MF_DBGLEVEL >= MF_DBG_ERROR)
Dbprintf("halt error. response len: %x", len); Dbprintf("halt error. response len: %x", len);
@ -579,7 +580,7 @@ int mifare_ultra_halt()
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(NULL, true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL);
if (len != 0) { if (len != 0) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) if (MF_DBGLEVEL >= MF_DBG_ERROR)
Dbprintf("halt error. response len: %x", len); Dbprintf("halt error. response len: %x", len);

View file

@ -152,8 +152,14 @@ bool IsBlock0PCF7931(uint8_t *block) {
bool IsBlock1PCF7931(uint8_t *block) { bool IsBlock1PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0 // assuming all RFU bits are set to 0
uint8_t rb1 = block[14] & 0x80;
uint8_t rfb = block[14] & 0x7f;
uint8_t rlb = block[15];
if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0)
if((block[14] & 0x7f) <= 9 && block[15] <= 9) // block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled
if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1))
return true; return true;
return false; return false;
@ -192,6 +198,7 @@ void ReadPCF7931() {
Dbprintf("Error, no tag or bad tag"); Dbprintf("Error, no tag or bad tag");
return; return;
} }
// exit if too many errors during reading // exit if too many errors during reading
if (tries > 50 && (2*errors > tries)) { if (tries > 50 && (2*errors > tries)) {
Dbprintf("Error reading the tag"); Dbprintf("Error reading the tag");
@ -201,9 +208,11 @@ void ReadPCF7931() {
// our logic breaks if we don't get at least two blocks // our logic breaks if we don't get at least two blocks
if (n < 2) { if (n < 2) {
// skip if all 0s block or no blocks
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
continue; continue;
// add block to single blocks list
if (single_blocks_cnt < max_blocks) { if (single_blocks_cnt < max_blocks) {
for (i = 0; i < single_blocks_cnt; ++i) { for (i = 0; i < single_blocks_cnt; ++i) {
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) { if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
@ -213,6 +222,7 @@ void ReadPCF7931() {
} }
if (j != 1) { if (j != 1) {
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16); memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
print_result("got single block", single_blocks[single_blocks_cnt], 16);
single_blocks_cnt++; single_blocks_cnt++;
} }
j = 0; j = 0;
@ -222,6 +232,10 @@ void ReadPCF7931() {
} }
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
for (i = 0; i < n; ++i)
{
print_result("got consecutive blocks", tmp_blocks[i], 16);
}
i = 0; i = 0;
if(!found_0_1) { if(!found_0_1) {
@ -284,7 +298,7 @@ void ReadPCF7931() {
goto end; goto end;
} }
} }
while (found_blocks != max_blocks); while (found_blocks < max_blocks);
end: end:
Dbprintf("-----------------------------------------"); Dbprintf("-----------------------------------------");

View file

@ -17,15 +17,21 @@
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
#define LED_RED 1 #define LED_RED 1
#define LED_ORANGE 2 #define LED_ORANGE 2
#define LED_GREEN 4 #define LED_GREEN 4
#define LED_RED2 8 #define LED_RED2 8
#define BUTTON_HOLD 1
#define BUTTON_NO_CLICK 0 #define BUTTON_HOLD 1
#define BUTTON_SINGLE_CLICK -1 #define BUTTON_NO_CLICK 0
#define BUTTON_DOUBLE_CLICK -2 #define BUTTON_SINGLE_CLICK -1
#define BUTTON_ERROR -99 #define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7))
#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8))
#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16))
#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32))
void print_result(char *name, uint8_t *buf, size_t len); void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits); size_t nbytes(size_t nbits);

View file

@ -34,6 +34,7 @@
#include "mifare/mad.h" #include "mifare/mad.h"
#include "mifare/ndef.h" #include "mifare/ndef.h"
#include "emv/dump.h" #include "emv/dump.h"
#include "protocols.h"
#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up
@ -92,10 +93,10 @@ int CmdHF14AMfWrBl(const char *Cmd)
PrintAndLog("--block no:%d, key type:%c, key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6)); PrintAndLog("--block no:%d, key type:%c, key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
PrintAndLog("--data: %s", sprint_hex(bldata, 16)); PrintAndLog("--data: %s", sprint_hex(bldata, 16));
UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}};
memcpy(c.d.asBytes, key, 6); memcpy(c.d.asBytes, key, 6);
memcpy(c.d.asBytes + 10, bldata, 16); memcpy(c.d.asBytes + 10, bldata, 16);
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
@ -136,9 +137,9 @@ int CmdHF14AMfRdBl(const char *Cmd)
} }
PrintAndLog("--block no:%d, key type:%c, key:%s ", blockNo, keyType?'B':'A', sprint_hex(key, 6)); PrintAndLog("--block no:%d, key type:%c, key:%s ", blockNo, keyType?'B':'A', sprint_hex(key, 6));
UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}};
memcpy(c.d.asBytes, key, 6); memcpy(c.d.asBytes, key, 6);
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
@ -167,7 +168,7 @@ int CmdHF14AMfRdBl(const char *Cmd)
return 2; return 2;
} }
return 0; return 0;
} }
int CmdHF14AMfRdSc(const char *Cmd) int CmdHF14AMfRdSc(const char *Cmd)
@ -233,7 +234,7 @@ int CmdHF14AMfRdSc(const char *Cmd)
PrintAndLog("Command execute timeout"); PrintAndLog("Command execute timeout");
} }
return 0; return 0;
} }
uint8_t FirstBlockOfSector(uint8_t sectorNo) uint8_t FirstBlockOfSector(uint8_t sectorNo)
@ -1327,7 +1328,7 @@ int CmdHF14AMfChk(const char *Cmd)
for (uint16_t t = 0; t < 2; t++) { for (uint16_t t = 0; t < 2; t++) {
if (e_sector[sectorNo].foundKey[t]) { if (e_sector[sectorNo].foundKey[t]) {
num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10); num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10);
keyFoundCount++; // Key found count for information keyFoundCount++; // Key found count for information
} }
} }
mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
@ -1710,10 +1711,10 @@ int CmdHF14AMfDbg(const char *Cmd)
return 0; return 0;
} }
UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}};
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdHF14AMfEGet(const char *Cmd) int CmdHF14AMfEGet(const char *Cmd)
@ -1736,7 +1737,7 @@ int CmdHF14AMfEGet(const char *Cmd)
PrintAndLog("Command execute timeout"); PrintAndLog("Command execute timeout");
} }
return 0; return 0;
} }
int CmdHF14AMfEClear(const char *Cmd) int CmdHF14AMfEClear(const char *Cmd)
@ -1747,9 +1748,9 @@ int CmdHF14AMfEClear(const char *Cmd)
return 0; return 0;
} }
UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}};
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
@ -1956,7 +1957,7 @@ int CmdHF14AMfESave(const char *Cmd)
PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename); PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename);
return 0; return 0;
} }
@ -3009,51 +3010,130 @@ int CmdHFMFNDEF(const char *cmd) {
return 0; return 0;
} }
static command_t CommandTable[] = int CmdHFMFPersonalize(const char *cmd) {
{
{"help", CmdHelp, 1, "This help"}, CLIParserInit("hf mf personalize",
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, "Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, "Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, "\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, "\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, "\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
{"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, "\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
{"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"},
{"chk", CmdHF14AMfChk, 0, "Test block keys"}, void *argtable[] = {
{"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, arg_param_begin,
{"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
{"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
{"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
{"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"}, arg_param_end
{"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"}, };
{"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, CLIExecWithReturn(cmd, argtable, true);
{"eset", CmdHF14AMfESet, 0, "Set simulator memory block"},
{"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, char keytypestr[2] = "A";
{"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, uint8_t keytype = 0x00;
{"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, int keytypestr_len;
{"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len);
{"cwipe", CmdHF14AMfCWipe, 0, "Wipe magic Chinese card"}, if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'A' && keytypestr[0] != 'b' && keytypestr[0] != 'B')) {
{"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"}, PrintAndLog("ERROR: not a valid key type. Key type must be A or B");
{"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"}, CLIParserFree();
{"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"}, return 1;
{"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, }
{"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, if (keytypestr[0] == 'B' || keytypestr[0] == 'b') {
{"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, keytype = 0x01;
{"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, }
{"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"},
{"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"}, uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
{NULL, NULL, 0, NULL} int key_len;
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
if (res || (!res && key_len > 0 && key_len != 6)) {
PrintAndLog("ERROR: not a valid key. Key must be 12 hex digits");
CLIParserFree();
return 1;
}
char pers_optionstr[6];
int opt_len;
uint8_t pers_option;
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t*)pers_optionstr, 5, &opt_len);
if (res || (!res && opt_len > 0 && opt_len != 5)
|| (strncmp(pers_optionstr, "UIDF0", 5) && strncmp(pers_optionstr, "UIDF1", 5) && strncmp(pers_optionstr, "UIDF2", 5) && strncmp(pers_optionstr, "UIDF3", 5))) {
PrintAndLog("ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
CLIParserFree();
return 1;
}
if (!strncmp(pers_optionstr, "UIDF0", 5)) {
pers_option = MIFARE_EV1_UIDF0;
} else if (!strncmp(pers_optionstr, "UIDF1", 5)) {
pers_option = MIFARE_EV1_UIDF1;
} else if (!strncmp(pers_optionstr, "UIDF2", 5)) {
pers_option = MIFARE_EV1_UIDF2;
} else {
pers_option = MIFARE_EV1_UIDF3;
}
CLIParserFree();
UsbCommand c = {CMD_MIFARE_PERSONALIZE_UID, {keytype, pers_option, 0}};
memcpy(c.d.asBytes, key, 6);
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("Personalization %s", isOK ? "FAILED" : "SUCCEEDED");
} else {
PrintAndLog("Command execute timeout");
}
return 0;
}
static command_t CommandTable[] = {
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},
{"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"},
{"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"},
{"chk", CmdHF14AMfChk, 0, "Test block keys"},
{"mifare", CmdHF14AMifare, 0, "Read parity error messages."},
{"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"},
{"nested", CmdHF14AMfNested, 0, "Test nested authentication"},
{"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
{"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"},
{"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"},
{"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"},
{"eset", CmdHF14AMfESet, 0, "Set simulator memory block"},
{"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"},
{"esave", CmdHF14AMfESave, 0, "Save to file emul dump"},
{"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"},
{"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"},
{"cwipe", CmdHF14AMfCWipe, 0, "Wipe magic Chinese card"},
{"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"},
{"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"},
{"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"},
{"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"},
{"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"},
{"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"},
{"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"},
{"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"},
{"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"},
{"personalize", CmdHFMFPersonalize, 0, "Personalize UID (Mifare Classic EV1 only)"},
{NULL, NULL, 0, NULL}
}; };
int CmdHFMF(const char *Cmd)
{ int CmdHFMF(const char *Cmd) {
(void)WaitForResponseTimeout(CMD_ACK,NULL,100); (void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }
int CmdHelp(const char *Cmd)
{ int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return 0;
} }

View file

@ -22,15 +22,13 @@
#include "hitag.h" #include "hitag.h"
#include "cmdmain.h" #include "cmdmain.h"
static int CmdHelp(const char *Cmd); static size_t nbytes(size_t nbits) {
return (nbits/8) + ((nbits%8)>0);
size_t nbytes(size_t nbits) {
return (nbits/8)+((nbits%8)>0);
} }
int CmdLFHitagList(const char *Cmd)
{ static int CmdLFHitagList(const char *Cmd) {
uint8_t *got = malloc(USB_CMD_DATA_SIZE); uint8_t *got = malloc(USB_CMD_DATA_SIZE);
// Query for the actual size of the trace // Query for the actual size of the trace
UsbCommand response; UsbCommand response;
GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false);
@ -95,7 +93,7 @@ int CmdLFHitagList(const char *Cmd)
int len = nbytes(bits); int len = nbytes(bits);
if (len > 100) { if (len > 100) {
break; break;
} }
if (i + len > traceLen) { break;} if (i + len > traceLen) { break;}
@ -133,12 +131,12 @@ int CmdLFHitagList(const char *Cmd)
char line[1000] = ""; char line[1000] = "";
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
//if((parityBits >> (len - j - 1)) & 0x01) { //if((parityBits >> (len - j - 1)) & 0x01) {
if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) {
sprintf(line+(j*4), "%02x! ", frame[j]); sprintf(line+(j*4), "%02x! ", frame[j]);
} else { } else {
sprintf(line+(j*4), "%02x ", frame[j]); sprintf(line+(j*4), "%02x ", frame[j]);
} }
} }
PrintAndLog(" +%7d: %3d: %s %s", PrintAndLog(" +%7d: %3d: %s %s",
@ -168,15 +166,17 @@ int CmdLFHitagList(const char *Cmd)
return 0; return 0;
} }
int CmdLFHitagSnoop(const char *Cmd) {
UsbCommand c = {CMD_SNOOP_HITAG}; static int CmdLFHitagSnoop(const char *Cmd) {
SendCommand(&c); UsbCommand c = {CMD_SNOOP_HITAG};
return 0; SendCommand(&c);
return 0;
} }
int CmdLFHitagSim(const char *Cmd) {
UsbCommand c = {CMD_SIMULATE_HITAG}; static int CmdLFHitagSim(const char *Cmd) {
UsbCommand c = {CMD_SIMULATE_HITAG};
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf; FILE* pf;
bool tag_mem_supplied; bool tag_mem_supplied;
@ -203,52 +203,110 @@ int CmdLFHitagSim(const char *Cmd) {
// Does the tag comes with memory // Does the tag comes with memory
c.arg[0] = (uint32_t)tag_mem_supplied; c.arg[0] = (uint32_t)tag_mem_supplied;
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
static bool getHitagUid(uint32_t *uid) {
// ToDo: this is for Hitag2 only (??)
UsbCommand c = {CMD_READER_HITAG, {RHT2F_UID_ONLY}};
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return false;
}
if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
return false;
}
if (uid)
*uid = bytes_to_num(resp.d.asBytes, 4);
return true;
}
static int CmdLFHitagInfo(const char *Cmd) {
char ctmp = param_getchar(Cmd, 0);
if (ctmp != '\0') {
PrintAndLog("Usage: lf hitag info [h]");
PrintAndLog("Options:");
PrintAndLog(" h This help");
PrintAndLog("Examples:");
PrintAndLog(" lf hitag info");
return 0;
}
// read UID
uint32_t uid = 0;
if (getHitagUid(&uid) == false)
return 1;
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
// how to detemine Hitag types?
// read block3, get configuration byte.
// PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
// common configurations.
// printHitagConfiguration(0x06);
//printHitagConfiguration( 0x0E );
//printHitagConfiguration( 0x02 );
//printHitagConfiguration( 0x00 );
//printHitagConfiguration( 0x04 );
return 0;
}
int CmdLFHitagReader(const char *Cmd) { int CmdLFHitagReader(const char *Cmd) {
UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}}; UsbCommand c = {CMD_READER_HITAG};
hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10); hitag_function htf = param_get32ex(Cmd, 0, 0, 10);
switch (htf) { switch (htf) {
case 01: { //RHTSF_CHALLENGE case 01: { //RHTSF_CHALLENGE
c = (UsbCommand){ CMD_READ_HITAG_S }; c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode
} break; } break;
case 02: { //RHTSF_KEY case 02: { //RHTSF_KEY
c = (UsbCommand){ CMD_READ_HITAG_S }; c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode
} break; } break;
case 03: { //RHTSF_CHALLENGE BLOCK case 03: { //RHTSF_CHALLENGE BLOCK
c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; c = (UsbCommand){ CMD_READ_HITAG_S_BLK };
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode
} break; } break;
case 04: { //RHTSF_KEY BLOCK case 04: { //RHTSF_KEY BLOCK
c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; c = (UsbCommand){ CMD_READ_HITAG_S_BLK };
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode
} break; } break;
case RHT2F_PASSWORD: { case RHT2F_PASSWORD: {
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
} break; } break;
case RHT2F_AUTHENTICATE: { case RHT2F_AUTHENTICATE: {
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
} break; } break;
case RHT2F_CRYPTO: { case RHT2F_CRYPTO: {
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
// num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); // num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4);
} break; } break;
case RHT2F_TEST_AUTH_ATTEMPTS: { case RHT2F_TEST_AUTH_ATTEMPTS: {
// No additional parameters needed // No additional parameters needed
@ -261,19 +319,20 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog(""); PrintAndLog("");
PrintAndLog("Usage: hitag reader <Reader Function #>"); PrintAndLog("Usage: hitag reader <Reader Function #>");
PrintAndLog("Reader Functions:"); PrintAndLog("Reader Functions:");
PrintAndLog(" HitagS (0*)"); PrintAndLog(" HitagS (0*):");
PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag"); PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag"); PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag"); PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag");
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag"); PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag");
PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)");
PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag1 (1*):");
PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" (not yet implemented)");
PrintAndLog(" 21 <password> (password mode)"); PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 22 <nr> <ar> (authentication)"); PrintAndLog(" 21 <password> (password mode)");
PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low"); PrintAndLog(" 22 <nr> <ar> (authentication)");
PrintAndLog(" 25 (test recorded authentications)"); PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low");
PrintAndLog(" 26 just read UID"); PrintAndLog(" 25 (test recorded authentications)");
PrintAndLog(" 26 just read UID");
return 1; return 1;
} break; } break;
} }
@ -286,10 +345,16 @@ int CmdLFHitagReader(const char *Cmd) {
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
WaitForResponse(CMD_ACK,&resp); if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument // Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1; if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return 1;
}
uint32_t id = bytes_to_num(resp.d.asBytes,4); uint32_t id = bytes_to_num(resp.d.asBytes,4);
@ -312,12 +377,11 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog("Succesfully saved tag memory to [%s]",filename); PrintAndLog("Succesfully saved tag memory to [%s]",filename);
} }
return 0; return 0;
} }
int CmdLFHitagSimS(const char *Cmd) { static int CmdLFHitagSimS(const char *Cmd) {
UsbCommand c = { CMD_SIMULATE_HITAG_S }; UsbCommand c = { CMD_SIMULATE_HITAG_S };
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf; FILE* pf;
@ -350,7 +414,8 @@ int CmdLFHitagSimS(const char *Cmd) {
return 0; return 0;
} }
int CmdLFHitagCheckChallenges(const char *Cmd) {
static int CmdLFHitagCheckChallenges(const char *Cmd) {
UsbCommand c = { CMD_TEST_HITAGS_TRACES }; UsbCommand c = { CMD_TEST_HITAGS_TRACES };
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf; FILE* pf;
@ -369,7 +434,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
PrintAndLog("Error: File reading error"); PrintAndLog("Error: File reading error");
fclose(pf); fclose(pf);
return 1; return 1;
} }
fclose(pf); fclose(pf);
} else { } else {
file_given = false; file_given = false;
@ -379,77 +444,91 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
c.arg[0] = (uint32_t)file_given; c.arg[0] = (uint32_t)file_given;
c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdLFHitagWP(const char *Cmd) { static int CmdLFHitagWriter(const char *Cmd) {
UsbCommand c = { CMD_WR_HITAG_S }; UsbCommand c = { CMD_WR_HITAG_S };
hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10); hitag_function htf = param_get32ex(Cmd,0,0,10);
switch (htf) { switch (htf) {
case 03: { //WHTSF_CHALLENGE case WHTSF_CHALLENGE: {
num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr); num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10); c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
} break; } break;
case 04: case WHTSF_KEY:
case 24: case WHT2F_CRYPTO: {
{ //WHTSF_KEY
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10); c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
} break;
case WHT2F_PASSWORD: {
num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
c.arg[2] = param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd, 3, 0, 16), 4, htd->crypto.data);
} break; } break;
default: { default: {
PrintAndLog("Error: unkown writer function %d",htf); PrintAndLog("Error: unkown writer function %d",htf);
PrintAndLog("Hitag writer functions"); PrintAndLog("Hitag writer functions");
PrintAndLog(" HitagS (0*)"); PrintAndLog(" HitagS (0*):");
PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag1 (1*)");
PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" (not yet implemented)");
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 27 <password> <page> <byte0...byte3> write page on a Hitag2 tag");
return 1; return 1;
} break; } break;
} }
// Copy the hitag function into the first argument // Copy the hitag function into the first argument
c.arg[0] = htf; c.arg[0] = htf;
// Send the command to the proxmark // Send the command to the proxmark
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
WaitForResponse(CMD_ACK,&resp); if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument // Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1; if (resp.arg[0] == false) {
return 0; PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
return 1;
}
return 0;
} }
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"list", CmdLFHitagList, 1, "<outfile> List Hitag trace history"}, {"list", CmdLFHitagList, 0, "<outfile> List Hitag trace history"},
{"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, {"info", CmdLFHitagInfo, 0, "Tag information" },
{"sim", CmdLFHitagSim, 1, "<infile> Simulate Hitag transponder"}, {"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"},
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, {"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"},
{"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, {"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"},
{"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" }, {"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" },
{"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> <tagmode> test all challenges" }, { {"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" },
NULL,NULL, 0, NULL } {"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" },
{ NULL, NULL, 0, NULL }
}; };
int CmdLFHitag(const char *Cmd)
{ static int CmdHelp(const char *Cmd) {
CmdsParse(CommandTable, Cmd); CmdsHelp(CommandTable);
return 0; return 0;
} }
int CmdHelp(const char *Cmd)
{ int CmdLFHitag(const char *Cmd) {
CmdsHelp(CommandTable); CmdsParse(CommandTable, Cmd);
return 0; return 0;
} }

View file

@ -11,11 +11,7 @@
#ifndef CMDLFHITAG_H__ #ifndef CMDLFHITAG_H__
#define CMDLFHITAG_H__ #define CMDLFHITAG_H__
int CmdLFHitag(const char *Cmd); extern int CmdLFHitag(const char *Cmd);
extern int CmdLFHitagReader(const char *Cmd);
int CmdLFHitagList(const char *Cmd);
int CmdLFHitagSnoop(const char *Cmd);
int CmdLFHitagSim(const char *Cmd);
int CmdLFHitagReader(const char *Cmd);
#endif #endif

View file

@ -42,11 +42,11 @@ int ukbhit(void)
Ntty.c_oflag = 0x0000; // output mode Ntty.c_oflag = 0x0000; // output mode
Ntty.c_lflag &= ~ICANON; // control mode = raw Ntty.c_lflag &= ~ICANON; // control mode = raw
Ntty.c_cc[VMIN] = 1; // return if at least 1 character is in the queue Ntty.c_cc[VMIN] = 1; // return if at least 1 character is in the queue
Ntty.c_cc[VTIME] = 0; // no timeout. Wait forever Ntty.c_cc[VTIME] = 0; // no timeout. Wait forever
if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes
error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe
error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes
} }
return ( error == 0 ? cnt : -1 ); return ( error == 0 ? cnt : -1 );
@ -78,12 +78,12 @@ int ukbhit(void) {
// log files functions // log files functions
void AddLogLine(char *file, char *extData, char *c) { void AddLogLine(char *file, char *extData, char *c) {
FILE *fLog = NULL; FILE *fLog = NULL;
char filename[FILE_PATH_SIZE] = {0x00}; char filename[FILE_PATH_SIZE] = {0x00};
int len = 0; int len = 0;
len = strlen(file); len = strlen(file);
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
memcpy(filename, file, len); memcpy(filename, file, len);
fLog = fopen(filename, "a"); fLog = fopen(filename, "a");
if (!fLog) { if (!fLog) {
@ -268,7 +268,7 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st
} }
char *sprint_ascii(const uint8_t *data, const size_t len) { char *sprint_ascii(const uint8_t *data, const size_t len) {
return sprint_ascii_ex(data, len, 0); return sprint_ascii_ex(data, len, 0);
} }
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
@ -290,7 +290,7 @@ uint64_t bytes_to_num(uint8_t* src, size_t len)
return num; return num;
} }
void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) {
while (len--) { while (len--) {
dest[len] = n & 1; dest[len] = n & 1;
n >>= 1; n >>= 1;
@ -333,22 +333,22 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS
//assumes little endian //assumes little endian
char *printBits(size_t const size, void const * const ptr) char *printBits(size_t const size, void const * const ptr)
{ {
unsigned char *b = (unsigned char*) ptr; unsigned char *b = (unsigned char*) ptr;
unsigned char byte; unsigned char byte;
static char buf[1024]; static char buf[1024];
char *tmp = buf; char *tmp = buf;
int i, j; int i, j;
for (i=size-1;i>=0;i--) for (i=size-1;i>=0;i--)
{ {
for (j=7;j>=0;j--) for (j=7;j>=0;j--)
{ {
byte = b[i] & (1<<j); byte = b[i] & (1<<j);
byte >>= j; byte >>= j;
sprintf(tmp, "%u", (unsigned int)byte); sprintf(tmp, "%u", (unsigned int)byte);
tmp++; tmp++;
} }
} }
return buf; return buf;
} }
@ -461,7 +461,7 @@ uint8_t param_isdec(const char *line, int paramnum)
int bg, en; int bg, en;
//TODO, check more thorougly //TODO, check more thorougly
if (!param_getptr(line, &bg, &en, paramnum)) return 1; if (!param_getptr(line, &bg, &en, paramnum)) return 1;
// return strtoul(&line[bg], NULL, 10) & 0xff; // return strtoul(&line[bg], NULL, 10) & 0xff;
return 0; return 0;
} }
@ -496,7 +496,7 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base)
return deflt; return deflt;
} }
int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) int param_gethex(const char *line, int paramnum, uint8_t *data, int hexcnt)
{ {
int bg, en, temp, i; int bg, en, temp, i;
@ -509,7 +509,7 @@ int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt)
return 1; return 1;
for(i = 0; i < hexcnt; i += 2) { for(i = 0; i < hexcnt; i += 2) {
if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1;
sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp); sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
data[i / 2] = temp & 0xff; data[i / 2] = temp & 0xff;
@ -523,7 +523,7 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt)
int bg, en, temp, i; int bg, en, temp, i;
//if (hexcnt % 2) //if (hexcnt % 2)
// return 1; // return 1;
if (param_getptr(line, &bg, &en, paramnum)) return 1; if (param_getptr(line, &bg, &en, paramnum)) return 1;
@ -534,7 +534,7 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt)
return 1; return 1;
for(i = 0; i < *hexcnt; i += 2) { for(i = 0; i < *hexcnt; i += 2) {
if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1;
sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp); sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp);
data[i / 2] = temp & 0xff; data[i / 2] = temp & 0xff;
@ -618,100 +618,100 @@ https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/
// returns number of bits converted // returns number of bits converted
int hextobinarray(char *target, char *source) int hextobinarray(char *target, char *source)
{ {
int length, i, count= 0; int length, i, count= 0;
char* start = source; char* start = source;
char x; char x;
length = strlen(source); length = strlen(source);
// process 4 bits (1 hex digit) at a time // process 4 bits (1 hex digit) at a time
while(length--) while(length--)
{ {
x= *(source++); x= *(source++);
// capitalize // capitalize
if (x >= 'a' && x <= 'f') if (x >= 'a' && x <= 'f')
x -= 32; x -= 32;
// convert to numeric value // convert to numeric value
if (x >= '0' && x <= '9') if (x >= '0' && x <= '9')
x -= '0'; x -= '0';
else if (x >= 'A' && x <= 'F') else if (x >= 'A' && x <= 'F')
x -= 'A' - 10; x -= 'A' - 10;
else { else {
printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start); printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start);
return 0; return 0;
} }
// output // output
for(i= 0 ; i < 4 ; ++i, ++count) for(i= 0 ; i < 4 ; ++i, ++count)
*(target++)= (x >> (3 - i)) & 1; *(target++)= (x >> (3 - i)) & 1;
} }
return count; return count;
} }
// convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source) // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
// return number of bits converted // return number of bits converted
int binarraytohex(char *target,char *source, int length) int binarraytohex(char *target,char *source, int length)
{ {
unsigned char i, x; unsigned char i, x;
int j = length; int j = length;
if(j % 4) if(j % 4)
return 0; return 0;
while(j) while(j)
{ {
for(i= x= 0 ; i < 4 ; ++i) for(i= x= 0 ; i < 4 ; ++i)
x += ( source[i] << (3 - i)); x += ( source[i] << (3 - i));
sprintf(target,"%X", (unsigned int)x); sprintf(target,"%X", (unsigned int)x);
++target; ++target;
source += 4; source += 4;
j -= 4; j -= 4;
} }
return length; return length;
} }
// return parity bit required to match type // return parity bit required to match type
uint8_t GetParity( uint8_t *bits, uint8_t type, int length) uint8_t GetParity( uint8_t *bits, uint8_t type, int length)
{ {
int x; int x;
for(x= 0 ; length > 0 ; --length) for(x= 0 ; length > 0 ; --length)
x += bits[length - 1]; x += bits[length - 1];
x %= 2; x %= 2;
return x ^ type; return x ^ type;
} }
// add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half // add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half
void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length) void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length)
{ {
*(target++)= GetParity(source, EVEN, length / 2); *(target++)= GetParity(source, EVEN, length / 2);
memcpy(target, source, length); memcpy(target, source, length);
target += length; target += length;
*(target)= GetParity(source + length / 2, ODD, length / 2); *(target)= GetParity(source + length / 2, ODD, length / 2);
} }
// xor two arrays together for len items. The dst array contains the new xored values. // xor two arrays together for len items. The dst array contains the new xored values.
void xor(unsigned char *dst, unsigned char *src, size_t len) { void xor(unsigned char *dst, unsigned char *src, size_t len) {
for( ; len > 0; len--,dst++,src++) for( ; len > 0; len--,dst++,src++)
*dst ^= *src; *dst ^= *src;
} }
// RotateLeft - Ultralight, Desfire, works on byte level // RotateLeft - Ultralight, Desfire, works on byte level
// 00-01-02 >> 01-02-00 // 00-01-02 >> 01-02-00
void rol(uint8_t *data, const size_t len){ void rol(uint8_t *data, const size_t len){
uint8_t first = data[0]; uint8_t first = data[0];
for (size_t i = 0; i < len-1; i++) { for (size_t i = 0; i < len-1; i++) {
data[i] = data[i+1]; data[i] = data[i+1];
} }
data[len-1] = first; data[len-1] = first;
} }
// Replace unprintable characters with a dot in char buffer // Replace unprintable characters with a dot in char buffer
void clean_ascii(unsigned char *buf, size_t len) { void clean_ascii(unsigned char *buf, size_t len) {
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
if (!isprint(buf[i])) if (!isprint(buf[i]))
buf[i] = '.'; buf[i] = '.';
} }
} }
@ -724,8 +724,8 @@ void strcleanrn(char *buf, size_t len) {
// replace char in buffer // replace char in buffer
void strcreplace(char *buf, size_t len, char from, char to) { void strcreplace(char *buf, size_t len, char from, char to) {
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
if (buf[i] == from) if (buf[i] == from)
buf[i] = to; buf[i] = to;
} }
} }

View file

@ -125,6 +125,10 @@ NXP/Philips CUSTOM COMMANDS
#define MIFARE_CMD_TRANSFER 0xB0 #define MIFARE_CMD_TRANSFER 0xB0
#define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_UIDF0 0x00
#define MIFARE_EV1_UIDF1 0x40
#define MIFARE_EV1_UIDF2 0x20
#define MIFARE_EV1_UIDF3 0x60
#define MIFARE_EV1_SETMODE 0x43 #define MIFARE_EV1_SETMODE 0x43
#define MIFARE_ULC_WRITE 0xA2 #define MIFARE_ULC_WRITE 0xA2
@ -232,6 +236,26 @@ NXP/Philips CUSTOM COMMANDS
#define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes) #define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes)
#define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes) #define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes)
// HITAG1 commands
#define HITAG1_SET_CCNEW 0xC2 // left 5 bits only
#define HITAG1_READ_ID 0x00 // not a real command, consists of 5 bits length, <length> bits partial SN, 8 bits CRC
#define HITAG1_SELECT 0x00 // left 5 bits only, followed by 32 bits SN and 8 bits CRC
#define HITAG1_WRPPAGE 0x80 // left 4 bits only, followed by 8 bits page and 8 bits CRC
#define HITAG1_WRPBLK 0x90 // left 4 bits only, followed by 8 bits block and 8 bits CRC
#define HITAG1_WRCPAGE 0xA0 // left 4 bits only, followed by 8 bits page or key information and 8 bits CRC
#define HITAG1_WRCBLK 0xB0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
#define HITAG1_RDPPAGE 0xC0 // left 4 bits only, followed by 8 bits page and 8 bits CRC
#define HITAG1_RDPBLK 0xD0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
#define HITAG1_RDCPAGE 0xE0 // left 4 bits only, followed by 8 bits page and 8 bits CRC
#define HITAG1_RDCBLK 0xF0 // left 4 bits only, followed by 8 bits block and 8 bits CRC
#define HITAG1_HALT 0x70 // left 4 bits only, followed by 8 bits (dummy) page and 8 bits CRC
// HITAG2 commands
#define HITAG2_START_AUTH 0xC0 // left 5 bits only
#define HITAG2_READ_PAGE 0xC0 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
#define HITAG2_READ_PAGE_INVERTED 0x44 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
#define HITAG2_WRITE_PAGE 0x82 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
#define HITAG2_HALT 0x00 // left 5 bits only
#define ISO_14443A 0 #define ISO_14443A 0
#define ICLASS 1 #define ICLASS 1

View file

@ -31,6 +31,7 @@ typedef enum {
WHT2F_CRYPTO = 24, WHT2F_CRYPTO = 24,
RHT2F_TEST_AUTH_ATTEMPTS = 25, RHT2F_TEST_AUTH_ATTEMPTS = 25,
RHT2F_UID_ONLY = 26, RHT2F_UID_ONLY = 26,
WHT2F_PASSWORD = 27,
} hitag_function; } hitag_function;
typedef struct { typedef struct {

View file

@ -197,17 +197,17 @@ typedef struct{
#define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613 #define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613
#define CMD_MIFARE_READBL 0x0620 #define CMD_MIFARE_READBL 0x0620
#define CMD_MIFAREU_READBL 0x0720
#define CMD_MIFARE_READSC 0x0621 #define CMD_MIFARE_READSC 0x0621
#define CMD_MIFAREU_READCARD 0x0721
#define CMD_MIFARE_WRITEBL 0x0622 #define CMD_MIFARE_WRITEBL 0x0622
#define CMD_MIFARE_CHKKEYS 0x0623
#define CMD_MIFARE_PERSONALIZE_UID 0x0624
#define CMD_MIFARE_SNIFFER 0x0630
//ultralightC
#define CMD_MIFAREU_READBL 0x0720
#define CMD_MIFAREU_READCARD 0x0721
#define CMD_MIFAREU_WRITEBL 0x0722 #define CMD_MIFAREU_WRITEBL 0x0722
#define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 #define CMD_MIFAREU_WRITEBL_COMPAT 0x0723
#define CMD_MIFARE_CHKKEYS 0x0623
#define CMD_MIFARE_SNIFFER 0x0630
//ultralightC
#define CMD_MIFAREUC_AUTH 0x0724 #define CMD_MIFAREUC_AUTH 0x0724
//0x0725 and 0x0726 no longer used //0x0725 and 0x0726 no longer used
#define CMD_MIFAREUC_SETPWD 0x0727 #define CMD_MIFAREUC_SETPWD 0x0727