From: pwpiwi Date: Sat, 24 Aug 2019 16:27:01 +0000 (+0200) Subject: Merge branch 'master' into iclass_MAC_speedup X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/a1ff338bd5023bac02d51e1de5ca70fbdb90d3bf?hp=1477ba8a3c34f9b7eb624167251efea927755194 Merge branch 'master' into iclass_MAC_speedup --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 5210edbc..e95ccde6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added downlink reference mode option r [ 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 - `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] diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 34d1747b..93f32f5f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -29,6 +29,7 @@ #include "iso15693.h" #include "lfsampling.h" #include "BigBuf.h" +#include "mifarecmd.h" #include "mifareutil.h" #include "mifaresim.h" #include "pcf7931.h" @@ -1243,6 +1244,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_WRITEBL: MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; + case CMD_MIFARE_PERSONALIZE_UID: + MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes); + break; //case CMD_MIFAREU_WRITEBL_COMPAT: //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes); //break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 0302a9f6..5d3e3e59 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -16,7 +16,6 @@ #include #include "common.h" #include "usb_cmd.h" -#include "hitag2.h" #include "hitagS.h" #include "mifare.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_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 -bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); -void MifareDesfireGetInformation(); -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); -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); +bool InitDesfireCard(); +void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); +void MifareDesfireGetInformation(); +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); +int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); +size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); // cmd.h bool cmd_receive(UsbCommand* cmd); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 270958ce..7cdabefa 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -19,12 +19,14 @@ #include "hitag2.h" #include "proxmark3.h" +#include "cmd.h" #include "apps.h" #include "util.h" #include "hitag.h" #include "string.h" #include "BigBuf.h" #include "fpgaloader.h" +#include "protocols.h" static bool bQuiet; @@ -44,9 +46,9 @@ struct hitag2_tag { TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written } state; unsigned int active_sector; - byte_t crypto_active; + uint8_t crypto_active; uint64_t cs; - byte_t sectors[12][4]; + uint8_t sectors[12][4]; }; static struct hitag2_tag tag = { @@ -77,14 +79,14 @@ static enum { // ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. // Historically it used to be FREE_BUFFER_SIZE, which was 2744. #define AUTH_TABLE_LENGTH 2744 -static byte_t* auth_table; +static uint8_t *auth_table; static size_t auth_table_pos = 0; static size_t auth_table_len = AUTH_TABLE_LENGTH; -static byte_t password[4]; -static byte_t NrAr[8]; -static byte_t key[8]; -static byte_t writedata[4]; +static uint8_t password[4]; +static uint8_t NrAr[8]; +static uint8_t key[8]; +static uint8_t writedata[4]; static uint64_t cipher_state; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ @@ -93,57 +95,39 @@ static uint64_t cipher_state; // No warranties or guarantees of any kind. // This code is released into the public domain by its author. -// Basic macros: - -#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))) - // 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 u32 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_f4a = 0x2C79; // 0010 1100 0111 1001 +static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 -static u32 _f20 (const u64 x) -{ - u32 i5; +static uint32_t _f20(const uint64_t x) { + uint32_t i5; - 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,16,20,22,25)) & 1)* 4 - + ((ht2_f4b >> i4 (x,27,28,30,32)) & 1)* 8 - + ((ht2_f4a >> i4 (x,33,42,43,45)) & 1)*16; + 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,16,20,22,25)) & 1) * 4 + + ((ht2_f4b >> i4(x,27,28,30,32)) & 1) * 8 + + ((ht2_f4a >> i4(x,33,42,43,45)) & 1) * 16; return (ht2_f5c >> i5) & 1; } -static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) -{ - u32 i; - u64 x = ((key & 0xFFFF) << 32) + serial; +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++) - { + for (i = 0; i < 32; i++) { x >>= 1; - x += (u64) (_f20 (x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; + x += (uint64_t)(_f20(x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; } return x; } -static u64 _hitag2_round (u64 *state) -{ - u64 x = *state; +static uint64_t _hitag2_round(uint64_t *state) { + uint64_t x = *state; x = (x >> 1) + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) @@ -152,40 +136,36 @@ static u64 _hitag2_round (u64 *state) ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); *state = x; - return _f20 (x); + return _f20(x); } -static u32 _hitag2_byte (u64 * x) -{ - u32 i, c; - - for (i = 0, c = 0; i < 8; i++) c += (u32) _hitag2_round (x) << (i^7); +static uint32_t _hitag2_byte(uint64_t *x) { + uint32_t i, c; + for (i = 0, c = 0; i < 8; i++) { + c += (uint32_t) _hitag2_round(x) << (i^7); + } return c; } -static int hitag2_reset(void) -{ +static int hitag2_reset(void) { tag.state = TAG_STATE_RESET; tag.crypto_active = 0; return 0; } -static int hitag2_init(void) -{ -// memcpy(&tag, &resetdata, sizeof(tag)); +static int hitag2_init(void) { hitag2_reset(); return 0; } -static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) -{ - uint64_t key = ((uint64_t)tag->sectors[2][2]) | +static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv) { + uint64_t key = ((uint64_t)tag->sectors[2][2]) | ((uint64_t)tag->sectors[2][3] << 8) | ((uint64_t)tag->sectors[1][0] << 16) | ((uint64_t)tag->sectors[1][1] << 24) | ((uint64_t)tag->sectors[1][2] << 32) | ((uint64_t)tag->sectors[1][3] << 40); - uint32_t uid = ((uint32_t)tag->sectors[0][0]) | + uint32_t uid = ((uint32_t)tag->sectors[0][0]) | ((uint32_t)tag->sectors[0][1] << 8) | ((uint32_t)tag->sectors[0][2] << 16) | ((uint32_t)tag->sectors[0][3] << 24); @@ -193,12 +173,11 @@ static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) (((uint32_t)(iv[1])) << 8) | (((uint32_t)(iv[2])) << 16) | (((uint32_t)(iv[3])) << 24); - tag->cs = _hitag2_init(rev64(key), rev32(uid), rev32(iv_)); + tag->cs = _hitag2_init(REV64(key), REV32(uid), REV32(iv_)); } -static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_is) -{ - byte_t authenticator_should[4]; +static int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) { + uint8_t authenticator_should[4]; authenticator_should[0] = ~_hitag2_byte(cs); authenticator_should[1] = ~_hitag2_byte(cs); authenticator_should[2] = ~_hitag2_byte(cs); @@ -206,11 +185,10 @@ static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_ return (memcmp(authenticator_should, authenticator_is, 4) == 0); } -static int hitag2_cipher_transcrypt(uint64_t* cs, byte_t *data, unsigned int bytes, unsigned int bits) -{ +static int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, unsigned int bytes, unsigned int bits) { int i; - for(i=0; i 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ -//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define HITAG_FRAME_LEN 20 +#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ -#define HITAG_T_PROG 614 +#define HITAG_T_PROG 614 -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 #define HITAG_T_TAG_FOUR_HALF_PERIOD 57 -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 #define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 - static void hitag_send_bit(int bit) { LED_A_ON(); // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Fixed modulation, earlier proxmark version used inverted signal - if(bit == 0) { + if (bit == 0) { // Manchester: Unloaded, then loaded |__--| LOW(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); HIGH(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } else { // Manchester: Loaded, then unloaded |--__| HIGH(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); LOW(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } LED_A_OFF(); } -static void hitag_send_frame(const byte_t* frame, size_t frame_len) +static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { // Send start of frame - for(size_t i=0; i<5; i++) { + for(size_t i = 0; i < 5; i++) { hitag_send_bit(1); } // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&1); + for (size_t i = 0; i < frame_len; i++) { + hitag_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); } // Drop the modulation LOW(GPIO_SSC_DOUT); } - -static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) -{ - byte_t rx_air[HITAG_FRAME_LEN]; +static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + uint8_t rx_air[HITAG_FRAME_LEN]; // Copy the (original) received frame how it is send over the air - memcpy(rx_air,rx,nbytes(rxlen)); + memcpy(rx_air, rx, nbytes(rxlen)); - if(tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); + if (tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen/8, rxlen%8); } // Reset the transmission frame length @@ -305,112 +277,112 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // Received 11000 from the reader, request for UID, send UID - case 05: { - // Always send over the air in the clear plaintext mode - if(rx_air[0] != 0xC0) { - // Unknown frame ? - return; + case 05: { + // Always send over the air in the clear plaintext mode + if (rx_air[0] != HITAG2_START_AUTH) { + // Unknown frame ? + return; + } + *txlen = 32; + memcpy(tx, tag.sectors[0], 4); + tag.crypto_active = 0; } - *txlen = 32; - memcpy(tx,tag.sectors[0],4); - tag.crypto_active = 0; - } break; // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number - case 10: { - unsigned int sector = (~( ((rx[0]<<2)&0x04) | ((rx[1]>>6)&0x03) ) & 0x07); - // Verify complement of sector index - if(sector != ((rx[0]>>3)&0x07)) { - //DbpString("Transmission error (read/write)"); - return; - } + case 10: { + unsigned int sector = (~( ((rx[0]<<2) & 0x04) | ((rx[1]>>6) & 0x03) ) & 0x07); + // Verify complement of sector index + if (sector != ((rx[0]>>3) & 0x07)) { + //DbpString("Transmission error (read/write)"); + return; + } - switch (rx[0] & 0xC6) { - // Read command: 11xx x00y - case 0xC0: - memcpy(tx,tag.sectors[sector],4); - *txlen = 32; - break; + switch (rx[0] & 0xC6) { + // Read command: 11xx x00y + case HITAG2_READ_PAGE: + memcpy(tx, tag.sectors[sector], 4); + *txlen = 32; + break; - // Inverted Read command: 01xx x10y - case 0x44: - for (size_t i=0; i<4; i++) { - tx[i] = tag.sectors[sector][i] ^ 0xff; - } - *txlen = 32; - break; + // Inverted Read command: 01xx x10y + case HITAG2_READ_PAGE_INVERTED: + for (size_t i = 0; i < 4; i++) { + tx[i] = tag.sectors[sector][i] ^ 0xff; + } + *txlen = 32; + break; - // Write command: 10xx x01y - case 0x82: - // Prepare write, acknowledge by repeating command - memcpy(tx,rx,nbytes(rxlen)); - *txlen = rxlen; - tag.active_sector = sector; - tag.state=TAG_STATE_WRITING; - break; + // Write command: 10xx x01y + case HITAG2_WRITE_PAGE: + // Prepare write, acknowledge by repeating command + memcpy(tx, rx, nbytes(rxlen)); + *txlen = rxlen; + tag.active_sector = sector; + tag.state = TAG_STATE_WRITING; + break; - // Unknown command - default: - Dbprintf("Unknown command: %02x %02x",rx[0],rx[1]); - return; - break; + // Unknown command + default: + Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); + return; + break; + } } - } break; // Writing data or Reader password - case 32: { - if(tag.state == TAG_STATE_WRITING) { - // These are the sector contents to be written. We don't have to do anything else. - memcpy(tag.sectors[tag.active_sector],rx,nbytes(rxlen)); - tag.state=TAG_STATE_RESET; - return; - } else { - // Received RWD password, respond with configuration and our password - if(memcmp(rx,tag.sectors[1],4) != 0) { - DbpString("Reader password is wrong"); + case 32: { + if (tag.state == TAG_STATE_WRITING) { + // These are the sector contents to be written. We don't have to do anything else. + memcpy(tag.sectors[tag.active_sector], rx, nbytes(rxlen)); + tag.state = TAG_STATE_RESET; return; + } else { + // Received RWD password, respond with configuration and our password + if (memcmp(rx, tag.sectors[1], 4) != 0) { + DbpString("Reader password is wrong"); + return; + } + *txlen = 32; + memcpy(tx, tag.sectors[3], 4); } - *txlen = 32; - memcpy(tx,tag.sectors[3],4); } - } break; // Received RWD authentication challenge and respnse - case 64: { - // Store the authentication attempt - if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { - memcpy(auth_table+auth_table_len,rx,8); - auth_table_len += 8; - } + case 64: { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { + memcpy(auth_table+auth_table_len, rx, 8); + auth_table_len += 8; + } - // Reset the cipher state - hitag2_cipher_reset(&tag,rx); - // Check if the authentication was correct - if(!hitag2_cipher_authenticate(&(tag.cs),rx+4)) { - // The reader failed to authenticate, do nothing - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); - return; - } - // Succesful, but commented out reporting back to the Host, this may delay to much. - // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + // Reset the cipher state + hitag2_cipher_reset(&tag, rx); + // Check if the authentication was correct + if (!hitag2_cipher_authenticate(&(tag.cs), rx+4)) { + // The reader failed to authenticate, do nothing + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); + return; + } + // Succesful, but commented out reporting back to the Host, this may delay to much. + // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); - // Activate encryption algorithm for all further communication - tag.crypto_active = 1; + // Activate encryption algorithm for all further communication + tag.crypto_active = 1; - // Use the tag password as response - memcpy(tx,tag.sectors[3],4); - *txlen = 32; - } + // Use the tag password as response + memcpy(tx, tag.sectors[3], 4); + *txlen = 32; + } break; } -// LogTraceHitag(rx,rxlen,0,0,false); -// LogTraceHitag(tx,*txlen,0,0,true); + // LogTraceHitag(rx, rxlen, 0, 0, false); + // LogTraceHitag(tx, *txlen, 0, 0, true); - if(tag.crypto_active) { + if (tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); } } @@ -426,295 +398,310 @@ static void hitag_reader_send_bit(int bit) { // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); - // Wait for 4-10 times the carrier period - while(AT91C_BASE_TC0->TC_CV < T0*6); - // SpinDelayUs(8*8); + // t_low = 4...10 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*6); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); - if(bit == 0) { - // Zero bit: |_-| - while(AT91C_BASE_TC0->TC_CV < T0*22); - // SpinDelayUs(16*8); + if (bit == 0) { + // Zero bit: |_-|, T[0] = 18...22 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*22); } else { - // One bit: |_--| - while(AT91C_BASE_TC0->TC_CV < T0*28); - // SpinDelayUs(22*8); + // One bit: |_--|, T[1] = 26...32 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*28); } LED_A_OFF(); } -static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) +static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&1); + for(size_t i = 0; i < frame_len; i++) { + hitag_reader_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); } // Send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); - // Wait for 4-10 times the carrier period - while(AT91C_BASE_TC0->TC_CV < T0*6); + // t_low = 4...10 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*6); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); + // t_stop > 36 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*36); } size_t blocknr; -static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +//----------------------------------------------------------------------------- +// Hitag2 operations +//----------------------------------------------------------------------------- + +static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + switch (writestate) { + case WRITE_STATE_START: + tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + *txlen = 10; + writestate = WRITE_STATE_PAGENUM_WRITTEN; + break; + case WRITE_STATE_PAGENUM_WRITTEN: + // Check if page number was received correctly + if ((rxlen == 10) + && (rx[0] == (HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2))) + && (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { + *txlen = 32; + memset(tx, 0, HITAG_FRAME_LEN); + memcpy(tx, writedata, 4); + writestate = WRITE_STATE_PROG; + } else { + Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen=%d rx=%02x%02x%02x%02x", + rxlen, rx[0], rx[1], rx[2], rx[3]); + bSuccessful = false; + return false; + } + break; + case WRITE_STATE_PROG: + if (rxlen == 0) { + bSuccessful = true; + } else { + bSuccessful = false; + Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); + } + return false; + default: + DbpString("hitag2_write_page: Unknown state %d"); + bSuccessful = false; + return false; + } + + return true; +} + +static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { // Reset the transmission frame length *txlen = 0; - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer (after sending password) - if (bPwd) { - DbpString("Password failed!"); + if (bPwd && !bAuthenticating && write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { return false; } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; + } else { + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer (after sending password) + if (bPwd) { + DbpString("Password failed!"); + return false; + } + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; - // Received UID, tag password - case 32: { - if (!bPwd) { - *txlen = 32; - memcpy(tx,password,4); - bPwd = true; - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; - } else { + // Received UID, tag password + case 32: { + if (!bPwd) { + bPwd = true; + bAuthenticating = true; + memcpy(tx, password, 4); + *txlen = 32; + } else { + if (bAuthenticating) { + bAuthenticating = false; + if (write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + break; + } + } else { + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } - if(blocknr == 1){ - //store password in block1, the TAG answers with Block3, but we need the password in memory - memcpy(tag.sectors[blocknr],tx,4); - }else{ - memcpy(tag.sectors[blocknr],rx,4); + if (blocknr > 7) { + DbpString("Read successful!"); + bSuccessful = true; + return false; + } + tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + *txlen = 10; + } } + break; - blocknr++; - if (blocknr > 7) { - DbpString("Read succesful!"); - bSuccessful = true; + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d", rxlen); return false; } - *txlen = 10; - tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - } - } break; - - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - return true; -} - -static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) -{ - switch (writestate) { - case WRITE_STATE_START: - *txlen = 10; - tx[0] = 0x82 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - writestate = WRITE_STATE_PAGENUM_WRITTEN; - break; - case WRITE_STATE_PAGENUM_WRITTEN: - // Check if page number was received correctly - if ((rxlen == 10) && - (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && - (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { - *txlen = 32; - memset(tx, 0, HITAG_FRAME_LEN); - memcpy(tx, writedata, 4); - writestate = WRITE_STATE_PROG; - } else { - Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen=%d rx=%02x%02x%02x%02x", - rxlen, rx[0], rx[1], rx[2], rx[3]); - bSuccessful = false; - return false; - } - break; - case WRITE_STATE_PROG: - if (rxlen == 0) { - bSuccessful = true; - } else { - bSuccessful = false; - Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); + break; } - return false; - default: - DbpString("hitag2_write_page: Unknown state %d"); - bSuccessful = false; - return false; } return true; } -static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen, bool write) { +static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { // Reset the transmission frame length *txlen = 0; - if(bCrypto) { - hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8); - + if (bCrypto) { + hitag2_cipher_transcrypt(&cipher_state, rx, rxlen/8, rxlen%8); } if (bCrypto && !bAuthenticating && write) { if (!hitag2_write_page(rx, rxlen, tx, txlen)) { return false; } - } - else - { + } else { - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: - { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - // Failed during authentication - if (bAuthenticating) { - DbpString("Authentication failed!"); - return false; - } else { - // Failed reading a block, could be (read/write) locked, skip block and re-authenticate - if (blocknr == 1) { - // Write the low part of the key in memory - memcpy(tag.sectors[1],key+2,4); - } else if (blocknr == 2) { - // Write the high part of the key in memory - tag.sectors[2][0] = 0x00; - tag.sectors[2][1] = 0x00; - tag.sectors[2][2] = key[0]; - tag.sectors[2][3] = key[1]; + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + // Failed during authentication + if (bAuthenticating) { + DbpString("Authentication failed!"); + return false; + } else { + // Failed reading a block, could be (read/write) locked, skip block and re-authenticate + if (blocknr == 1) { + // Write the low part of the key in memory + memcpy(tag.sectors[1], key+2, 4); + } else if (blocknr == 2) { + // Write the high part of the key in memory + tag.sectors[2][0] = 0x00; + tag.sectors[2][1] = 0x00; + tag.sectors[2][2] = key[0]; + tag.sectors[2][3] = key[1]; + } else { + // Just put zero's in the memory (of the unreadable block) + memset(tag.sectors[blocknr], 0x00, 4); + } + blocknr++; + bCrypto = false; + } } else { - // Just put zero's in the memory (of the unreadable block) - memset(tag.sectors[blocknr],0x00,4); + tx[0] = HITAG2_START_AUTH; + *txlen = 5; } - blocknr++; - bCrypto = false; + break; } - } else { - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } - break; - } - // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; - uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; - Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x", (uint32_t) ((rev64(ui64key)) >> 32), (uint32_t) ((rev64(ui64key)) & 0xffffffff), rev32(ui32uid)); - cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0); - memset(tx,0x00,4); - memset(tx+4,0xff,4); - hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); - *txlen = 64; - bCrypto = true; - bAuthenticating = true; - } else { - // Check if we received answer tag (at) - if (bAuthenticating) { - bAuthenticating = false; - if (write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; + uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; + Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x", (uint32_t) ((REV64(ui64key)) >> 32), (uint32_t) ((REV64(ui64key)) & 0xffffffff), REV32(ui32uid)); + cipher_state = _hitag2_init(REV64(ui64key), REV32(ui32uid), 0); + memset(tx, 0x00, 4); + memset(tx+4, 0xff, 4); + hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); + *txlen = 64; + bCrypto = true; + bAuthenticating = true; + } else { + // Check if we received answer tag (at) + if (bAuthenticating) { + bAuthenticating = false; + if (write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + break; + } + } + // stage 2+, got data block + else { + // Store the received block + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } + if (blocknr > 7) { + DbpString("Read successful!"); + bSuccessful = true; return false; + } else { + tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + *txlen = 10; } - break; } - } else { - // Store the received block - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; } + break; - if (blocknr > 7) { - DbpString("Read succesful!"); - bSuccessful = true; + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d",rxlen); return false; - } else { - *txlen = 10; - tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); } + break; } - } break; - - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } } - if(bCrypto) { + if (bCrypto) { // We have to return now to avoid double encryption if (!bAuthenticating) { - hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8); + hitag2_cipher_transcrypt(&cipher_state, tx, *txlen/8, *txlen%8); } } return true; } - -static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { // Reset the transmission frame length *txlen = 0; // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - DbpString("Authentication failed!"); - return false; + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + DbpString("Authentication failed!"); + return false; + } + tx[0] = HITAG2_START_AUTH; + *txlen = 5; } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; + break; // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - *txlen = 64; - memcpy(tx,NrAr,8); - bCrypto = true; - } else { - DbpString("Authentication succesful!"); - // We are done... for now - return false; + case 32: { + if (!bCrypto) { + memcpy(tx, NrAr, 8); + *txlen = 64; + bCrypto = true; + } else { + DbpString("Authentication successful!"); + // We are done... for now + return false; + } } - } break; + break; // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; + default: { + Dbprintf("Unknown frame length: %d",rxlen); + return false; + } + break; } return true; } - -static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { // Reset the transmission frame length *txlen = 0; @@ -722,93 +709,99 @@ static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); - // Removing failed entry from authentiations table - memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8); - auth_table_len -= 8; + // Removing failed entry from authentiations table + memcpy(auth_table+auth_table_pos, auth_table+auth_table_pos+8, 8); + auth_table_len -= 8; - // Return if we reached the end of the authentications table - bCrypto = false; - if (auth_table_pos == auth_table_len) { - return false; - } + // Return if we reached the end of the authentications table + bCrypto = false; + if (auth_table_pos == auth_table_len) { + return false; + } - // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) - memcpy(NrAr,auth_table+auth_table_pos,8); + // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) + memcpy(NrAr, auth_table+auth_table_pos, 8); + } + tx[0] = HITAG2_START_AUTH; + *txlen = 5; } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; + break; // Received UID, crypto tag answer, or read block response - case 32: { - if (!bCrypto) { - *txlen = 64; - memcpy(tx,NrAr,8); - bCrypto = true; - } else { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); - bCrypto = false; - if ((auth_table_pos+8) == auth_table_len) { - return false; + case 32: { + if (!bCrypto) { + *txlen = 64; + memcpy(tx, NrAr, 8); + bCrypto = true; + } else { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); + bCrypto = false; + if ((auth_table_pos+8) == auth_table_len) { + return false; + } + auth_table_pos += 8; + memcpy(NrAr, auth_table+auth_table_pos, 8); } - auth_table_pos += 8; - memcpy(NrAr,auth_table+auth_table_pos,8); } - } break; + break; - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; + default: { + Dbprintf("Unknown frame length: %d",rxlen); + return false; + } + break; } return true; } -static bool hitag2_read_uid(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { +static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { // Reset the transmission frame length *txlen = 0; // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect - case 0: { - // Just starting or if there is no answer - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; + case 0: { + // Just starting or if there is no answer + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; // Received UID - case 32: { - // Check if we received answer tag (at) - if (bAuthenticating) { - bAuthenticating = false; - } else { - // Store the received block - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; + case 32: { + // Check if we received answer tag (at) + if (bAuthenticating) { + bAuthenticating = false; + } else { + // Store the received block + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } + if (blocknr > 0) { + //DbpString("Read successful!"); + bSuccessful = true; + return false; + } } - if (blocknr > 0) { - //DbpString("Read successful!"); - bSuccessful = true; + break; + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d",rxlen); return false; } - } break; - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; + break; } return true; } void SnoopHitag(uint32_t type) { - int frame_count; + // int frame_count; int response; int overflow; bool rising_edge; @@ -816,8 +809,8 @@ void SnoopHitag(uint32_t type) { int lastbit; bool bSkip; int tag_sof; - byte_t rx[HITAG_FRAME_LEN] = {0}; - size_t rxlen=0; + uint8_t rx[HITAG_FRAME_LEN] = {0}; + size_t rxlen = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -829,7 +822,7 @@ void SnoopHitag(uint32_t type) { auth_table_pos = 0; BigBuf_free(); - auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); + auth_table = (uint8_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); DbpString("Starting Hitag2 snoop"); @@ -840,7 +833,6 @@ void SnoopHitag(uint32_t type) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -858,14 +850,13 @@ void SnoopHitag(uint32_t type) { // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. - uint32_t t1_channel_mode = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; - AT91C_BASE_TC1->TC_CMR = t1_channel_mode; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; overflow = 0; reader_frame = false; @@ -873,14 +864,14 @@ void SnoopHitag(uint32_t type) { bSkip = true; tag_sof = 4; - while(!BUTTON_PRESS()) { + while (!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -892,7 +883,7 @@ void SnoopHitag(uint32_t type) { // Switch from tag to reader capture LED_C_OFF(); reader_frame = true; - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; } @@ -909,17 +900,17 @@ void SnoopHitag(uint32_t type) { if (reader_frame) { LED_B_ON(); // Capture reader frame - if(ra >= HITAG_T_STOP) { + if (ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if(ra >= HITAG_T_1_MIN ) { + } else if (ra >= HITAG_T_1_MIN) { // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_0_MIN) { + } else if (ra >= HITAG_T_0_MIN) { // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -929,20 +920,20 @@ void SnoopHitag(uint32_t type) { } else { LED_C_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //DbpString("wierd1?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -953,7 +944,7 @@ void SnoopHitag(uint32_t type) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) if (tag_sof) { // Ignore bits that are transmitted during SOF @@ -971,9 +962,9 @@ void SnoopHitag(uint32_t type) { } // Check if frame was captured - if(rxlen > 0) { - frame_count++; - if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) { + if (rxlen > 0) { + // frame_count++; + if (!LogTraceHitag(rx, rxlen, response, 0, reader_frame)) { DbpString("Trace full"); break; } @@ -988,7 +979,7 @@ void SnoopHitag(uint32_t type) { } // Reset the received frame and response timing info - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); response = 0; reader_frame = false; lastbit = 1; @@ -1021,14 +1012,14 @@ void SnoopHitag(uint32_t type) { // DbpString("All done"); } -void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { - int frame_count; +void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { + // int frame_count; int response; int overflow; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t tx[HITAG_FRAME_LEN]; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t tx[HITAG_FRAME_LEN]; + size_t txlen = 0; bool bQuitTraceFull = false; bQuiet = false; @@ -1040,9 +1031,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { auth_table_len = 0; auth_table_pos = 0; - byte_t* auth_table; + uint8_t *auth_table; BigBuf_free(); - auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); + auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); DbpString("Starting Hitag2 simulation"); @@ -1051,16 +1042,16 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { if (tag_mem_supplied) { DbpString("Loading hitag2 memory..."); - memcpy((byte_t*)tag.sectors,data,48); + memcpy((uint8_t*)tag.sectors, data, 48); } uint32_t block = 0; - for (size_t i=0; i<12; i++) { - for (size_t j=0; j<4; j++) { + for (size_t i = 0; i < 12; i++) { + for (size_t j = 0; j < 4; j++) { block <<= 8; block |= tag.sectors[i][j]; } - Dbprintf("| %d | %08x |",i,block); + Dbprintf("| %d | %08x |", i, block); } // Set up simulator mode, frequency divisor which will drive the FPGA @@ -1068,7 +1059,6 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -1096,22 +1086,22 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; // Reset the received frame, frame count and timing info - memset(rx,0x00,sizeof(rx)); - frame_count = 0; + memset(rx, 0x00, sizeof(rx)); + // frame_count = 0; response = 0; overflow = 0; // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while(!BUTTON_PRESS()) { + while (!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; overflow = 0; @@ -1122,17 +1112,17 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { LED_B_ON(); // Capture reader frame - if(ra >= HITAG_T_STOP) { + if (ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if(ra >= HITAG_T_1_MIN ) { + } else if (ra >= HITAG_T_1_MIN) { // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_0_MIN) { + } else if (ra >= HITAG_T_0_MIN) { // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -1143,10 +1133,10 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } // Check if frame was captured - if(rxlen > 4) { - frame_count++; + if (rxlen > 4) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,true)) { + if (!LogTraceHitag(rx, rxlen, response, 0, true)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1160,22 +1150,22 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitag2_handle_reader_command(rx,rxlen,tx,&txlen); + hitag2_handle_reader_command(rx, rxlen, tx, &txlen); // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, // not that since the clock counts since the rising edge, but T_Wait1 is // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) // periods. The gap time T_Low varies (4..10). All timer values are in // terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); + while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); // Send and store the tag answer (if there is any) if (txlen) { // Transmit the tag frame - hitag_send_frame(tx,txlen); + hitag_send_frame(tx, txlen); // Store the frame in the trace if (!bQuiet) { - if (!LogTraceHitag(tx,txlen,0,0,false)) { + if (!LogTraceHitag(tx, txlen, 0, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1187,7 +1177,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } // Reset the received frame and response timing info - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); response = 0; // Enable and reset external trigger in timer for capturing future frames @@ -1211,14 +1201,14 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } -void ReaderHitag(hitag_function htf, hitag_data* htd) { - int frame_count; +void ReaderHitag(hitag_function htf, hitag_data *htd) { + // int frame_count; int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; int lastbit; bool bSkip; int reset_sof; @@ -1238,54 +1228,61 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //DbpString("Starting Hitag reader family"); // Check configuration - switch(htf) { - case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); - memcpy(password,htd->pwd.password,4); - blocknr = 0; - bQuitTraceFull = false; - bQuiet = false; - bPwd = false; - } break; - case RHT2F_AUTHENTICATE: { - DbpString("Authenticating using nr,ar pair:"); - memcpy(NrAr,htd->auth.NrAr,8); - Dbhexdump(8,NrAr,false); - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - case RHT2F_CRYPTO: - { - DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. - Dbhexdump(6,key,false); - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - case RHT2F_TEST_AUTH_ATTEMPTS: { - Dbprintf("Testing %d authentication attempts",(auth_table_len/8)); - auth_table_pos = 0; - memcpy(NrAr, auth_table, 8); - bQuitTraceFull = false; - bQuiet = false; - bCrypto = false; - } break; - case RHT2F_UID_ONLY: { - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case RHT2F_PASSWORD: { + Dbprintf("List identifier in password mode"); + memcpy(password, htd->pwd.password, 4); + blocknr = 0; + bQuitTraceFull = false; + bQuiet = false; + bPwd = false; + bAuthenticating = false; + } + break; + case RHT2F_AUTHENTICATE: { + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr, htd->auth.NrAr, 8); + Dbhexdump(8, NrAr, false); + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + case RHT2F_CRYPTO: + { + DbpString("Authenticating using key:"); + memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. + Dbhexdump(6, key, false); + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + case RHT2F_TEST_AUTH_ATTEMPTS: { + Dbprintf("Testing %d authentication attempts", (auth_table_len/8)); + auth_table_pos = 0; + memcpy(NrAr, auth_table, 8); + bQuitTraceFull = false; + bQuiet = false; + bCrypto = false; + } + break; + case RHT2F_UID_ONLY: { + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } LED_D_ON(); @@ -1301,14 +1298,10 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); @@ -1332,12 +1325,12 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; lastbit = 1; // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10){ + if (htf < 10) { // hitagS settings reset_sof = 1; t_wait = 200; @@ -1353,19 +1346,23 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { t_wait = HITAG_T_WAIT_2; //DbpString("Configured for hitag2 reader"); } else { - Dbprintf("Error, unknown hitag reader type: %d",htf); - return; + Dbprintf("Error, unknown hitag reader type: %d", htf); + goto out; } - uint8_t attempt_count=0; - while(!bStop && !BUTTON_PRESS()) { - // Watchdog hit + + // wait for tag to power up + // t_PowerUp = 312,5 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*(312-t_wait)); + + uint8_t attempt_count = 0; + while (!bStop && !BUTTON_PRESS()) { WDT_HIT(); // Check if frame was captured and store it - if(rxlen > 0) { - frame_count++; + if (rxlen > 0) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,false)) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1378,28 +1375,34 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // By default reset the transmission buffer tx = txbuf; - switch(htf) { + switch (htf) { case RHT2F_PASSWORD: { - bStop = !hitag2_password(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); + } + break; case RHT2F_AUTHENTICATE: { - bStop = !hitag2_authenticate(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen); + } + break; case RHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx,rxlen,tx,&txlen, false); - } break; + bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false); + } + break; case RHT2F_TEST_AUTH_ATTEMPTS: { - bStop = !hitag2_test_auth_attempts(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen); + } + break; case RHT2F_UID_ONLY: { bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen); attempt_count++; //attempt 3 times to get uid then quit - if (!bStop && attempt_count == 3) bStop = true; - } break; + if (!bStop && attempt_count == 3) + bStop = true; + } + break; default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + Dbprintf("Error, unknown function: %d", htf); + goto out; + } } // Send and store the reader command @@ -1411,22 +1414,22 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); //Dbprintf("DEBUG: Sending reader frame"); // Transmit the reader frame - hitag_reader_send_frame(tx,txlen); + hitag_reader_send_frame(tx, txlen); // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count - if(txlen > 0) { - frame_count++; + if (txlen > 0) { + // frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { + if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { if (bQuitTraceFull) { break; } else { @@ -1437,7 +1440,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } // Reset values for receiving frames - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; bSkip = true; @@ -1449,7 +1452,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -1459,14 +1462,14 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { LED_B_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //Dbprintf("DEBUG: Wierd1"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) //need to test to verify we don't exceed memory... @@ -1477,7 +1480,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) //need to test to verify we don't exceed memory... @@ -1493,7 +1496,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) //need to test to verify we don't exceed memory... @@ -1515,13 +1518,15 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } } //if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount >100) break; + if (errorCount > 100) break; // We can break this loop if we received the last bit from a frame if (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) { - if (rxlen>0) break; + if (rxlen > 0) break; } } } + +out: //Dbprintf("DEBUG: Done waiting for frame"); LED_B_OFF(); @@ -1532,20 +1537,19 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //Dbprintf("frame received: %d",frame_count); //DbpString("All done"); if (bSuccessful) - cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48); + cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); else - cmd_send(CMD_ACK,bSuccessful,0,0,0,0); - + cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); } -void WriterHitag(hitag_function htf, hitag_data* htd, int page) { - int frame_count; +void WriterHitag(hitag_function htf, hitag_data *htd, int page) { + // int frame_count; int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; int lastbit; bool bSkip; int reset_sof; @@ -1565,24 +1569,36 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { //DbpString("Starting Hitag reader family"); // Check configuration - switch(htf) { - case WHT2F_CRYPTO: - { - DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. - memcpy(writedata, htd->crypto.data, 4); - Dbhexdump(6,key,false); - blocknr = page; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - writestate = WRITE_STATE_START; - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case WHT2F_CRYPTO: { + DbpString("Authenticating using key:"); + memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. + memcpy(writedata, htd->crypto.data, 4); + Dbhexdump(6, key, false); + blocknr = page; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + writestate = WRITE_STATE_START; + } + break; + case WHT2F_PASSWORD: { + DbpString("Authenticating using password:"); + memcpy(password, htd->pwd.password, 4); + memcpy(writedata, htd->crypto.data, 4); + Dbhexdump(4, password, false); + blocknr = page; + bPwd = false; + bAuthenticating = false; + writestate = WRITE_STATE_START; + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } LED_D_ON(); @@ -1598,7 +1614,6 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); @@ -1629,13 +1644,13 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; lastbit = 1; bStop = false; // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10){ + if (htf < 10) { // hitagS settings reset_sof = 1; t_wait = 200; @@ -1651,18 +1666,18 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { t_wait = HITAG_T_WAIT_2; //DbpString("Configured for hitag2 reader"); } else { - Dbprintf("Error, unknown hitag reader type: %d",htf); + Dbprintf("Error, unknown hitag reader type: %d", htf); return; } - while(!bStop && !BUTTON_PRESS()) { - // Watchdog hit + while (!bStop && !BUTTON_PRESS()) { + WDT_HIT(); // Check if frame was captured and store it - if(rxlen > 0) { - frame_count++; + if (rxlen > 0) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,false)) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1675,14 +1690,20 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // By default reset the transmission buffer tx = txbuf; - switch(htf) { - case WHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx,rxlen,tx,&txlen, true); - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case WHT2F_CRYPTO: { + bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); + } + break; + case WHT2F_PASSWORD: { + bStop = !hitag2_password(rx, rxlen, tx, &txlen, true); + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } // Send and store the reader command @@ -1694,22 +1715,22 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); //Dbprintf("DEBUG: Sending reader frame"); // Transmit the reader frame - hitag_reader_send_frame(tx,txlen); + hitag_reader_send_frame(tx, txlen); - // Enable and reset external trigger in timer for capturing future frames + // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count - if(txlen > 0) { - frame_count++; + if (txlen > 0) { + // frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { + if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { if (bQuitTraceFull) { break; } else { @@ -1720,7 +1741,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } // Reset values for receiving frames - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; bSkip = true; @@ -1732,7 +1753,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -1742,31 +1763,31 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { LED_B_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //Dbprintf("DEBUG: Wierd1"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; // We have to skip this half period at start and add the 'one' the second time @@ -1776,13 +1797,13 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } if (tag_sof) { // Ignore bits that are transmitted during SOF tag_sof--; @@ -1792,24 +1813,23 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { rxlen++; } } else { - //Dbprintf("DEBUG: Wierd2"); + // Dbprintf("DEBUG: Wierd2"); errorCount++; - // Ignore wierd value, is to small to mean anything + // Ignore wierd value, it is too small to mean anything } } - //if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount >100) break; + // if we saw over 100 wierd values break it probably isn't hitag... + if (errorCount > 100) break; // We can break this loop if we received the last bit from a frame if (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) { - if (rxlen>0) break; + if (rxlen > 0) break; } } // Wait some extra time for flash to be programmed - if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) - { + if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_PROG - HITAG_T_WAIT_MAX)); + while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_PROG - HITAG_T_WAIT_MAX)); } } //Dbprintf("DEBUG: Done waiting for frame"); @@ -1821,5 +1841,5 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); //Dbprintf("frame received: %d",frame_count); //DbpString("All done"); - cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48); + cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); } diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h index 555f04ee..3883c17b 100644 --- a/armsrc/hitag2.h +++ b/armsrc/hitag2.h @@ -16,9 +16,9 @@ #include #include "hitag.h" -void SnoopHitag(uint32_t type); -void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); -void ReaderHitag(hitag_function htf, hitag_data* htd); -void WriterHitag(hitag_function htf, hitag_data* htd, int page); +extern void SnoopHitag(uint32_t type); +extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); +extern void ReaderHitag(hitag_function htf, hitag_data* htd); +extern void WriterHitag(hitag_function htf, hitag_data* htd, int page); #endif diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 9e8f1432..5da170bb 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -26,18 +26,6 @@ #define CRC_PRESET 0xFF #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 bSuccessful; static struct hitagS_tag tag; @@ -57,17 +45,17 @@ size_t blocknr; bool end=false; // 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)) -static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +#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 uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 +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_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 uf20bs u32 +#define uf20bs uint32_t -static u32 f20(const u64 x) { - u32 i5; +static uint32_t f20(const uint64_t x) { + uint32_t i5; i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 + ((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; } -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 >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8) @@ -89,20 +88,12 @@ static u64 hitag2_round(u64 *state) { *state = x; return f20(x); } -static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) { - u32 i; - u64 x = ((key & 0xFFFF) << 32) + serial; - 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; + +static uint32_t hitag2_byte(uint64_t *x) { + uint32_t i, c; 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; } @@ -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 page; int i; - u64 state; + uint64_t state; unsigned char crc; // 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 Dbprintf("Challenge for UID: %X", temp_uid); temp2++; - state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]), - rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); + state = hitag2_init(REV64(tag.key), REV32(tag.pages[0][0]), + REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); Dbprintf( ",{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]); @@ -1216,7 +1207,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr unsigned char uid[32]; byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00; unsigned char crc; - u64 state; + uint64_t state; byte_t auth_ks[4]; byte_t conf_pages[3]; 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; if(end!=true){ 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("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); - Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); + Dbprintf("key: %02X %02X\n\n", key, REV64(key)); + Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, REV32(tag.uid)); + Dbprintf("rnd: %02X %02X\n\n", rnd, REV32(rnd)); */ for (i = 0; i < 4; i++) { 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; pwdl1=0; 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++) { hitag2_byte(&state); } diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 8fe502ca..bed2f076 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -15,13 +15,23 @@ #include "mifarecmd.h" +#include + +#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 "parity.h" #include "crc.h" #include "fpgaloader.h" -#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_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 /* // 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) { 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; }; 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; }; 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; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -99,7 +109,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); LED_B_ON(); 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; if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { 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)) { 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++) { if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { isOK = 0; - if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); break; } } if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); } // ----------------------------- crypto1 destroy @@ -393,22 +403,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) while (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; }; 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; }; 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; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -419,7 +429,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); LED_B_ON(); 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 (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(0); - return; }; + return; }; if(mifare_ultra_halt()) { 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 iso14a_card_select_t card_info; 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; } switch (card_info.uidlen) { @@ -684,7 +694,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, have_uid = true; } else { // no need for anticollision. We can directly select the card 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; } } @@ -696,14 +706,14 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint32_t nt1; 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; } // nested authentication uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL); 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; } @@ -712,7 +722,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, ReaderTransmit(dummy_answer, 1, NULL); timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT; - + num_nonces++; if (num_nonces % 2) { memcpy(buf+i, receivedAnswer, 4); @@ -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)); LED_B_OFF(); - if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); + if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); if (field_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; #define NESTED_MAX_TRIES 12 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(); 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. if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); rtr--; continue; } 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--; continue; }; auth1_time = 0; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); rtr--; continue; }; @@ -836,12 +846,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat auth2_time = 0; } if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); rtr--; continue; }; - nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 + nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 101; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); if (nttmp == nt2) break; @@ -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); } else { 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; } } @@ -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. if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); continue; } 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; }; auth1_time = 0; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); 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; len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; }; @@ -925,7 +935,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat ks1 = nt2 ^ nttest; 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); target_nt[i] = 0; 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)); LED_B_OFF(); - if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); + if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -996,7 +1006,7 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) if (set14aTimeout){ iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe } - + if (multisectorCheck) { TKeyIndex keyIndex = {{0}}; uint8_t sectorCnt = blockNo; @@ -1026,6 +1036,60 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) 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 // @@ -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)) { 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++) { @@ -1101,13 +1165,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (sectorNo == 0){ if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); break; } } else { if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); 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++) { if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); break; }; if (isOK) { if (blockNo < NumBlocksPerSector(sectorNo) - 1) { emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); - } else { // sector trailer, keep the keys, set only the AC + } else { // sector trailer, keep the keys, set only the AC emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); @@ -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 (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); }; // ----------------------------- crypto1 destroy @@ -1173,20 +1237,20 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ bool needWipe = cmdParams & 0x01; bool needFill = cmdParams & 0x02; bool gen1b = cmdParams & 0x04; - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; uint8_t block1[16] = {0x00}; uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t d_block[18] = {0x00}; - + // card commands uint8_t wupC1[] = { 0x40 }; uint8_t wupC2[] = { 0x43 }; uint8_t wipeC[] = { 0x41 }; - + // iso14443 setup LED_A_ON(); LED_B_OFF(); @@ -1196,54 +1260,54 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ // tracing clear_trace(); set_tracing(true); - + while (true){ // wipe if (needWipe){ ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; if(mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); }; }; - + // put default data if (needFill){ // select commands 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) - if (!gen1b) { + // 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(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } // send blocks command for (int blockNo = 0; blockNo < numBlocks; blockNo++) { - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + 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"); break; }; - + // check type of block and add crc if (!isBlockTrailer(blockNo)){ memcpy(d_block, block1, 16); @@ -1257,33 +1321,33 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ // send write command ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; }; } - + // halt - // do no issue halt command for gen1b + // do no issue halt command for gen1b if (!gen1b) { if (mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); break; } } } break; - } + } // send USB response LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,NULL,0); LED_B_OFF(); - + // reset fpga FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - + return; } @@ -1330,13 +1394,13 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // get UID from chip if (workFlags & 0x01) { 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. //break; }; 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. // 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 if (needWipe && !(workFlags & 0x40)){ ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; 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. - // break; + // break; }; }; @@ -1368,24 +1432,24 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (workFlags & 0x02) { 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(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + 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"); break; }; @@ -1393,8 +1457,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai AppendCrc14443a(d_block, 16); ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); 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) if (!(workFlags & 0x40)) { 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. // break; } @@ -1461,15 +1525,15 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai while (true) { if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; // do no issue for gen1b magic tag if (!(workFlags & 0x40)) { ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } @@ -1477,7 +1541,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // read block 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; }; 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) if (!(workFlags & 0x40)) { 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. - // break; + // break; } } } @@ -1523,34 +1587,34 @@ void MifareCIdent(){ uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - set_tracing(true); + set_tracing(true); ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { isOK = 2; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { isOK = 1; }; }; // From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it. mifare_classic_halt(NULL, 0); - + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LEDsoff(); } // @@ -1580,7 +1644,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ } 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){ diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index e17fa998..c16c3a3e 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -10,18 +10,36 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#ifndef __MIFARECMD_H -#define __MIFARECMD_H +#ifndef MIFARECMD_H__ +#define MIFARECMD_H__ -#include "proxmark3.h" -#include "apps.h" -#include "util.h" +#include -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" +extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); +extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); +extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain); +extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); +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 \ No newline at end of file +#endif diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 647305e8..fe5a7485 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -22,6 +22,7 @@ #include "iso14443a.h" #include "crapto1/crapto1.h" #include "mbedtls/des.h" +#include "protocols.h" 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]; // 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 (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]; // 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 (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -282,7 +283,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ if (MF_DBGLEVEL >= MF_DBG_EXTENDED) 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); if (len != 4) { 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}; // 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 (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[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(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 (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); return 0; @@ -421,7 +422,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) int result = 0; 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 (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); 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]; // 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 (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 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 (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 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 (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("halt error. response len: %x", len); @@ -579,7 +580,7 @@ int mifare_ultra_halt() uint8_t receivedAnswer[MAX_MIFARE_FRAME_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 (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("halt error. response len: %x", len); diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index e3bac386..147f6fb8 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -152,8 +152,14 @@ bool IsBlock0PCF7931(uint8_t *block) { bool IsBlock1PCF7931(uint8_t *block) { // 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[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 false; @@ -192,6 +198,7 @@ void ReadPCF7931() { Dbprintf("Error, no tag or bad tag"); return; } + // exit if too many errors during reading if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); @@ -201,9 +208,11 @@ void ReadPCF7931() { // our logic breaks if we don't get at least two blocks 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)) continue; + // add block to single blocks list if (single_blocks_cnt < max_blocks) { for (i = 0; i < single_blocks_cnt; ++i) { if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) { @@ -213,6 +222,7 @@ void ReadPCF7931() { } if (j != 1) { memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16); + print_result("got single block", single_blocks[single_blocks_cnt], 16); single_blocks_cnt++; } 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); + for (i = 0; i < n; ++i) + { + print_result("got consecutive blocks", tmp_blocks[i], 16); + } i = 0; if(!found_0_1) { @@ -284,7 +298,7 @@ void ReadPCF7931() { goto end; } } - while (found_blocks != max_blocks); + while (found_blocks < max_blocks); end: Dbprintf("-----------------------------------------"); diff --git a/armsrc/util.h b/armsrc/util.h index da333e01..7b3d0849 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -17,15 +17,21 @@ #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) -#define LED_RED 1 +#define LED_RED 1 #define LED_ORANGE 2 -#define LED_GREEN 4 -#define LED_RED2 8 -#define BUTTON_HOLD 1 -#define BUTTON_NO_CLICK 0 -#define BUTTON_SINGLE_CLICK -1 -#define BUTTON_DOUBLE_CLICK -2 -#define BUTTON_ERROR -99 +#define LED_GREEN 4 +#define LED_RED2 8 + +#define BUTTON_HOLD 1 +#define BUTTON_NO_CLICK 0 +#define BUTTON_SINGLE_CLICK -1 +#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); size_t nbytes(size_t nbits); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c38e276e..9ecf99fb 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,6 +34,7 @@ #include "mifare/mad.h" #include "mifare/ndef.h" #include "emv/dump.h" +#include "protocols.h" #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("--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 + 10, bldata, 16); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; 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)); - UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -167,7 +168,7 @@ int CmdHF14AMfRdBl(const char *Cmd) return 2; } - return 0; + return 0; } int CmdHF14AMfRdSc(const char *Cmd) @@ -233,7 +234,7 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("Command execute timeout"); } - return 0; + return 0; } uint8_t FirstBlockOfSector(uint8_t sectorNo) @@ -1086,7 +1087,7 @@ int CmdHF14AMfChk(const char *Cmd) bool createDumpFile = 0; bool singleBlock = false; // Flag to ID if a single or multi key check uint8_t keyFoundCount = 0; // Counter to display the number of keys found/transfered to emulator - + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1132,7 +1133,7 @@ int CmdHF14AMfChk(const char *Cmd) return 1; }; } - + parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); if (singleBlock & createDumpFile) { @@ -1244,7 +1245,7 @@ int CmdHF14AMfChk(const char *Cmd) uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; // !SingleKey, so all key check (if SectorsCnt > 0) - if (!singleBlock) { + if (!singleBlock) { PrintAndLog("To cancel this operation press the button on the proxmark..."); printf("--"); for (uint32_t c = 0; c < keycnt; c += max_keys) { @@ -1265,7 +1266,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Command execute timeout"); } } - } else { + } else { int keyAB = keyType; do { for (uint32_t c = 0; c < keycnt; c += max_keys) { @@ -1275,16 +1276,16 @@ int CmdHF14AMfChk(const char *Cmd) clearTraceLog = false; if (res != 1) { - if (!res) { + if (!res) { // Use the common format below // PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64); foundAKey = true; - + // Store the Single Key for display list // For a single block check, SectorsCnt = Sector that contains the block - e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found - e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data - + e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found + e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data + } } else { PrintAndLog("Command execute timeout"); @@ -1327,7 +1328,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint16_t t = 0; t < 2; t++) { if (e_sector[sectorNo].foundKey[t]) { 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); @@ -1355,7 +1356,7 @@ int CmdHF14AMfChk(const char *Cmd) fclose(fkeys); PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys."); } - + free(e_sector); free(keyBlock); PrintAndLog(""); @@ -1710,10 +1711,10 @@ int CmdHF14AMfDbg(const char *Cmd) return 0; } - UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; - SendCommand(&c); + UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; + SendCommand(&c); - return 0; + return 0; } int CmdHF14AMfEGet(const char *Cmd) @@ -1736,7 +1737,7 @@ int CmdHF14AMfEGet(const char *Cmd) PrintAndLog("Command execute timeout"); } - return 0; + return 0; } int CmdHF14AMfEClear(const char *Cmd) @@ -1747,9 +1748,9 @@ int CmdHF14AMfEClear(const char *Cmd) return 0; } - UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; + SendCommand(&c); + return 0; } @@ -1956,7 +1957,7 @@ int CmdHF14AMfESave(const char *Cmd) PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename); - return 0; + return 0; } @@ -2026,7 +2027,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) case '\0': numSectors = 16; break; case '2' : numSectors = 32; break; case '4' : numSectors = 40; break; - case 'd' : + case 'd' : case 'D' : createDumpFile = true; break; } cmdp++; @@ -3009,51 +3010,130 @@ int CmdHFMFNDEF(const char *cmd) { 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"}, - {NULL, NULL, 0, NULL} +int CmdHFMFPersonalize(const char *cmd) { + + CLIParserInit("hf mf personalize", + "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.", + "Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n" + "\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n" + "\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0("tT", "keytype", "", "key type (A or B) to authenticate sector 0 (default: A)"), + arg_str0("kK", "key", "", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"), + arg_str1(NULL, NULL, "", "Personalization Option"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + char keytypestr[2] = "A"; + uint8_t keytype = 0x00; + int keytypestr_len; + int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len); + if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'A' && keytypestr[0] != 'b' && keytypestr[0] != 'B')) { + PrintAndLog("ERROR: not a valid key type. Key type must be A or B"); + CLIParserFree(); + return 1; + } + if (keytypestr[0] == 'B' || keytypestr[0] == 'b') { + keytype = 0x01; + } + + uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + 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); CmdsParse(CommandTable, Cmd); return 0; } -int CmdHelp(const char *Cmd) -{ - CmdsHelp(CommandTable); - return 0; + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; } diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index cd23f88c..be807222 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -22,15 +22,13 @@ #include "hitag.h" #include "cmdmain.h" -static int CmdHelp(const char *Cmd); - -size_t nbytes(size_t nbits) { - return (nbits/8)+((nbits%8)>0); +static size_t nbytes(size_t nbits) { + return (nbits/8) + ((nbits%8)>0); } -int CmdLFHitagList(const char *Cmd) -{ - uint8_t *got = malloc(USB_CMD_DATA_SIZE); + +static int CmdLFHitagList(const char *Cmd) { + uint8_t *got = malloc(USB_CMD_DATA_SIZE); // Query for the actual size of the trace UsbCommand response; GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); @@ -45,7 +43,7 @@ int CmdLFHitagList(const char *Cmd) got = p; GetFromBigBuf(got, traceLen, 0, NULL, -1, false); } - + PrintAndLog("recorded activity (TraceLen = %d bytes):"); PrintAndLog(" ETU :nbits: who bytes"); PrintAndLog("---------+-----+----+-----------"); @@ -57,11 +55,11 @@ int CmdLFHitagList(const char *Cmd) char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf = NULL; - - if (len > FILE_PATH_SIZE) + + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"wb")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -71,7 +69,7 @@ int CmdLFHitagList(const char *Cmd) } for (;;) { - + if(i > traceLen) { break; } bool isResponse; @@ -95,7 +93,7 @@ int CmdLFHitagList(const char *Cmd) int len = nbytes(bits); if (len > 100) { - break; + break; } if (i + len > traceLen) { break;} @@ -104,7 +102,7 @@ int CmdLFHitagList(const char *Cmd) int fillupBits = 8 - (bits % 8); byte_t framefilled[bits+fillupBits]; byte_t* ff = framefilled; - + int response_bit[200] = {0}; int z = 0; for (int y = 0; y < len; y++) { @@ -133,12 +131,12 @@ int CmdLFHitagList(const char *Cmd) char line[1000] = ""; for (j = 0; j < len; j++) { - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } + //if((parityBits >> (len - j - 1)) & 0x01) { + if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { + sprintf(line+(j*4), "%02x! ", frame[j]); + } else { + sprintf(line+(j*4), "%02x ", frame[j]); + } } PrintAndLog(" +%7d: %3d: %s %s", @@ -154,11 +152,11 @@ int CmdLFHitagList(const char *Cmd) (isResponse ? "TAG" : " "), line); } - + prev = timestamp; i += (len + 9); } - + if (pf) { fclose(pf); PrintAndLog("Recorded activity succesfully written to file: %s", filename); @@ -168,22 +166,24 @@ int CmdLFHitagList(const char *Cmd) return 0; } -int CmdLFHitagSnoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_HITAG}; - SendCommand(&c); - return 0; + +static int CmdLFHitagSnoop(const char *Cmd) { + UsbCommand c = {CMD_SNOOP_HITAG}; + 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 }; FILE* pf; bool tag_mem_supplied; int len = strlen(Cmd); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -199,56 +199,114 @@ int CmdLFHitagSim(const char *Cmd) { } else { tag_mem_supplied = false; } - + // Does the tag comes with memory c.arg[0] = (uint32_t)tag_mem_supplied; - SendCommand(&c); - return 0; + SendCommand(&c); + 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) { - 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_function htf = param_get32ex(Cmd,0,0,10); - + hitag_function htf = param_get32ex(Cmd, 0, 0, 10); + switch (htf) { case 01: { //RHTSF_CHALLENGE 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,2,0,16),4,htd->auth.NrAr+4); - c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode + 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); + c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode } break; case 02: { //RHTSF_KEY c = (UsbCommand){ CMD_READ_HITAG_S }; - 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[2] = param_get64ex(Cmd,3,0,0); //tag mode + 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[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode } break; case 03: { //RHTSF_CHALLENGE BLOCK 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,2,0,16),4,htd->auth.NrAr+4); - c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode + 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); + c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode } break; case 04: { //RHTSF_KEY BLOCK c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; - 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[2] = param_get64ex(Cmd,3,0,0); //tag mode + 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[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode } break; 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; case RHT2F_AUTHENTICATE: { - 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, 1, 0, 16), 4, htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4); } break; case RHT2F_CRYPTO: { - 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_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key); + // num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); } break; case RHT2F_TEST_AUTH_ATTEMPTS: { // No additional parameters needed @@ -261,19 +319,20 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog(""); PrintAndLog("Usage: hitag reader "); PrintAndLog("Reader Functions:"); - PrintAndLog(" HitagS (0*)"); - PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); - PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); - PrintAndLog(" 03 (Challenge) read all blocks from a Hitag S tag"); - PrintAndLog(" 04 (set to 0 if no authentication is needed) read all blocks from a Hitag S tag"); - PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); - PrintAndLog(" Hitag1 (1*)"); - PrintAndLog(" Hitag2 (2*)"); - PrintAndLog(" 21 (password mode)"); - PrintAndLog(" 22 (authentication)"); - PrintAndLog(" 23 (authentication) key is in format: ISK high + ISK low"); - PrintAndLog(" 25 (test recorded authentications)"); - PrintAndLog(" 26 just read UID"); + PrintAndLog(" HitagS (0*):"); + PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); + PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); + PrintAndLog(" 03 (Challenge) read all blocks from a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) read all blocks from a Hitag S tag"); + PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); + PrintAndLog(" Hitag1 (1*):"); + PrintAndLog(" (not yet implemented)"); + PrintAndLog(" Hitag2 (2*):"); + PrintAndLog(" 21 (password mode)"); + PrintAndLog(" 22 (authentication)"); + PrintAndLog(" 23 (authentication) key is in format: ISK high + ISK low"); + PrintAndLog(" 25 (test recorded authentications)"); + PrintAndLog(" 26 just read UID"); return 1; } break; } @@ -286,13 +345,19 @@ int CmdLFHitagReader(const char *Cmd) { SendCommand(&c); 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 - 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); - + if (htf == RHT2F_UID_ONLY){ PrintAndLog("Valid Hitag2 tag found - UID: %08x",id); } else { @@ -312,12 +377,11 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog("Succesfully saved tag memory to [%s]",filename); } - return 0; } -int CmdLFHitagSimS(const char *Cmd) { +static int CmdLFHitagSimS(const char *Cmd) { UsbCommand c = { CMD_SIMULATE_HITAG_S }; char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; @@ -350,7 +414,8 @@ int CmdLFHitagSimS(const char *Cmd) { return 0; } -int CmdLFHitagCheckChallenges(const char *Cmd) { + +static int CmdLFHitagCheckChallenges(const char *Cmd) { UsbCommand c = { CMD_TEST_HITAGS_TRACES }; char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; @@ -358,7 +423,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { int len = strlen(Cmd); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -369,87 +434,101 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { PrintAndLog("Error: File reading error"); fclose(pf); return 1; - } + } fclose(pf); } else { file_given = false; } - + //file with all the challenges to try c.arg[0] = (uint32_t)file_given; c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode - SendCommand(&c); - return 0; + SendCommand(&c); + return 0; } -int CmdLFHitagWP(const char *Cmd) { +static int CmdLFHitagWriter(const char *Cmd) { UsbCommand c = { CMD_WR_HITAG_S }; hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_function htf = param_get32ex(Cmd,0,0,10); switch (htf) { - case 03: { //WHTSF_CHALLENGE + case WHTSF_CHALLENGE: { num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr); c.arg[2]= param_get32ex(Cmd, 2, 0, 10); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data); } break; - case 04: - case 24: - { //WHTSF_KEY + case WHTSF_KEY: + case WHT2F_CRYPTO: { num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); c.arg[2]= param_get32ex(Cmd, 2, 0, 10); 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; default: { PrintAndLog("Error: unkown writer function %d",htf); PrintAndLog("Hitag writer functions"); - PrintAndLog(" HitagS (0*)"); - PrintAndLog(" 03 (Challenge) write page on a Hitag S tag"); - PrintAndLog(" 04 (set to 0 if no authentication is needed) write page on a Hitag S tag"); - PrintAndLog(" Hitag1 (1*)"); - PrintAndLog(" Hitag2 (2*)"); - PrintAndLog(" 24 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" HitagS (0*):"); + PrintAndLog(" 03 (Challenge) write page on a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" Hitag1 (1*)"); + PrintAndLog(" (not yet implemented)"); + PrintAndLog(" Hitag2 (2*):"); + PrintAndLog(" 24 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" 27 write page on a Hitag2 tag"); return 1; } break; } // Copy the hitag function into the first argument c.arg[0] = htf; - // Send the command to the proxmark - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - - // Check the return status, stored in the first argument - if (resp.arg[0] == false) return 1; - return 0; + // Send the command to the proxmark + SendCommand(&c); + + UsbCommand 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 + if (resp.arg[0] == false) { + PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed"); + return 1; + } + return 0; } -static command_t CommandTable[] = +static int CmdHelp(const char *Cmd); + +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdLFHitagList, 1, " List Hitag trace history"}, - {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, - {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, - {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, - {"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, - {"simS", CmdLFHitagSimS, 1, " Simulate HitagS transponder" }, - {"checkChallenges", CmdLFHitagCheckChallenges, 1, " test all challenges" }, { - NULL,NULL, 0, NULL } + {"help", CmdHelp, 1, "This help"}, + {"list", CmdLFHitagList, 0, " List Hitag trace history"}, + {"info", CmdLFHitagInfo, 0, "Tag information" }, + {"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"}, + {"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"}, + {"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"}, + {"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" }, + {"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" }, + {"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" }, + { NULL, NULL, 0, NULL } }; -int CmdLFHitag(const char *Cmd) -{ - CmdsParse(CommandTable, Cmd); - return 0; + +static int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) -{ - CmdsHelp(CommandTable); - return 0; + +int CmdLFHitag(const char *Cmd) { + CmdsParse(CommandTable, Cmd); + return 0; } diff --git a/client/cmdlfhitag.h b/client/cmdlfhitag.h index 22b6bb06..062ed484 100644 --- a/client/cmdlfhitag.h +++ b/client/cmdlfhitag.h @@ -11,11 +11,7 @@ #ifndef CMDLFHITAG_H__ #define CMDLFHITAG_H__ -int CmdLFHitag(const char *Cmd); - -int CmdLFHitagList(const char *Cmd); -int CmdLFHitagSnoop(const char *Cmd); -int CmdLFHitagSim(const char *Cmd); -int CmdLFHitagReader(const char *Cmd); +extern int CmdLFHitag(const char *Cmd); +extern int CmdLFHitagReader(const char *Cmd); #endif diff --git a/client/util.c b/client/util.c index cd18fc00..7e230488 100644 --- a/client/util.c +++ b/client/util.c @@ -26,7 +26,7 @@ #ifndef _WIN32 #include -#include +#include #include int ukbhit(void) @@ -42,11 +42,11 @@ int ukbhit(void) Ntty.c_oflag = 0x0000; // output mode 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[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 - error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe - error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes + error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe + error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes } return ( error == 0 ? cnt : -1 ); @@ -78,13 +78,13 @@ int ukbhit(void) { // log files functions void AddLogLine(char *file, char *extData, char *c) { FILE *fLog = NULL; - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + + len = strlen(file); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, file, len); - len = strlen(file); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, file, len); - fLog = fopen(filename, "a"); if (!fLog) { printf("Could not append log file %s", filename); @@ -119,10 +119,10 @@ void AddLogCurrentDT(char *fileName) { void FillFileNameByUID(char *fileName, uint8_t *uid, char *ext, int byteCount) { char * fnameptr = fileName; - + for (int j = 0; j < byteCount; j++, fnameptr += 2) - sprintf(fnameptr, "%02x", (unsigned int) uid[j]); - sprintf(fnameptr, "%s", ext); + sprintf(fnameptr, "%02x", (unsigned int) uid[j]); + sprintf(fnameptr, "%s", ext); } // fill buffer from structure [{uint8_t data, size_t length},...] @@ -130,25 +130,25 @@ int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...) { *dataLength = 0; va_list valist; va_start(valist, dataLength); - + uint8_t *vdata = NULL; size_t vlength = 0; do{ vdata = va_arg(valist, uint8_t *); if (!vdata) break; - + vlength = va_arg(valist, size_t); if (*dataLength + vlength > maxDataLength) { va_end(valist); return 1; } - + memcpy(&data[*dataLength], vdata, vlength); *dataLength += vlength; - + } while (vdata); - + va_end(valist); return 0; @@ -161,13 +161,13 @@ bool CheckStringIsHEXValue(const char *value) { if (strlen(value) % 2) return false; - + return true; } -void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, +void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase) { - + char *tmp = (char *)buf; size_t i; memset(tmp, 0x00, hex_max_len); @@ -175,17 +175,17 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex int maxLen = ( hex_len > hex_max_len) ? hex_max_len : hex_len; for (i = 0; i < maxLen; ++i, tmp += 2 + spaces_between) { - sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); - + sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); + for (int j = 0; j < spaces_between; j++) sprintf(tmp + 2 + j, " "); } - + i *= (2 + spaces_between); int minStrLen = min_str_len > i ? min_str_len : 0; if (minStrLen > hex_max_len) minStrLen = hex_max_len; - for(; i < minStrLen; i++, tmp += 1) + for(; i < minStrLen; i++, tmp += 1) sprintf(tmp, " "); return; @@ -195,7 +195,7 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex char *sprint_hex(const uint8_t *data, const size_t len) { static char buf[4097] = {0}; - + hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, false); return buf; @@ -259,16 +259,16 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st tmp[i] = ((c < 32) || (c == 127)) ? '.' : c; ++i; } - + int minStrLen = min_str_len > i ? min_str_len : 0; - for(; i < minStrLen; ++i) + for(; i < minStrLen; ++i) tmp[i] = ' '; - + return buf; } 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) @@ -290,7 +290,7 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) 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--) { dest[len] = 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 char *printBits(size_t const size, void const * const ptr) { - unsigned char *b = (unsigned char*) ptr; - unsigned char byte; + unsigned char *b = (unsigned char*) ptr; + unsigned char byte; static char buf[1024]; char *tmp = buf; - int i, j; - - for (i=size-1;i>=0;i--) - { - for (j=7;j>=0;j--) - { - byte = b[i] & (1<>= j; - sprintf(tmp, "%u", (unsigned int)byte); + int i, j; + + for (i=size-1;i>=0;i--) + { + for (j=7;j>=0;j--) + { + byte = b[i] & (1<>= j; + sprintf(tmp, "%u", (unsigned int)byte); tmp++; - } - } + } + } return buf; } @@ -382,10 +382,10 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) { int i; int len = strlen(line); - + *bg = 0; *en = 0; - + // skip spaces while (line[*bg] ==' ' || line[*bg]=='\t') (*bg)++; if (*bg >= len) { @@ -395,13 +395,13 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) for (i = 0; i < paramnum; i++) { while (line[*bg]!=' ' && line[*bg]!='\t' && line[*bg] != '\0') (*bg)++; while (line[*bg]==' ' || line[*bg]=='\t') (*bg)++; - + if (line[*bg] == '\0') return 1; } - + *en = *bg; while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0') (*en)++; - + (*en)--; return 0; @@ -411,7 +411,7 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) int param_getlength(const char *line, int paramnum) { int bg, en; - + if (param_getptr(line, &bg, &en, paramnum)) return 0; return en - bg + 1; @@ -423,12 +423,12 @@ char param_getchar(const char *line, int paramnum) { char param_getchar_indx(const char *line, int indx, int paramnum) { int bg, en; - + if (param_getptr(line, &bg, &en, paramnum)) return 0x00; if (bg + indx > en) return '\0'; - + return line[bg + indx]; } @@ -461,7 +461,7 @@ uint8_t param_isdec(const char *line, int paramnum) int bg, en; //TODO, check more thorougly 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; } @@ -470,7 +470,7 @@ uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoul(&line[bg], NULL, base) & 0xff; else return deflt; @@ -480,7 +480,7 @@ uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoul(&line[bg], NULL, base); else return deflt; @@ -490,30 +490,30 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoull(&line[bg], NULL, base); else 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; if (hexcnt % 2) return 1; - + if (param_getptr(line, &bg, &en, paramnum)) return 1; - if (en - bg + 1 != hexcnt) + if (en - bg + 1 != hexcnt) return 1; 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); data[i / 2] = temp & 0xff; - } + } return 0; } @@ -523,22 +523,22 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) int bg, en, temp, i; //if (hexcnt % 2) - // return 1; - + // return 1; + if (param_getptr(line, &bg, &en, paramnum)) return 1; if (en - bg + 1 > *hexcnt) return 1; - + *hexcnt = en - bg + 1; if (*hexcnt % 2) //error if not complete hex bytes return 1; 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); data[i / 2] = temp & 0xff; - } + } return 0; } @@ -551,21 +551,21 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxd if (param_getptr(line, &bg, &en, paramnum)) return 1; *datalen = 0; - + int indx = bg; while (line[indx]) { if (line[indx] == '\t' || line[indx] == ' ') { indx++; continue; } - + if (isxdigit((unsigned char)line[indx])) { buf[strlen(buf) + 1] = 0x00; buf[strlen(buf)] = line[indx]; } else { // if we have symbols other than spaces and hex return 1; - } + } if (*datalen >= maxdatalen) { // if we dont have space in buffer and have symbols to translate @@ -578,14 +578,14 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxd *buf = 0; (*datalen)++; } - + indx++; } - if (strlen(buf) > 0) + if (strlen(buf) > 0) //error when not completed hex bytes return 3; - + return 0; } @@ -593,7 +593,7 @@ int param_getstr(const char *line, int paramnum, char * str, size_t buffersize) { int bg, en; - if (param_getptr(line, &bg, &en, paramnum)) { + if (param_getptr(line, &bg, &en, paramnum)) { return 0; } @@ -602,10 +602,10 @@ int param_getstr(const char *line, int paramnum, char * str, size_t buffersize) printf("out of bounds error: want %d bytes have %zd bytes\n", en - bg + 1 + 1, buffersize); return 0; } - + memcpy(str, line + bg, en - bg + 1); str[en - bg + 1] = 0; - + return en - bg + 1; } @@ -618,100 +618,100 @@ https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/ // returns number of bits converted int hextobinarray(char *target, char *source) { - int length, i, count= 0; - char* start = source; - char x; - - length = strlen(source); - // process 4 bits (1 hex digit) at a time - while(length--) - { - x= *(source++); - // capitalize - if (x >= 'a' && x <= 'f') - x -= 32; - // convert to numeric value - if (x >= '0' && x <= '9') - x -= '0'; - else if (x >= 'A' && x <= 'F') - x -= 'A' - 10; - else { - printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start); - return 0; - } - // output - for(i= 0 ; i < 4 ; ++i, ++count) - *(target++)= (x >> (3 - i)) & 1; - } - - return count; + int length, i, count= 0; + char* start = source; + char x; + + length = strlen(source); + // process 4 bits (1 hex digit) at a time + while(length--) + { + x= *(source++); + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else { + printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start); + return 0; + } + // output + for(i= 0 ; i < 4 ; ++i, ++count) + *(target++)= (x >> (3 - i)) & 1; + } + + return count; } // 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 int binarraytohex(char *target,char *source, int length) { - unsigned char i, x; - int j = length; + unsigned char i, x; + int j = length; - if(j % 4) - return 0; + if(j % 4) + return 0; - while(j) - { - for(i= x= 0 ; i < 4 ; ++i) - x += ( source[i] << (3 - i)); - sprintf(target,"%X", (unsigned int)x); - ++target; - source += 4; - j -= 4; - } - return length; + while(j) + { + for(i= x= 0 ; i < 4 ; ++i) + x += ( source[i] << (3 - i)); + sprintf(target,"%X", (unsigned int)x); + ++target; + source += 4; + j -= 4; + } + return length; } // return parity bit required to match type uint8_t GetParity( uint8_t *bits, uint8_t type, int length) { - int x; + int x; - for(x= 0 ; length > 0 ; --length) - x += bits[length - 1]; - x %= 2; + for(x= 0 ; length > 0 ; --length) + x += bits[length - 1]; + 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 void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length) { - *(target++)= GetParity(source, EVEN, length / 2); - memcpy(target, source, length); - target += length; - *(target)= GetParity(source + length / 2, ODD, length / 2); + *(target++)= GetParity(source, EVEN, length / 2); + memcpy(target, source, length); + target += length; + *(target)= GetParity(source + length / 2, ODD, length / 2); } // 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) { for( ; len > 0; len--,dst++,src++) - *dst ^= *src; + *dst ^= *src; } // RotateLeft - Ultralight, Desfire, works on byte level // 00-01-02 >> 01-02-00 void rol(uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; } // Replace unprintable characters with a dot in char buffer void clean_ascii(unsigned char *buf, size_t len) { for (size_t i = 0; i < len; i++) { - if (!isprint(buf[i])) - buf[i] = '.'; + if (!isprint(buf[i])) + buf[i] = '.'; } } @@ -724,8 +724,8 @@ void strcleanrn(char *buf, size_t len) { // replace char in buffer void strcreplace(char *buf, size_t len, char from, char to) { for (size_t i = 0; i < len; i++) { - if (buf[i] == from) - buf[i] = to; + if (buf[i] == from) + buf[i] = to; } } @@ -734,7 +734,7 @@ char *strmcopy(char *buf) { if ((str = (char*) malloc(strlen(buf) + 1)) != NULL) { memset(str, 0, strlen(buf) + 1); strcpy(str, buf); - } + } return str; } diff --git a/common/protocols.h b/common/protocols.h index ab556516..9de72661 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -125,6 +125,10 @@ NXP/Philips CUSTOM COMMANDS #define MIFARE_CMD_TRANSFER 0xB0 #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_ULC_WRITE 0xA2 @@ -232,6 +236,26 @@ NXP/Philips CUSTOM COMMANDS #define TOPAZ_WRITE_E8 0x54 // Write-with-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, 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 ICLASS 1 diff --git a/include/hitag.h b/include/hitag.h index 35660dcb..b5b13c31 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -31,6 +31,7 @@ typedef enum { WHT2F_CRYPTO = 24, RHT2F_TEST_AUTH_ATTEMPTS = 25, RHT2F_UID_ONLY = 26, + WHT2F_PASSWORD = 27, } hitag_function; typedef struct { diff --git a/include/usb_cmd.h b/include/usb_cmd.h index c998bf94..1bc5e5ba 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -197,17 +197,17 @@ typedef struct{ #define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613 #define CMD_MIFARE_READBL 0x0620 -#define CMD_MIFAREU_READBL 0x0720 #define CMD_MIFARE_READSC 0x0621 -#define CMD_MIFAREU_READCARD 0x0721 #define CMD_MIFARE_WRITEBL 0x0622 -#define CMD_MIFAREU_WRITEBL 0x0722 -#define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 - #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_COMPAT 0x0723 #define CMD_MIFAREUC_AUTH 0x0724 //0x0725 and 0x0726 no longer used #define CMD_MIFAREUC_SETPWD 0x0727