move hitag2 crypto parts to the common folder in order to be able to use it on the client side. Some textual and minor adaptations across the bord

This commit is contained in:
iceman1001 2024-03-27 09:32:00 +01:00
commit 700d558432
17 changed files with 185 additions and 117 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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)

View file

@ -771,6 +771,7 @@ SRCS += bucketsort.c \
crc32.c \
crc64.c \
commonutil.c \
hitag2/hitag2_crypto.c \
iso15693tools.c \
legic_prng.c \
lfdemod.c \

View file

@ -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", "<hex>", "input hex string"),
arg_str0("x", "xor", "<str>", "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}
};

View file

@ -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) {

View file

@ -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;
}

View file

@ -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

View file

@ -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]);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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