diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index dc4bda955..e45993e73 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -310,6 +310,7 @@ bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, ui bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t timestamp_start, uint32_t timestamp_end, bool reader2tag) { uint8_t parity[(nbytes(bitLen) - 1) / 8 + 1]; memset(parity, 0x00, sizeof(parity)); + // parity has amount of leftover bits. parity[0] = bitLen % 8; return LogTrace(btBytes, nbytes(bitLen), timestamp_start, timestamp_end, parity, reader2tag); } diff --git a/armsrc/Makefile b/armsrc/Makefile index 5f641884a..b42061267 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -72,6 +72,7 @@ endif ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS))) SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c + APP_CFLAGS += -I../common/hitag2 else SRC_HITAG = endif diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index f35bb1947..4fb16c7ca 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -55,7 +55,7 @@ Public Mode B : 0x00 - 0000 0000 Public Mode C : 0x04 - 0000 0100 */ -static struct hitag2_tag tag = { +static hitag2_t tag = { .state = TAG_STATE_RESET, .sectors = { // Password mode: | Crypto mode: [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID @@ -118,6 +118,7 @@ static void hitag2_init(void) { #endif #define HITAG_FRAME_LEN 20 +#define HITAG_FRAME_BIT_COUNT (8 * HITAG_FRAME_LEN) #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 */ @@ -198,7 +199,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ memcpy(rx_air, rx, nbytes(rxlen)); if (tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen / 8, rxlen % 8); + ht2_hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen / 8, rxlen % 8); } // Reset the transmission frame length @@ -225,7 +226,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Verify complement of sector index if (sector != ((rx[0] >> 3) & 0x07)) { - DbpString("Transmission error (read/write)"); + DBG DbpString("Transmission error (read/write)"); return; } @@ -255,7 +256,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ } // Unknown command default: { - Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); + DBG Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); return; } } @@ -272,7 +273,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ } else { // Received RWD password, respond with configuration and our password if (memcmp(rx, tag.sectors[1], 4) != 0) { - DbpString("Reader password is wrong"); + DBG DbpString("Reader password is wrong"); return; } *txlen = 32; @@ -290,12 +291,12 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ } // Reset the cipher state - hitag2_cipher_reset(&tag, rx); + ht2_hitag2_cipher_reset(&tag, rx); // Check if the authentication was correct - if (!hitag2_cipher_authenticate(&(tag.cs), rx + 4)) { + if (!ht2_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]); + DBG 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; } // Activate encryption algorithm for all further communication @@ -312,7 +313,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // LogTraceBits(tx, txlen, 0, 0, true); if (tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8); + ht2_hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8); } } @@ -728,13 +729,14 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * *txlen = 0; if (bCrypto) { - hitag2_cipher_transcrypt(&cipher_state, rx, rxlen / 8, rxlen % 8); + ht2_hitag2_cipher_transcrypt(&cipher_state, rx, rxlen / 8, rxlen % 8); } if (bCrypto && !bAuthenticating && write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + if (hitag2_write_page(rx, rxlen, tx, txlen) == false) { return false; } + } else { // Try to find out which command was send by selecting on length (in bits) @@ -745,7 +747,7 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * if (bCrypto) { // Failed during authentication if (bAuthenticating) { - DbpString("Authentication failed!"); + DBG DbpString("Authentication failed!"); return false; } else { // Failed reading a block, could be (read/write) locked, skip block and re-authenticate @@ -774,16 +776,27 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * // Received UID, crypto tag answer case 32: { // stage 1, got UID - if (!bCrypto) { + if (bCrypto == false) { + + DBG Dbprintf("hitag2_crypto: key array "); + DBG Dbhexdump(6, key, false); + 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); - // PRN + DBG Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x" + , (uint32_t)((REV64(ui64key)) >> 32) + , (uint32_t)((REV64(ui64key)) & 0xffffffff) + , REV32(ui32uid) + ); + + cipher_state = ht2_hitag2_init(REV64(ui64key), REV32(ui32uid), 0); + + // PRN 00 00 00 00 memset(tx, 0x00, 4); - // Secret data + // Secret data FF FF FF FF memset(tx + 4, 0xff, 4); - hitag2_cipher_transcrypt(&cipher_state, tx + 4, 4, 0); + ht2_hitag2_cipher_transcrypt(&cipher_state, tx + 4, 4, 0); *txlen = 64; bCrypto = true; bAuthenticating = true; @@ -792,7 +805,7 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * if (bAuthenticating) { bAuthenticating = false; if (write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + if (hitag2_write_page(rx, rxlen, tx, txlen) == false) { return false; } break; @@ -805,7 +818,7 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * blocknr++; } if (blocknr > 7) { - DbpString("Read successful!"); + DBG DbpString("Read successful!"); bSuccessful = true; return false; } else { @@ -819,7 +832,7 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * // Unexpected response default: { - Dbprintf("Unknown frame length: %d", rxlen); + DBG Dbprintf("Unknown frame length: %d", rxlen); return false; } break; @@ -828,8 +841,8 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t * if (bCrypto) { // We have to return now to avoid double encryption - if (!bAuthenticating) { - hitag2_cipher_transcrypt(&cipher_state, tx, *txlen / 8, *txlen % 8); + if (bAuthenticating == false) { + ht2_hitag2_cipher_transcrypt(&cipher_state, tx, *txlen / 8, *txlen % 8); } } @@ -846,7 +859,7 @@ static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, si case 0: { // Stop if there is no answer while we are in crypto mode (after sending NrAr) if (bCrypto) { - DbpString("Authentication failed!"); + DBG DbpString("Authentication failed!"); return false; } *txlen = 5; @@ -861,7 +874,7 @@ static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, si memcpy(tx, NrAr, 8); bCrypto = true; } else { - DbpString("Authentication successful!"); + DBG DbpString("Authentication successful!"); return true; } } @@ -869,7 +882,7 @@ static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, si // Unexpected response default: { - Dbprintf("Unknown frame length: %d", rxlen); + DBG Dbprintf("Unknown frame length: %d", rxlen); return false; } break; @@ -990,7 +1003,7 @@ void EloadHitag(const uint8_t *data, uint16_t len) { // Tstop 36 > fc (high field stop limit) // Tlow 4-10 fc (reader field low time) void SniffHitag2(bool ledcontrol) { - DbpString("Starting Hitag2 sniffing"); + if (ledcontrol) LED_D_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -1202,10 +1215,12 @@ void SniffHitag2(bool ledcontrol) { // } // 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) { // '1' bit rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); rxlen++; + } else if (ra >= HITAG_T_0_MIN) { // '0' bit rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); @@ -1271,8 +1286,6 @@ void SniffHitag2(bool ledcontrol) { } } - // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); response = 0; reader_frame = false; lastbit = 1; @@ -1284,12 +1297,15 @@ void SniffHitag2(bool ledcontrol) { LED_B_OFF(); LED_C_OFF(); } + } else { // Save the timer overflow, will be 0 when frame was received overflow += (AT91C_BASE_TC1->TC_CV / HITAG_T0); } + // Reset the frame length rxlen = 0; + // Reset the timer to restart while-loop that receives frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; @@ -1302,12 +1318,11 @@ void SniffHitag2(bool ledcontrol) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - set_tracing(false); - - Dbprintf("frame received: %d", frame_count); - Dbprintf("Authentication Attempts: %d", (auth_table_len / 8)); + DBG Dbprintf("frames.......... %d", frame_count); + Dbprintf("Auth attempts... %d", (auth_table_len / 8)); + switch_off(); + BigBuf_free(); } // Hitag2 simulation diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index d304cb6b3..ee0bba534 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -450,7 +450,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, Dbprintf("Challenge for UID: %X", temp_uid); temp2++; *txlen = 32; - state = _hitag2_init(REV64(tag.key), + state = ht2_hitag2_init(REV64(tag.key), REV32((tag.pages[0][3] << 24) + (tag.pages[0][2] << 16) + (tag.pages[0][1] << 8) + tag.pages[0][0]), REV32((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]) ); @@ -462,14 +462,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, hitagS_set_frame_modulation(); for (int i = 0; i < 4; i++) { - _hitag2_byte(&state); + ht2_hitag2_byte(&state); } //send con2, pwdh0, pwdl0, pwdl1 encrypted as a response - tx[0] = _hitag2_byte(&state) ^ tag.pages[1][2]; - tx[1] = _hitag2_byte(&state) ^ tag.pwdh0; - tx[2] = _hitag2_byte(&state) ^ tag.pwdl0; - tx[3] = _hitag2_byte(&state) ^ tag.pwdl1; + tx[0] = ht2_hitag2_byte(&state) ^ tag.pages[1][2]; + tx[1] = ht2_hitag2_byte(&state) ^ tag.pwdh0; + tx[2] = ht2_hitag2_byte(&state) ^ tag.pwdl0; + tx[3] = ht2_hitag2_byte(&state) ^ tag.pwdl1; if (tag.mode != HT_STANDARD) { //add crc8 @@ -479,7 +479,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, calc_crc(&crc, tag.pwdh0, 8); calc_crc(&crc, tag.pwdl0, 8); calc_crc(&crc, tag.pwdl1, 8); - tx[4] = (crc ^ _hitag2_byte(&state)); + tx[4] = (crc ^ ht2_hitag2_byte(&state)); } /* * some readers do not allow to authenticate multiple times in a row with the same tag. @@ -1183,10 +1183,10 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx, ((uint64_t)htd->crypto.key[4]) << 32 | ((uint64_t)htd->crypto.key[5]) << 40 ; - uint64_t state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); + uint64_t state = ht2_hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); uint8_t auth_ks[4]; for (int i = 0; i < 4; i++) { - auth_ks[i] = _hitag2_byte(&state) ^ 0xff; + auth_ks[i] = ht2_hitag2_byte(&state) ^ 0xff; } txlen = 0; @@ -1239,14 +1239,14 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx, pwdl0 = 0; pwdl1 = 0; if (htf == RHTSF_KEY || htf == WHTSF_KEY) { - uint64_t state = _hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); + uint64_t state = ht2_hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); for (int i = 0; i < 4; i++) { - _hitag2_byte(&state); + ht2_hitag2_byte(&state); } - uint8_t con2 = rx[0] ^ _hitag2_byte(&state); - pwdh0 = rx[1] ^ _hitag2_byte(&state); - pwdl0 = rx[2] ^ _hitag2_byte(&state); - pwdl1 = rx[3] ^ _hitag2_byte(&state); + uint8_t con2 = rx[0] ^ ht2_hitag2_byte(&state); + pwdh0 = rx[1] ^ ht2_hitag2_byte(&state); + pwdl0 = rx[2] ^ ht2_hitag2_byte(&state); + pwdl1 = rx[3] ^ ht2_hitag2_byte(&state); if (g_dbglevel >= DBG_EXTENDED) Dbprintf("con2 %02X pwdh0 %02X pwdl0 %02X pwdl1 %02X", con2, pwdh0, pwdl0, pwdl1); diff --git a/armsrc/util.h b/armsrc/util.h index 00db8eb99..63e5f7eda 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -68,21 +68,6 @@ #define BUTTON_DOUBLE_CLICK -2 #define BUTTON_ERROR -99 -#ifndef REV8 -#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)) -#endif - -#ifndef REV16 -#define REV16(x) (REV8(x) + (REV8 ((x) >> 8) << 8)) -#endif - -#ifndef REV32 -#define REV32(x) (REV16(x) + (REV16((x) >> 16) << 16)) -#endif - -#ifndef REV64 -#define REV64(x) (REV32(x) + ((uint64_t)(REV32((x) >> 32) << 32))) -#endif #ifndef BIT32 #define BIT32(x,n) ((((x)[(n)>>5])>>((n)))&1) diff --git a/client/Makefile b/client/Makefile index 942316726..f9e3c9382 100644 --- a/client/Makefile +++ b/client/Makefile @@ -771,6 +771,7 @@ SRCS += bucketsort.c \ crc32.c \ crc64.c \ commonutil.c \ + hitag2/hitag2_crypto.c \ iso15693tools.c \ legic_prng.c \ lfdemod.c \ diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 14747a081..2a13eef0c 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -3649,6 +3649,51 @@ static int CmdBinaryMap(const char *Cmd) { return PM3_SUCCESS; } +static int CmdXor(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "data xor", + "takes input string and xor string. Perform xor on it.\n" + "If no xor string, try the most reoccuring value to xor against", + "data xor -d 99aabbcc8888888888\n" + "data xor -d 99aabbcc --xor 88888888\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str1("d", "data", "", "input hex string"), + arg_str0("x", "xor", "", "input xor string"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int hlen = 128; + uint8_t hex[128 + 1]; + CLIGetHexWithReturn(ctx, 1, hex, &hlen); + + int xlen = 128; + uint8_t xor[128 + 1]; + CLIGetHexWithReturn(ctx, 2, xor, &xlen); + CLIParserFree(ctx); + + // find xor value + if (xlen == 0) { + uint8_t x = get_highest_frequency(hex, hlen); + xlen = hlen; + memset(xor, x, xlen); + } + + if (hlen != xlen) { + PrintAndLogEx(FAILED, "Length mismatch, got %i != %i", hlen, xlen); + return PM3_EINVARG; + } + + PrintAndLogEx(SUCCESS, "input... %s", sprint_hex_inrow(hex, hlen)); + PrintAndLogEx(SUCCESS, "xor..... %s", sprint_hex_inrow(xor, xlen)); + hex_xor(hex, xor, hlen); + PrintAndLogEx(SUCCESS, "plain... " _YELLOW_("%s"), sprint_hex_inrow(hex, hlen)); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("General") "-------------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, @@ -3700,9 +3745,10 @@ static command_t CommandTable[] = { {"load", CmdLoad, AlwaysAvailable, "Load contents of file into graph window"}, {"num", CmdNumCon, AlwaysAvailable, "Converts dec/hex/bin"}, {"print", CmdPrintDemodBuff, AlwaysAvailable, "Print the data in the DemodBuffer"}, - {"samples", CmdSamples, IfPm3Present, "Get raw samples for graph window (GraphBuffer)"}, - {"save", CmdSave, AlwaysAvailable, "Save signal trace data (from graph window)"}, + {"samples", CmdSamples, IfPm3Present, "Get raw samples for graph window ( GraphBuffer )"}, + {"save", CmdSave, AlwaysAvailable, "Save signal trace data ( GraphBuffer )"}, {"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "Set Debugging Level on client side"}, + {"xor", CmdXor, AlwaysAvailable, "Xor a input string"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 5bf049677..be429561c 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -365,7 +365,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i break; case MIFARE_ULEV1_AUTH: if (cmdsize == 7) - snprintf(exp, size, "PWD-AUTH KEY: " _GREEN_("0x%02X%02X%02X%02X"), cmd[1], cmd[2], cmd[3], cmd[4]); + snprintf(exp, size, "PWD-AUTH: " _GREEN_("0x%02X%02X%02X%02X"), cmd[1], cmd[2], cmd[3], cmd[4]); else snprintf(exp, size, "PWD-AUTH"); break; @@ -2103,9 +2103,9 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, break; } - if ((MifareAuthState == masNone) || (MifareAuthState == masError)) + if ((MifareAuthState == masNone) || (MifareAuthState == masError)) { annotateIso14443a(exp, size, cmd, cmdsize, isResponse); - + } } static void mf_get_paritybinstr(char *s, uint32_t val, uint8_t par) { diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index 91b321fd0..e4357e054 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -366,18 +366,16 @@ static void print_hitag2_blocks(uint8_t *d, uint16_t n) { , annotation[i] ); } - PrintAndLogEx(INFO, "---------+-------------+-------+-----+---------"); - PrintAndLogEx(INFO, " L = Locked, "_GREEN_("RW") " = Read Write, R = Read Only"); + PrintAndLogEx(INFO, "--------+-------------+-------+-----+---------"); + PrintAndLogEx(INFO, " "_RED_("L") " = Locked, "_GREEN_("RW") " = Read Write, R = Read Only"); PrintAndLogEx(INFO, " FI = Fixed / Irreversible"); - PrintAndLogEx(INFO, "-----------------------------------------------"); + PrintAndLogEx(INFO, "----------------------------------------------"); } // Annotate HITAG protocol void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) { } - - static struct { enum { STATE_HALT, @@ -387,16 +385,12 @@ static struct { } state; } _ht2state; - void annotateHitag2_init(void) { _ht2state.state = STATE_HALT; } void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response) { - // I think its better to handle this log bytes as a long array of bits instead. - // 1100 0 - // 1100 0001 1100 0000 00 if (cmdsize == 0) { return; } diff --git a/client/src/cmdlfhitag.h b/client/src/cmdlfhitag.h index c13520524..c3cefc10d 100644 --- a/client/src/cmdlfhitag.h +++ b/client/src/cmdlfhitag.h @@ -26,7 +26,9 @@ #define HITAG_PASSWORD_SIZE 4 #define HITAG_UID_SIZE 4 #define HITAG_BLOCK_SIZE 4 -#define HITAG2_MAX_BYTE_SIZE (12 * HITAG_BLOCK_SIZE) +#define HITAG2_MAX_BLOCKS 8 +#define HITAG2_MAX_BYTE_SIZE (HITAG2_MAX_BLOCKS * HITAG_BLOCK_SIZE) + // need to see which limits these cards has #define HITAG1_MAX_BYTE_SIZE 64 #define HITAGS_MAX_BYTE_SIZE 64 diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index fa5d804cb..08204463a 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -650,26 +650,26 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr if (data_len == 1) { if (nbits == 5) { - snprintf(line[0], 120, "%2u: %02x ", nbits, frame[0] >> (8 - nbits)); + snprintf(line[0], 120, "%2u: %02X ", nbits, frame[0] >> (8 - nbits)); } else { - snprintf(line[0], 120, "%2u: %02x ", nbits, frame[0] >> (8 - nbits)); + snprintf(line[0], 120, "%2u: %02X ", nbits, frame[0] >> (8 - nbits)); } } else { if (nbits == 0) { - snprintf(line[0], 120, "%2u: %02x ", (data_len * 8), frame[0]); + snprintf(line[0], 120, "%2u: %02X ", (data_len * 8), frame[0]); } else { - snprintf(line[0], 120, "%2u: %02x ", ((data_len - 1) * 8) + nbits, frame[0]); + snprintf(line[0], 120, "%2u: %02X ", ((data_len - 1) * 8) + nbits, frame[0]); } } offset = 4; } else { - snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02x ", frame[j]); + snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02X ", frame[j]); } } else { - snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x ", frame[j]); + snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02X ", frame[j]); } } diff --git a/client/src/comms.c b/client/src/comms.c index 93572ab98..3e03cf9f3 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -314,19 +314,26 @@ static void PacketResponseReceived(PacketResponseNG *packet) { //PrintAndLogEx(NORMAL, "[" _MAGENTA_("pm3") "] ["_BLUE_("#")"] " "%s", s); PrintAndLogEx(NORMAL, "[" _BLUE_("#") "] %s", s); } else { - if (flag & FLAG_INPLACE) + if (flag & FLAG_INPLACE) { PrintAndLogEx(NORMAL, "\r" NOLF); + } PrintAndLogEx(NORMAL, "%s" NOLF, s); - if (flag & FLAG_NEWLINE) + if (flag & FLAG_NEWLINE) { PrintAndLogEx(NORMAL, ""); + } } break; } case CMD_DEBUG_PRINT_INTEGERS: { - if (packet->ng == false) - PrintAndLogEx(NORMAL, "[" _MAGENTA_("pm3") "] ["_BLUE_("#")"] " "%" PRIx64 ", %" PRIx64 ", %" PRIx64 "", packet->oldarg[0], packet->oldarg[1], packet->oldarg[2]); + if (packet->ng == false) { + PrintAndLogEx(NORMAL, "[" _MAGENTA_("pm3") "] ["_BLUE_("#")"] " "%" PRIx64 ", %" PRIx64 ", %" PRIx64 "" + , packet->oldarg[0] + , packet->oldarg[1] + , packet->oldarg[2] + ); + } break; } // iceman: hw status - down the path on device, runs printusbspeed which starts sending a lot of diff --git a/common/commonutil.h b/common/commonutil.h index f057486a2..a31c6c64e 100644 --- a/common/commonutil.h +++ b/common/commonutil.h @@ -49,6 +49,23 @@ # define NTIME(n) for (int _index = 0; _index < n; _index++) #endif +#ifndef REV8 +#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)) +#endif + +#ifndef REV16 +#define REV16(x) (REV8(x) + (REV8 ((x) >> 8) << 8)) +#endif + +#ifndef REV32 +#define REV32(x) (REV16(x) + (REV16((x) >> 16) << 16)) +#endif + +#ifndef REV64 +#define REV64(x) (REV32(x) + ((uint64_t)(REV32((x) >> 32) << 32))) +#endif + + extern struct version_information_t g_version_information; void FormatVersionInformation(char *dst, int len, const char *prefix, const void *version_info); void format_version_information_short(char *dst, int len, const void *version_info); diff --git a/common/hitag2/hitag2_crypto.c b/common/hitag2/hitag2_crypto.c index 931c17fa8..8fd596fa8 100644 --- a/common/hitag2/hitag2_crypto.c +++ b/common/hitag2/hitag2_crypto.c @@ -19,6 +19,7 @@ #include "util.h" #include "string.h" +#include "commonutil.h" /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ // Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007. @@ -35,7 +36,7 @@ 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 -uint32_t _f20(const uint64_t x) { +static uint32_t ht2_f20(const uint64_t x) { uint32_t i5; i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 @@ -47,18 +48,18 @@ uint32_t _f20(const uint64_t x) { return (ht2_f5c >> i5) & 1; } -uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) { +uint64_t ht2_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; + x += (uint64_t)(ht2_f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; } return x; } -uint64_t _hitag2_round(uint64_t *state) { +uint64_t ht2_hitag2_round(uint64_t *state) { uint64_t x = *state; x = (x >> 1) + @@ -68,7 +69,7 @@ uint64_t _hitag2_round(uint64_t *state) { ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); *state = x; - return _f20(x); + return ht2_f20(x); } // "MIKRON" = O N M I K R @@ -81,15 +82,15 @@ uint64_t _hitag2_round(uint64_t *state) { // The inverse of the first 4 bytes is sent to the tag to authenticate. // The rest is encrypted by XORing it with the subsequent keystream. -uint32_t _hitag2_byte(uint64_t *x) { +uint32_t ht2_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); + c += (uint32_t) ht2_hitag2_round(x) << (i ^ 7); } return c; } -void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv) { +void ht2_hitag2_cipher_reset(hitag2_t *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) | @@ -104,22 +105,22 @@ void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_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 = ht2_hitag2_init(REV64(key), REV32(uid), REV32(iv_)); } -int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) { +int ht2_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); - authenticator_should[3] = ~_hitag2_byte(cs); + authenticator_should[0] = ~ht2_hitag2_byte(cs); + authenticator_should[1] = ~ht2_hitag2_byte(cs); + authenticator_should[2] = ~ht2_hitag2_byte(cs); + authenticator_should[3] = ~ht2_hitag2_byte(cs); return (memcmp(authenticator_should, authenticator_is, 4) == 0); } -int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) { +int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) { int i; - for (i = 0; i < bytes; i++) data[i] ^= _hitag2_byte(cs); - for (i = 0; i < bits; i++) data[bytes] ^= _hitag2_round(cs) << (7 - i); + for (i = 0; i < bytes; i++) data[i] ^= ht2_hitag2_byte(cs); + for (i = 0; i < bits; i++) data[bytes] ^= ht2_hitag2_round(cs) << (7 - i); return 0; } diff --git a/common/hitag2/hitag2_crypto.h b/common/hitag2/hitag2_crypto.h index c6a7d7308..381417621 100644 --- a/common/hitag2/hitag2_crypto.h +++ b/common/hitag2/hitag2_crypto.h @@ -18,7 +18,7 @@ #include "common.h" -struct hitag2_tag { +typedef struct { uint32_t uid; enum { TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr @@ -30,14 +30,13 @@ struct hitag2_tag { uint8_t crypto_active; uint64_t cs; uint8_t sectors[12][4]; -}; +} hitag2_t; -uint32_t _f20(const uint64_t x); -uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV); -uint64_t _hitag2_round(uint64_t *state); -uint32_t _hitag2_byte(uint64_t *x); -void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv); -int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is); -int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ; +uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV); +uint64_t ht2_hitag2_round(uint64_t *state); +uint32_t ht2_hitag2_byte(uint64_t *x); +void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv); +int ht2_hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is); +int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ; #endif diff --git a/common_arm/Makefile.common b/common_arm/Makefile.common index 18d931b46..e8e574112 100644 --- a/common_arm/Makefile.common +++ b/common_arm/Makefile.common @@ -44,7 +44,7 @@ OBJDIR = obj INCLUDE = -I../include -I../common_arm -I../common_fpga -I../common -I. # Also search prerequisites in the common directory (for usb.c), the fpga directory (for fpga.bit), and the lz4 directory -VPATH = . ../common_arm ../common ../common/crapto1 ../common/mbedtls ../common/lz4 ../fpga ../armsrc/Standalone +VPATH = . ../common_arm ../common ../common/crapto1 ../common/mbedtls ../common/lz4 ../fpga ../armsrc/Standalone ../common/hitag2 INCLUDES = ../include/proxmark3_arm.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/pm3_cmd.h diff --git a/include/protocols.h b/include/protocols.h index a2c620b05..68fa344eb 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -914,7 +914,6 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define HITAG2_WRITE_PAGE "10" // write page after auth #define HITAG2_HALT "00" // silence currently authenticated tag - // HITAG S commands #define HITAGS_QUIET 0x70 //inverted in bit 0 and following 2 bits