'lf hitag writer': add Hitag2 password auth

* (PRs 233, 303, 304 by @ViRb3 on https://github.com/RfidResearchGroup/proxmark3)
* replace byte_t by uint8_t
* note that Hitag1 commands are not yet available
* whitespace fixes
This commit is contained in:
pwpiwi 2019-08-06 13:00:35 +02:00
commit 56e92b77da
4 changed files with 732 additions and 700 deletions

View file

@ -16,7 +16,6 @@
#include <stddef.h> #include <stddef.h>
#include "common.h" #include "common.h"
#include "usb_cmd.h" #include "usb_cmd.h"
#include "hitag2.h"
#include "hitagS.h" #include "hitagS.h"
#include "mifare.h" #include "mifare.h"
#include "../common/crc32.h" #include "../common/crc32.h"

View file

@ -19,6 +19,7 @@
#include "hitag2.h" #include "hitag2.h"
#include "proxmark3.h" #include "proxmark3.h"
#include "cmd.h"
#include "apps.h" #include "apps.h"
#include "util.h" #include "util.h"
#include "hitag.h" #include "hitag.h"
@ -44,9 +45,9 @@ struct hitag2_tag {
TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written
} state; } state;
unsigned int active_sector; unsigned int active_sector;
byte_t crypto_active; uint8_t crypto_active;
uint64_t cs; uint64_t cs;
byte_t sectors[12][4]; uint8_t sectors[12][4];
}; };
static struct hitag2_tag tag = { static struct hitag2_tag tag = {
@ -77,14 +78,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. // 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. // Historically it used to be FREE_BUFFER_SIZE, which was 2744.
#define AUTH_TABLE_LENGTH 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_pos = 0;
static size_t auth_table_len = AUTH_TABLE_LENGTH; static size_t auth_table_len = AUTH_TABLE_LENGTH;
static byte_t password[4]; static uint8_t password[4];
static byte_t NrAr[8]; static uint8_t NrAr[8];
static byte_t key[8]; static uint8_t key[8];
static byte_t writedata[4]; static uint8_t writedata[4];
static uint64_t cipher_state; static uint64_t cipher_state;
/* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */
@ -177,7 +178,7 @@ static int hitag2_init(void)
return 0; return 0;
} }
static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv)
{ {
uint64_t key = ((uint64_t)tag->sectors[2][2]) | uint64_t key = ((uint64_t)tag->sectors[2][2]) |
((uint64_t)tag->sectors[2][3] << 8) | ((uint64_t)tag->sectors[2][3] << 8) |
@ -196,9 +197,9 @@ static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv)
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) static int hitag2_cipher_authenticate(uint64_t* cs, const uint8_t *authenticator_is)
{ {
byte_t authenticator_should[4]; uint8_t authenticator_should[4];
authenticator_should[0] = ~_hitag2_byte(cs); authenticator_should[0] = ~_hitag2_byte(cs);
authenticator_should[1] = ~_hitag2_byte(cs); authenticator_should[1] = ~_hitag2_byte(cs);
authenticator_should[2] = ~_hitag2_byte(cs); authenticator_should[2] = ~_hitag2_byte(cs);
@ -206,7 +207,7 @@ static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_
return (memcmp(authenticator_should, authenticator_is, 4) == 0); 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; int i;
for(i=0; i<bytes; i++) data[i] ^= _hitag2_byte(cs); for(i=0; i<bytes; i++) data[i] ^= _hitag2_byte(cs);
@ -271,7 +272,7 @@ static void hitag_send_bit(int bit) {
LED_A_OFF(); 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 // Send start of frame
for(size_t i = 0; i < 5; i++) { for(size_t i = 0; i < 5; i++) {
@ -280,7 +281,7 @@ static void hitag_send_frame(const byte_t* frame, size_t frame_len)
// Send the content of the frame // Send the content of the frame
for (size_t i = 0; i < frame_len; i++) { for (size_t i = 0; i < frame_len; i++) {
hitag_send_bit((frame[i/8] >> (7-(i%8)))&1); hitag_send_bit((frame[i/8] >> (7-(i%8))) & 0x01);
} }
// Drop the modulation // Drop the modulation
@ -288,9 +289,8 @@ static void hitag_send_frame(const byte_t* frame, size_t frame_len)
} }
static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) 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];
byte_t rx_air[HITAG_FRAME_LEN];
// Copy the (original) received frame how it is send over the air // Copy the (original) received frame how it is send over the air
memcpy(rx_air, rx, nbytes(rxlen)); memcpy(rx_air, rx, nbytes(rxlen));
@ -446,11 +446,11 @@ static void hitag_reader_send_bit(int bit) {
} }
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 // Send the content of the frame
for(size_t i = 0; i < frame_len; i++) { for(size_t i = 0; i < frame_len; i++) {
hitag_reader_send_bit((frame[i/8] >> (7-(i%8)))&1); hitag_reader_send_bit((frame[i/8] >> (7-(i%8))) & 0x01);
} }
// Send EOF // Send EOF
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
@ -464,63 +464,11 @@ static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len)
size_t blocknr; size_t blocknr;
static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { //-----------------------------------------------------------------------------
// Reset the transmission frame length // Hitag2 operations
*txlen = 0; //-----------------------------------------------------------------------------
// Try to find out which command was send by selecting on length (in bits) static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
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;
}
*txlen = 5;
memcpy(tx,"\xc0",nbytes(*txlen));
} 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 {
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);
}
blocknr++;
if (blocknr > 7) {
DbpString("Read succesful!");
bSuccessful = true;
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) { switch (writestate) {
case WRITE_STATE_START: case WRITE_STATE_START:
*txlen = 10; *txlen = 10;
@ -530,9 +478,9 @@ static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t
break; break;
case WRITE_STATE_PAGENUM_WRITTEN: case WRITE_STATE_PAGENUM_WRITTEN:
// Check if page number was received correctly // Check if page number was received correctly
if ((rxlen == 10) && if ((rxlen == 10)
(rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && && (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2)))
(rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { && (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) {
*txlen = 32; *txlen = 32;
memset(tx, 0, HITAG_FRAME_LEN); memset(tx, 0, HITAG_FRAME_LEN);
memcpy(tx, writedata, 4); memcpy(tx, writedata, 4);
@ -561,28 +509,92 @@ static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t
return true; return true;
} }
static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen, bool write) { 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;
if (bPwd && !bAuthenticating && write) {
if (!hitag2_write_page(rx, rxlen, tx, txlen)) {
return false;
}
} 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;
}
*txlen = 5;
memcpy(tx, "\xc0", nbytes(*txlen));
}
break;
// 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 > 7) {
DbpString("Read successful!");
bSuccessful = true;
return false;
}
*txlen = 10;
tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2);
tx[1] = ((blocknr^7) << 6);
}
}
break;
// Unexpected response
default: {
Dbprintf("Unknown frame length: %d", rxlen);
return false;
}
break;
}
}
return true;
}
static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) {
// Reset the transmission frame length // Reset the transmission frame length
*txlen = 0; *txlen = 0;
if (bCrypto) { if (bCrypto) {
hitag2_cipher_transcrypt(&cipher_state, rx, rxlen/8, rxlen%8); hitag2_cipher_transcrypt(&cipher_state, rx, rxlen/8, rxlen%8);
} }
if (bCrypto && !bAuthenticating && write) { if (bCrypto && !bAuthenticating && write) {
if (!hitag2_write_page(rx, rxlen, tx, txlen)) { if (!hitag2_write_page(rx, rxlen, tx, txlen)) {
return false; return false;
} }
} } else {
else
{
// Try to find out which command was send by selecting on length (in bits) // Try to find out which command was send by selecting on length (in bits)
switch (rxlen) { switch (rxlen) {
// No answer, try to resurrect // No answer, try to resurrect
case 0: case 0: {
{
// Stop if there is no answer while we are in crypto mode (after sending NrAr) // Stop if there is no answer while we are in crypto mode (after sending NrAr)
if (bCrypto) { if (bCrypto) {
// Failed during authentication // Failed during authentication
@ -636,14 +648,15 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx
} }
break; break;
} }
} else { }
// stage 2+, got data block
else {
// Store the received block // Store the received block
memcpy(tag.sectors[blocknr], rx, 4); memcpy(tag.sectors[blocknr], rx, 4);
blocknr++; blocknr++;
} }
if (blocknr > 7) { if (blocknr > 7) {
DbpString("Read succesful!"); DbpString("Read successful!");
bSuccessful = true; bSuccessful = true;
return false; return false;
} else { } else {
@ -656,7 +669,7 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Uknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; } break;
} }
@ -672,8 +685,7 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx
return true; return true;
} }
static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) {
// Reset the transmission frame length // Reset the transmission frame length
*txlen = 0; *txlen = 0;
@ -697,7 +709,7 @@ static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size
memcpy(tx, NrAr, 8); memcpy(tx, NrAr, 8);
bCrypto = true; bCrypto = true;
} else { } else {
DbpString("Authentication succesful!"); DbpString("Authentication successful!");
// We are done... for now // We are done... for now
return false; return false;
} }
@ -705,7 +717,7 @@ static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Uknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; } break;
} }
@ -714,7 +726,7 @@ static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size
} }
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 // Reset the transmission frame length
*txlen = 0; *txlen = 0;
@ -762,7 +774,7 @@ static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx
} break; } break;
default: { default: {
Dbprintf("Uknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; } break;
} }
@ -770,7 +782,7 @@ static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx
return true; 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 // Reset the transmission frame length
*txlen = 0; *txlen = 0;
@ -800,7 +812,7 @@ static bool hitag2_read_uid(byte_t* rx, const size_t rxlen, byte_t* tx, size_t*
} break; } break;
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Uknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; } break;
} }
@ -808,7 +820,7 @@ static bool hitag2_read_uid(byte_t* rx, const size_t rxlen, byte_t* tx, size_t*
} }
void SnoopHitag(uint32_t type) { void SnoopHitag(uint32_t type) {
int frame_count; // int frame_count;
int response; int response;
int overflow; int overflow;
bool rising_edge; bool rising_edge;
@ -816,7 +828,7 @@ void SnoopHitag(uint32_t type) {
int lastbit; int lastbit;
bool bSkip; bool bSkip;
int tag_sof; int tag_sof;
byte_t rx[HITAG_FRAME_LEN] = {0}; uint8_t rx[HITAG_FRAME_LEN] = {0};
size_t rxlen = 0; size_t rxlen = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
@ -829,7 +841,7 @@ void SnoopHitag(uint32_t type) {
auth_table_pos = 0; auth_table_pos = 0;
BigBuf_free(); 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); memset(auth_table, 0x00, AUTH_TABLE_LENGTH);
DbpString("Starting Hitag2 snoop"); DbpString("Starting Hitag2 snoop");
@ -865,7 +877,7 @@ void SnoopHitag(uint32_t type) {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
frame_count = 0; // frame_count = 0;
response = 0; response = 0;
overflow = 0; overflow = 0;
reader_frame = false; reader_frame = false;
@ -972,7 +984,7 @@ void SnoopHitag(uint32_t type) {
// Check if frame was captured // Check if frame was captured
if (rxlen > 0) { if (rxlen > 0) {
frame_count++; // frame_count++;
if (!LogTraceHitag(rx, rxlen, response, 0, reader_frame)) { if (!LogTraceHitag(rx, rxlen, response, 0, reader_frame)) {
DbpString("Trace full"); DbpString("Trace full");
break; break;
@ -1021,13 +1033,13 @@ void SnoopHitag(uint32_t type) {
// DbpString("All done"); // DbpString("All done");
} }
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data) {
int frame_count; // int frame_count;
int response; int response;
int overflow; int overflow;
byte_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0; size_t rxlen = 0;
byte_t tx[HITAG_FRAME_LEN]; uint8_t tx[HITAG_FRAME_LEN];
size_t txlen = 0; size_t txlen = 0;
bool bQuitTraceFull = false; bool bQuitTraceFull = false;
bQuiet = false; bQuiet = false;
@ -1040,9 +1052,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
auth_table_len = 0; auth_table_len = 0;
auth_table_pos = 0; auth_table_pos = 0;
byte_t* auth_table; uint8_t *auth_table;
BigBuf_free(); 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); memset(auth_table, 0x00, AUTH_TABLE_LENGTH);
DbpString("Starting Hitag2 simulation"); DbpString("Starting Hitag2 simulation");
@ -1051,7 +1063,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
if (tag_mem_supplied) { if (tag_mem_supplied) {
DbpString("Loading hitag2 memory..."); DbpString("Loading hitag2 memory...");
memcpy((byte_t*)tag.sectors,data,48); memcpy((uint8_t*)tag.sectors, data, 48);
} }
uint32_t block = 0; uint32_t block = 0;
@ -1097,7 +1109,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
memset(rx, 0x00, sizeof(rx)); memset(rx, 0x00, sizeof(rx));
frame_count = 0; // frame_count = 0;
response = 0; response = 0;
overflow = 0; overflow = 0;
@ -1144,7 +1156,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
// Check if frame was captured // Check if frame was captured
if (rxlen > 4) { if (rxlen > 4) {
frame_count++; // frame_count++;
if (!bQuiet) { if (!bQuiet) {
if (!LogTraceHitag(rx, rxlen, response, 0, true)) { if (!LogTraceHitag(rx, rxlen, response, 0, true)) {
DbpString("Trace full"); DbpString("Trace full");
@ -1212,12 +1224,12 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
} }
void ReaderHitag(hitag_function htf, hitag_data *htd) { void ReaderHitag(hitag_function htf, hitag_data *htd) {
int frame_count; // int frame_count;
int response; int response;
byte_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0; size_t rxlen = 0;
byte_t txbuf[HITAG_FRAME_LEN]; uint8_t txbuf[HITAG_FRAME_LEN];
byte_t* tx = txbuf; uint8_t *tx = txbuf;
size_t txlen = 0; size_t txlen = 0;
int lastbit; int lastbit;
bool bSkip; bool bSkip;
@ -1246,6 +1258,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
bQuitTraceFull = false; bQuitTraceFull = false;
bQuiet = false; bQuiet = false;
bPwd = false; bPwd = false;
bAuthenticating = false;
} break; } break;
case RHT2F_AUTHENTICATE: { case RHT2F_AUTHENTICATE: {
DbpString("Authenticating using nr,ar pair:"); DbpString("Authenticating using nr,ar pair:");
@ -1332,7 +1345,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
frame_count = 0; // frame_count = 0;
response = 0; response = 0;
lastbit = 1; lastbit = 1;
@ -1363,7 +1376,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
// Check if frame was captured and store it // Check if frame was captured and store it
if (rxlen > 0) { if (rxlen > 0) {
frame_count++; // frame_count++;
if (!bQuiet) { if (!bQuiet) {
if (!LogTraceHitag(rx, rxlen, response, 0, false)) { if (!LogTraceHitag(rx, rxlen, response, 0, false)) {
DbpString("Trace full"); DbpString("Trace full");
@ -1380,7 +1393,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
tx = txbuf; tx = txbuf;
switch (htf) { switch (htf) {
case RHT2F_PASSWORD: { case RHT2F_PASSWORD: {
bStop = !hitag2_password(rx,rxlen,tx,&txlen); bStop = !hitag2_password(rx, rxlen, tx, &txlen, false);
} break; } break;
case RHT2F_AUTHENTICATE: { case RHT2F_AUTHENTICATE: {
bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen); bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen);
@ -1394,7 +1407,8 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
case RHT2F_UID_ONLY: { case RHT2F_UID_ONLY: {
bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen); bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen);
attempt_count++; //attempt 3 times to get uid then quit attempt_count++; //attempt 3 times to get uid then quit
if (!bStop && attempt_count == 3) bStop = true; if (!bStop && attempt_count == 3)
bStop = true;
} break; } break;
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
@ -1423,7 +1437,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
// Add transmitted frame to total count // Add transmitted frame to total count
if (txlen > 0) { if (txlen > 0) {
frame_count++; // frame_count++;
if (!bQuiet) { if (!bQuiet) {
// Store the frame in the trace // 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)) {
@ -1532,19 +1546,19 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
//Dbprintf("frame received: %d",frame_count); //Dbprintf("frame received: %d",frame_count);
//DbpString("All done"); //DbpString("All done");
if (bSuccessful) 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 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) { void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
int frame_count; // int frame_count;
int response; int response;
byte_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0; size_t rxlen = 0;
byte_t txbuf[HITAG_FRAME_LEN]; uint8_t txbuf[HITAG_FRAME_LEN];
byte_t* tx = txbuf; uint8_t *tx = txbuf;
size_t txlen = 0; size_t txlen = 0;
int lastbit; int lastbit;
bool bSkip; bool bSkip;
@ -1566,8 +1580,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
// Check configuration // Check configuration
switch (htf) { switch (htf) {
case WHT2F_CRYPTO: case WHT2F_CRYPTO: {
{
DbpString("Authenticating using key:"); DbpString("Authenticating using key:");
memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code.
memcpy(writedata, htd->crypto.data, 4); memcpy(writedata, htd->crypto.data, 4);
@ -1579,6 +1592,16 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
bQuitTraceFull = true; bQuitTraceFull = true;
writestate = WRITE_STATE_START; writestate = WRITE_STATE_START;
} break; } 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: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; return;
@ -1629,7 +1652,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
frame_count = 0; // frame_count = 0;
response = 0; response = 0;
lastbit = 1; lastbit = 1;
bStop = false; bStop = false;
@ -1660,7 +1683,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
// Check if frame was captured and store it // Check if frame was captured and store it
if (rxlen > 0) { if (rxlen > 0) {
frame_count++; // frame_count++;
if (!bQuiet) { if (!bQuiet) {
if (!LogTraceHitag(rx, rxlen, response, 0, false)) { if (!LogTraceHitag(rx, rxlen, response, 0, false)) {
DbpString("Trace full"); DbpString("Trace full");
@ -1679,6 +1702,10 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
case WHT2F_CRYPTO: { case WHT2F_CRYPTO: {
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true);
} break; } break;
case WHT2F_PASSWORD: {
bStop = !hitag2_password(rx, rxlen, tx, &txlen, true);
}
break;
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; return;
@ -1706,7 +1733,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
// Add transmitted frame to total count // Add transmitted frame to total count
if (txlen > 0) { if (txlen > 0) {
frame_count++; // frame_count++;
if (!bQuiet) { if (!bQuiet) {
// Store the frame in the trace // 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)) {
@ -1794,7 +1821,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
} else { } else {
// Dbprintf("DEBUG: Wierd2"); // Dbprintf("DEBUG: Wierd2");
errorCount++; errorCount++;
// Ignore wierd value, is to small to mean anything // Ignore wierd value, it is to small to mean anything
} }
} }
//if we saw over 100 wierd values break it probably isn't hitag... //if we saw over 100 wierd values break it probably isn't hitag...
@ -1806,8 +1833,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
} }
// Wait some extra time for flash to be programmed // 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; 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));
} }
@ -1821,5 +1847,5 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
//Dbprintf("frame received: %d",frame_count); //Dbprintf("frame received: %d",frame_count);
//DbpString("All done"); //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);
} }

View file

@ -261,14 +261,15 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog(""); PrintAndLog("");
PrintAndLog("Usage: hitag reader <Reader Function #>"); PrintAndLog("Usage: hitag reader <Reader Function #>");
PrintAndLog("Reader Functions:"); PrintAndLog("Reader Functions:");
PrintAndLog(" HitagS (0*)"); PrintAndLog(" HitagS (0*):");
PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag"); PrintAndLog(" 01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag"); PrintAndLog(" 02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag");
PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag"); PrintAndLog(" 03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag");
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag"); PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag");
PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)");
PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag1 (1*):");
PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" (not yet implemented)");
PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 21 <password> (password mode)"); PrintAndLog(" 21 <password> (password mode)");
PrintAndLog(" 22 <nr> <ar> (authentication)"); PrintAndLog(" 22 <nr> <ar> (authentication)");
PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low"); PrintAndLog(" 23 <key> (authentication) key is in format: ISK high + ISK low");
@ -389,28 +390,33 @@ int CmdLFHitagWP(const char *Cmd) {
hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10); hitag_function htf = param_get32ex(Cmd,0,0,10);
switch (htf) { switch (htf) {
case 03: { //WHTSF_CHALLENGE case WHTSF_CHALLENGE: {
num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr); num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10); c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data);
} break; } break;
case 04: case WHTSF_KEY:
case 24: case WHT2F_CRYPTO: {
{ //WHTSF_KEY
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
c.arg[2]= param_get32ex(Cmd, 2, 0, 10); c.arg[2]= param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data);
} break;
case WHT2F_PASSWORD: {
num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
c.arg[2] = param_get32ex(Cmd, 2, 0, 10);
num_to_bytes(param_get32ex(Cmd, 3, 0, 16), 4, htd->crypto.data);
} break; } break;
default: { default: {
PrintAndLog("Error: unkown writer function %d",htf); PrintAndLog("Error: unkown writer function %d",htf);
PrintAndLog("Hitag writer functions"); PrintAndLog("Hitag writer functions");
PrintAndLog(" HitagS (0*)"); PrintAndLog(" HitagS (0*):");
PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" 03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" 04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag1 (1*)");
PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" (not yet implemented)");
PrintAndLog(" Hitag2 (2*):");
PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); PrintAndLog(" 24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag");
PrintAndLog(" 27 <password> <page> <byte0...byte3> write page on a Hitag2 tag");
return 1; return 1;
} break; } break;
} }

View file

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