'lf hitag': some cleanup, some fixes

* #define Hitag2 commands
* whitespace
* add EOF wait time
* add powerup wait time
This commit is contained in:
pwpiwi 2019-08-09 18:30:12 +02:00
commit b7f9b71f5d
7 changed files with 352 additions and 272 deletions

View file

@ -26,6 +26,7 @@
#include "string.h" #include "string.h"
#include "BigBuf.h" #include "BigBuf.h"
#include "fpgaloader.h" #include "fpgaloader.h"
#include "protocols.h"
static bool bQuiet; static bool bQuiet;
@ -94,57 +95,39 @@ static uint64_t cipher_state;
// No warranties or guarantees of any kind. // No warranties or guarantees of any kind.
// This code is released into the public domain by its author. // 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: // Single bit Hitag2 functions:
#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) #define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
static u32 _f20 (const u64 x) static uint32_t _f20(const uint64_t x) {
{ uint32_t i5;
u32 i5;
i5 = ((ht2_f4a >> i4 (x, 1, 2, 4, 5)) & 1)* 1 i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
+ ((ht2_f4b >> i4 (x, 7,11,13,14)) & 1)* 2 + ((ht2_f4b >> i4(x, 7,11,13,14)) & 1) * 2
+ ((ht2_f4b >> i4 (x,16,20,22,25)) & 1)* 4 + ((ht2_f4b >> i4(x,16,20,22,25)) & 1) * 4
+ ((ht2_f4b >> i4 (x,27,28,30,32)) & 1)* 8 + ((ht2_f4b >> i4(x,27,28,30,32)) & 1) * 8
+ ((ht2_f4a >> i4 (x,33,42,43,45)) & 1)*16; + ((ht2_f4a >> i4(x,33,42,43,45)) & 1) * 16;
return (ht2_f5c >> i5) & 1; return (ht2_f5c >> i5) & 1;
} }
static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) static uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
{ uint32_t i;
u32 i; uint64_t x = ((key & 0xFFFF) << 32) + serial;
u64 x = ((key & 0xFFFF) << 32) + serial;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++) {
{
x >>= 1; 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; return x;
} }
static u64 _hitag2_round (u64 *state) static uint64_t _hitag2_round(uint64_t *state) {
{ uint64_t x = *state;
u64 x = *state;
x = (x >> 1) + x = (x >> 1) +
((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6)
@ -153,33 +136,29 @@ static u64 _hitag2_round (u64 *state)
^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47);
*state = x; *state = x;
return _f20 (x); return _f20(x);
} }
static u32 _hitag2_byte (u64 * x) static uint32_t _hitag2_byte(uint64_t *x) {
{ uint32_t i, c;
u32 i, c; for (i = 0, c = 0; i < 8; i++) {
c += (uint32_t) _hitag2_round(x) << (i^7);
for (i = 0, c = 0; i < 8; i++) c += (u32) _hitag2_round (x) << (i^7); }
return c; return c;
} }
static int hitag2_reset(void) static int hitag2_reset(void) {
{
tag.state = TAG_STATE_RESET; tag.state = TAG_STATE_RESET;
tag.crypto_active = 0; tag.crypto_active = 0;
return 0; return 0;
} }
static int hitag2_init(void) static int hitag2_init(void) {
{
// memcpy(&tag, &resetdata, sizeof(tag));
hitag2_reset(); hitag2_reset();
return 0; return 0;
} }
static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_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) |
((uint64_t)tag->sectors[1][0] << 16) | ((uint64_t)tag->sectors[1][0] << 16) |
@ -194,11 +173,10 @@ static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv)
(((uint32_t)(iv[1])) << 8) | (((uint32_t)(iv[1])) << 8) |
(((uint32_t)(iv[2])) << 16) | (((uint32_t)(iv[2])) << 16) |
(((uint32_t)(iv[3])) << 24); (((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 uint8_t *authenticator_is) static int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) {
{
uint8_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);
@ -207,11 +185,10 @@ static int hitag2_cipher_authenticate(uint64_t* cs, const uint8_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, uint8_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);
for(i=0; i<bits; i++) data[bytes] ^= _hitag2_round(cs) << (7-i); for (i = 0; i < bits; i++) data[bytes] ^= _hitag2_round(cs) << (7-i);
return 0; return 0;
} }
@ -221,9 +198,6 @@ static int hitag2_cipher_transcrypt(uint64_t* cs, uint8_t *data, unsigned int by
// T0 = TIMER_CLOCK1 / 125000 = 192 // T0 = TIMER_CLOCK1 / 125000 = 192
#define T0 192 #define T0 192
#define SHORT_COIL() LOW(GPIO_SSC_DOUT)
#define OPEN_COIL() HIGH(GPIO_SSC_DOUT)
#define HITAG_FRAME_LEN 20 #define HITAG_FRAME_LEN 20
#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ #define HITAG_T_STOP 36 /* T_EOF should be > 36 */
#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ #define HITAG_T_LOW 8 /* T_LOW should be 4..10 */
@ -249,7 +223,6 @@ static int hitag2_cipher_transcrypt(uint64_t* cs, uint8_t *data, unsigned int by
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_THREE_HALF 41
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
static void hitag_send_bit(int bit) { static void hitag_send_bit(int bit) {
LED_A_ON(); LED_A_ON();
// Reset clock for the next bit // Reset clock for the next bit
@ -288,7 +261,6 @@ static void hitag_send_frame(const uint8_t *frame, size_t frame_len)
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
} }
static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_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]; uint8_t rx_air[HITAG_FRAME_LEN];
@ -307,7 +279,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
// Received 11000 from the reader, request for UID, send UID // Received 11000 from the reader, request for UID, send UID
case 05: { case 05: {
// Always send over the air in the clear plaintext mode // Always send over the air in the clear plaintext mode
if (rx_air[0] != 0xC0) { if (rx_air[0] != HITAG2_START_AUTH) {
// Unknown frame ? // Unknown frame ?
return; return;
} }
@ -328,13 +300,13 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
switch (rx[0] & 0xC6) { switch (rx[0] & 0xC6) {
// Read command: 11xx x00y // Read command: 11xx x00y
case 0xC0: case HITAG2_READ_PAGE:
memcpy(tx, tag.sectors[sector], 4); memcpy(tx, tag.sectors[sector], 4);
*txlen = 32; *txlen = 32;
break; break;
// Inverted Read command: 01xx x10y // Inverted Read command: 01xx x10y
case 0x44: case HITAG2_READ_PAGE_INVERTED:
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
tx[i] = tag.sectors[sector][i] ^ 0xff; tx[i] = tag.sectors[sector][i] ^ 0xff;
} }
@ -342,7 +314,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
break; break;
// Write command: 10xx x01y // Write command: 10xx x01y
case 0x82: case HITAG2_WRITE_PAGE:
// Prepare write, acknowledge by repeating command // Prepare write, acknowledge by repeating command
memcpy(tx, rx, nbytes(rxlen)); memcpy(tx, rx, nbytes(rxlen));
*txlen = rxlen; *txlen = rxlen;
@ -426,21 +398,18 @@ static void hitag_reader_send_bit(int bit) {
// Enable modulation, which means, drop the field // Enable modulation, which means, drop the field
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
// Wait for 4-10 times the carrier period // t_low = 4...10 carrier periods
while (AT91C_BASE_TC0->TC_CV < T0*6); while (AT91C_BASE_TC0->TC_CV < T0*6);
// SpinDelayUs(8*8);
// Disable modulation, just activates the field again // Disable modulation, just activates the field again
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
if (bit == 0) { if (bit == 0) {
// Zero bit: |_-| // Zero bit: |_-|, T[0] = 18...22 carrier periods
while (AT91C_BASE_TC0->TC_CV < T0*22); while (AT91C_BASE_TC0->TC_CV < T0*22);
// SpinDelayUs(16*8);
} else { } else {
// One bit: |_--| // One bit: |_--|, T[1] = 26...32 carrier periods
while (AT91C_BASE_TC0->TC_CV < T0*28); while (AT91C_BASE_TC0->TC_CV < T0*28);
// SpinDelayUs(22*8);
} }
LED_A_OFF(); LED_A_OFF();
} }
@ -456,10 +425,12 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len)
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
// Enable modulation, which means, drop the field // Enable modulation, which means, drop the field
HIGH(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
// Wait for 4-10 times the carrier period // t_low = 4...10 carrier periods
while (AT91C_BASE_TC0->TC_CV < T0*6); while (AT91C_BASE_TC0->TC_CV < T0*6);
// Disable modulation, just activates the field again // Disable modulation, just activates the field again
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
// t_stop > 36 carrier periods
while (AT91C_BASE_TC0->TC_CV < T0*36);
} }
size_t blocknr; size_t blocknr;
@ -471,15 +442,15 @@ size_t blocknr;
static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
switch (writestate) { switch (writestate) {
case WRITE_STATE_START: case WRITE_STATE_START:
*txlen = 10; tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2);
tx[0] = 0x82 | (blocknr << 3) | ((blocknr^7) >> 2);
tx[1] = ((blocknr^7) << 6); tx[1] = ((blocknr^7) << 6);
*txlen = 10;
writestate = WRITE_STATE_PAGENUM_WRITTEN; writestate = WRITE_STATE_PAGENUM_WRITTEN;
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] == (HITAG2_WRITE_PAGE | (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);
@ -527,8 +498,8 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
DbpString("Password failed!"); DbpString("Password failed!");
return false; return false;
} }
tx[0] = HITAG2_START_AUTH;
*txlen = 5; *txlen = 5;
memcpy(tx, "\xc0", nbytes(*txlen));
} }
break; break;
@ -558,9 +529,9 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
bSuccessful = true; bSuccessful = true;
return false; return false;
} }
*txlen = 10; tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr^7) >> 2);
tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2);
tx[1] = ((blocknr^7) << 6); tx[1] = ((blocknr^7) << 6);
*txlen = 10;
} }
} }
break; break;
@ -620,8 +591,8 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
bCrypto = false; bCrypto = false;
} }
} else { } else {
tx[0] = HITAG2_START_AUTH;
*txlen = 5; *txlen = 5;
memcpy(tx, "\xc0", nbytes(*txlen));
} }
break; break;
} }
@ -630,8 +601,8 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
if (!bCrypto) { 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; 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; 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)); 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); cipher_state = _hitag2_init(REV64(ui64key), REV32(ui32uid), 0);
memset(tx, 0x00, 4); memset(tx, 0x00, 4);
memset(tx+4, 0xff, 4); memset(tx+4, 0xff, 4);
hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0);
@ -660,18 +631,20 @@ static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *
bSuccessful = true; bSuccessful = true;
return false; return false;
} else { } else {
*txlen = 10; tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2);
tx[0] = 0xc0 | (blocknr << 3) | ((blocknr ^ 7) >> 2);
tx[1] = ((blocknr ^ 7) << 6); tx[1] = ((blocknr ^ 7) << 6);
*txlen = 10;
} }
} }
} break; }
break;
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Unknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; }
break;
} }
} }
@ -698,34 +671,36 @@ static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, si
DbpString("Authentication failed!"); DbpString("Authentication failed!");
return false; return false;
} }
tx[0] = HITAG2_START_AUTH;
*txlen = 5; *txlen = 5;
memcpy(tx, "\xc0", nbytes(*txlen)); }
} break; break;
// Received UID, crypto tag answer // Received UID, crypto tag answer
case 32: { case 32: {
if (!bCrypto) { if (!bCrypto) {
*txlen = 64;
memcpy(tx, NrAr, 8); memcpy(tx, NrAr, 8);
*txlen = 64;
bCrypto = true; bCrypto = true;
} else { } else {
DbpString("Authentication successful!"); DbpString("Authentication successful!");
// We are done... for now // We are done... for now
return false; return false;
} }
} break; }
break;
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Unknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; }
break;
} }
return true; return true;
} }
static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_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
@ -752,9 +727,10 @@ static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *
// Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) // 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); 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 // Received UID, crypto tag answer, or read block response
case 32: { case 32: {
@ -771,12 +747,14 @@ static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *
auth_table_pos += 8; auth_table_pos += 8;
memcpy(NrAr, auth_table+auth_table_pos, 8); memcpy(NrAr, auth_table+auth_table_pos, 8);
} }
} break; }
break;
default: { default: {
Dbprintf("Unknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; }
break;
} }
return true; return true;
@ -791,9 +769,10 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
// No answer, try to resurrect // No answer, try to resurrect
case 0: { case 0: {
// Just starting or if there is no answer // Just starting or if there is no answer
tx[0] = HITAG2_START_AUTH;
*txlen = 5; *txlen = 5;
memcpy(tx, "\xc0", nbytes(*txlen)); }
} break; break;
// Received UID // Received UID
case 32: { case 32: {
// Check if we received answer tag (at) // Check if we received answer tag (at)
@ -809,12 +788,14 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
bSuccessful = true; bSuccessful = true;
return false; return false;
} }
} break; }
break;
// Unexpected response // Unexpected response
default: { default: {
Dbprintf("Unknown frame length: %d",rxlen); Dbprintf("Unknown frame length: %d",rxlen);
return false; return false;
} break; }
break;
} }
return true; return true;
} }
@ -852,7 +833,6 @@ void SnoopHitag(uint32_t type) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
RELAY_OFF();
// Configure output pin that is connected to the FPGA (for modulating) // Configure output pin that is connected to the FPGA (for modulating)
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
@ -870,8 +850,7 @@ void SnoopHitag(uint32_t type) {
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // 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. // 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 = 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;
// Enable and reset counter // Enable and reset counter
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
@ -947,7 +926,7 @@ void SnoopHitag(uint32_t type) {
} }
// Capture the T0 periods that have passed since last communication or field drop (reset) // 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 |-_| // We always recieve a 'one' first, which has the falling edge after a half period |-_|
response = ra-HITAG_T_TAG_HALF_PERIOD; response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101) // Manchester coding example |-_|_-|-_| (101)
rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rx[rxlen / 8] |= 0 << (7-(rxlen%8));
@ -1033,7 +1012,7 @@ void SnoopHitag(uint32_t type) {
// DbpString("All done"); // DbpString("All done");
} }
void SimulateHitagTag(bool tag_mem_supplied, uint8_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;
@ -1054,7 +1033,7 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data) {
auth_table_pos = 0; auth_table_pos = 0;
uint8_t *auth_table; uint8_t *auth_table;
BigBuf_free(); BigBuf_free();
auth_table = (uint8_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); auth_table = 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");
@ -1080,7 +1059,6 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
RELAY_OFF();
// Configure output pin that is connected to the FPGA (for modulating) // Configure output pin that is connected to the FPGA (for modulating)
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
@ -1259,7 +1237,8 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
bQuiet = false; bQuiet = false;
bPwd = false; bPwd = false;
bAuthenticating = false; bAuthenticating = false;
} break; }
break;
case RHT2F_AUTHENTICATE: { case RHT2F_AUTHENTICATE: {
DbpString("Authenticating using nr,ar pair:"); DbpString("Authenticating using nr,ar pair:");
memcpy(NrAr, htd->auth.NrAr, 8); memcpy(NrAr, htd->auth.NrAr, 8);
@ -1268,7 +1247,8 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
bCrypto = false; bCrypto = false;
bAuthenticating = false; bAuthenticating = false;
bQuitTraceFull = true; bQuitTraceFull = true;
} break; }
break;
case RHT2F_CRYPTO: case RHT2F_CRYPTO:
{ {
DbpString("Authenticating using key:"); DbpString("Authenticating using key:");
@ -1279,7 +1259,8 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
bCrypto = false; bCrypto = false;
bAuthenticating = false; bAuthenticating = false;
bQuitTraceFull = true; bQuitTraceFull = true;
} break; }
break;
case RHT2F_TEST_AUTH_ATTEMPTS: { case RHT2F_TEST_AUTH_ATTEMPTS: {
Dbprintf("Testing %d authentication attempts", (auth_table_len/8)); Dbprintf("Testing %d authentication attempts", (auth_table_len/8));
auth_table_pos = 0; auth_table_pos = 0;
@ -1287,18 +1268,21 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
bQuitTraceFull = false; bQuitTraceFull = false;
bQuiet = false; bQuiet = false;
bCrypto = false; bCrypto = false;
} break; }
break;
case RHT2F_UID_ONLY: { case RHT2F_UID_ONLY: {
blocknr = 0; blocknr = 0;
bQuiet = false; bQuiet = false;
bCrypto = false; bCrypto = false;
bAuthenticating = false; bAuthenticating = false;
bQuitTraceFull = true; bQuitTraceFull = true;
} break; }
break;
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; return;
} break; }
break;
} }
LED_D_ON(); LED_D_ON();
@ -1314,14 +1298,10 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
// Set Frequency divisor which will drive the FPGA and analog mux selection // Set Frequency divisor which will drive the FPGA and analog mux selection
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
RELAY_OFF();
// Disable modulation at default, which means enable the field // Disable modulation at default, which means enable the field
LOW(GPIO_SSC_DOUT); 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 // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
@ -1367,11 +1347,15 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
//DbpString("Configured for hitag2 reader"); //DbpString("Configured for hitag2 reader");
} else { } else {
Dbprintf("Error, unknown hitag reader type: %d", htf); Dbprintf("Error, unknown hitag reader type: %d", htf);
return; goto out;
} }
// 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; uint8_t attempt_count = 0;
while (!bStop && !BUTTON_PRESS()) { while (!bStop && !BUTTON_PRESS()) {
// Watchdog hit
WDT_HIT(); WDT_HIT();
// Check if frame was captured and store it // Check if frame was captured and store it
@ -1394,26 +1378,31 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
switch (htf) { switch (htf) {
case RHT2F_PASSWORD: { case RHT2F_PASSWORD: {
bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); 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);
} break; }
break;
case RHT2F_CRYPTO: { case RHT2F_CRYPTO: {
bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false); bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false);
} break; }
break;
case RHT2F_TEST_AUTH_ATTEMPTS: { case RHT2F_TEST_AUTH_ATTEMPTS: {
bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen); bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen);
} break; }
break;
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) if (!bStop && attempt_count == 3)
bStop = true; bStop = true;
} break; }
break;
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; goto out;
} break; }
} }
// Send and store the reader command // Send and store the reader command
@ -1479,7 +1468,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
} }
// Capture the T0 periods that have passed since last communication or field drop (reset) // 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 |-_| // We always recieve a 'one' first, which has the falling edge after a half period |-_|
response = ra-HITAG_T_TAG_HALF_PERIOD; response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101) // Manchester coding example |-_|_-|-_| (101)
@ -1536,6 +1525,8 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
} }
} }
} }
out:
//Dbprintf("DEBUG: Done waiting for frame"); //Dbprintf("DEBUG: Done waiting for frame");
LED_B_OFF(); LED_B_OFF();
@ -1549,10 +1540,9 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_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;
uint8_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
@ -1591,7 +1581,8 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
bAuthenticating = false; bAuthenticating = false;
bQuitTraceFull = true; bQuitTraceFull = true;
writestate = WRITE_STATE_START; writestate = WRITE_STATE_START;
} break; }
break;
case WHT2F_PASSWORD: { case WHT2F_PASSWORD: {
DbpString("Authenticating using password:"); DbpString("Authenticating using password:");
memcpy(password, htd->pwd.password, 4); memcpy(password, htd->pwd.password, 4);
@ -1601,11 +1592,13 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
bPwd = false; bPwd = false;
bAuthenticating = false; bAuthenticating = false;
writestate = WRITE_STATE_START; writestate = WRITE_STATE_START;
} break; }
break;
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; return;
} break; }
break;
} }
LED_D_ON(); LED_D_ON();
@ -1621,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 // Set Frequency divisor which will drive the FPGA and analog mux selection
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
RELAY_OFF();
// Disable modulation at default, which means enable the field // Disable modulation at default, which means enable the field
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
@ -1678,7 +1670,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
return; return;
} }
while (!bStop && !BUTTON_PRESS()) { while (!bStop && !BUTTON_PRESS()) {
// Watchdog hit
WDT_HIT(); WDT_HIT();
// Check if frame was captured and store it // Check if frame was captured and store it
@ -1701,7 +1693,8 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
switch (htf) { switch (htf) {
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: { case WHT2F_PASSWORD: {
bStop = !hitag2_password(rx, rxlen, tx, &txlen, true); bStop = !hitag2_password(rx, rxlen, tx, &txlen, true);
} }
@ -1709,7 +1702,8 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
default: { default: {
Dbprintf("Error, unknown function: %d", htf); Dbprintf("Error, unknown function: %d", htf);
return; return;
} break; }
break;
} }
// Send and store the reader command // Send and store the reader command
@ -1821,10 +1815,10 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
} else { } else {
// Dbprintf("DEBUG: Wierd2"); // Dbprintf("DEBUG: Wierd2");
errorCount++; errorCount++;
// Ignore wierd value, it 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 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 // 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 (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) {

View file

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

View file

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

View file

@ -21,12 +21,18 @@
#define LED_ORANGE 2 #define LED_ORANGE 2
#define LED_GREEN 4 #define LED_GREEN 4
#define LED_RED2 8 #define LED_RED2 8
#define BUTTON_HOLD 1 #define BUTTON_HOLD 1
#define BUTTON_NO_CLICK 0 #define BUTTON_NO_CLICK 0
#define BUTTON_SINGLE_CLICK -1 #define BUTTON_SINGLE_CLICK -1
#define BUTTON_DOUBLE_CLICK -2 #define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99 #define BUTTON_ERROR -99
#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7))
#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8))
#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16))
#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32))
void print_result(char *name, uint8_t *buf, size_t len); void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits); size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits); uint32_t SwapBits(uint32_t value, int nrbits);

View file

@ -22,14 +22,12 @@
#include "hitag.h" #include "hitag.h"
#include "cmdmain.h" #include "cmdmain.h"
static int CmdHelp(const char *Cmd); static size_t nbytes(size_t nbits) {
return (nbits/8) + ((nbits%8)>0);
size_t nbytes(size_t nbits) {
return (nbits/8)+((nbits%8)>0);
} }
int CmdLFHitagList(const char *Cmd)
{ static int CmdLFHitagList(const char *Cmd) {
uint8_t *got = malloc(USB_CMD_DATA_SIZE); uint8_t *got = malloc(USB_CMD_DATA_SIZE);
// Query for the actual size of the trace // Query for the actual size of the trace
UsbCommand response; UsbCommand response;
@ -168,13 +166,15 @@ int CmdLFHitagList(const char *Cmd)
return 0; return 0;
} }
int CmdLFHitagSnoop(const char *Cmd) {
static int CmdLFHitagSnoop(const char *Cmd) {
UsbCommand c = {CMD_SNOOP_HITAG}; UsbCommand c = {CMD_SNOOP_HITAG};
SendCommand(&c); SendCommand(&c);
return 0; return 0;
} }
int CmdLFHitagSim(const char *Cmd) {
static int CmdLFHitagSim(const char *Cmd) {
UsbCommand c = {CMD_SIMULATE_HITAG}; UsbCommand c = {CMD_SIMULATE_HITAG};
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
@ -207,47 +207,105 @@ int CmdLFHitagSim(const char *Cmd) {
return 0; return 0;
} }
static bool getHitagUid(uint32_t *uid) {
// ToDo: this is for Hitag2 only (??)
UsbCommand c = {CMD_READER_HITAG, {RHT2F_UID_ONLY}};
SendCommand(&c);
UsbCommand resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return false;
}
if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID");
return false;
}
if (uid)
*uid = bytes_to_num(resp.d.asBytes, 4);
return true;
}
static int CmdLFHitagInfo(const char *Cmd) {
char ctmp = param_getchar(Cmd, 0);
if (ctmp != '\0') {
PrintAndLog("Usage: lf hitag info [h]");
PrintAndLog("Options:");
PrintAndLog(" h This help");
PrintAndLog("Examples:");
PrintAndLog(" lf hitag info");
return 0;
}
// read UID
uint32_t uid = 0;
if (getHitagUid(&uid) == false)
return 1;
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
// how to detemine Hitag types?
// read block3, get configuration byte.
// PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
// common configurations.
// printHitagConfiguration(0x06);
//printHitagConfiguration( 0x0E );
//printHitagConfiguration( 0x02 );
//printHitagConfiguration( 0x00 );
//printHitagConfiguration( 0x04 );
return 0;
}
int CmdLFHitagReader(const char *Cmd) { int CmdLFHitagReader(const char *Cmd) {
UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}}; UsbCommand c = {CMD_READER_HITAG};
hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10); hitag_function htf = param_get32ex(Cmd, 0, 0, 10);
switch (htf) { switch (htf) {
case 01: { //RHTSF_CHALLENGE case 01: { //RHTSF_CHALLENGE
c = (UsbCommand){ CMD_READ_HITAG_S }; c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode
} break; } break;
case 02: { //RHTSF_KEY case 02: { //RHTSF_KEY
c = (UsbCommand){ CMD_READ_HITAG_S }; c = (UsbCommand){ CMD_READ_HITAG_S };
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode
} break; } break;
case 03: { //RHTSF_CHALLENGE BLOCK case 03: { //RHTSF_CHALLENGE BLOCK
c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; c = (UsbCommand){ CMD_READ_HITAG_S_BLK };
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode
} break; } break;
case 04: { //RHTSF_KEY BLOCK case 04: { //RHTSF_KEY BLOCK
c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; c = (UsbCommand){ CMD_READ_HITAG_S_BLK };
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage
c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode
} break; } break;
case RHT2F_PASSWORD: { case RHT2F_PASSWORD: {
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->pwd.password);
} break; } break;
case RHT2F_AUTHENTICATE: { case RHT2F_AUTHENTICATE: {
num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr);
num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4);
} break; } break;
case RHT2F_CRYPTO: { case RHT2F_CRYPTO: {
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key);
// num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); // num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4);
} break; } break;
case RHT2F_TEST_AUTH_ATTEMPTS: { case RHT2F_TEST_AUTH_ATTEMPTS: {
@ -287,10 +345,16 @@ int CmdLFHitagReader(const char *Cmd) {
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
WaitForResponse(CMD_ACK,&resp); if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument // Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1; if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return 1;
}
uint32_t id = bytes_to_num(resp.d.asBytes,4); uint32_t id = bytes_to_num(resp.d.asBytes,4);
@ -313,12 +377,11 @@ int CmdLFHitagReader(const char *Cmd) {
PrintAndLog("Succesfully saved tag memory to [%s]",filename); PrintAndLog("Succesfully saved tag memory to [%s]",filename);
} }
return 0; return 0;
} }
int CmdLFHitagSimS(const char *Cmd) { static int CmdLFHitagSimS(const char *Cmd) {
UsbCommand c = { CMD_SIMULATE_HITAG_S }; UsbCommand c = { CMD_SIMULATE_HITAG_S };
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf; FILE* pf;
@ -351,7 +414,8 @@ int CmdLFHitagSimS(const char *Cmd) {
return 0; return 0;
} }
int CmdLFHitagCheckChallenges(const char *Cmd) {
static int CmdLFHitagCheckChallenges(const char *Cmd) {
UsbCommand c = { CMD_TEST_HITAGS_TRACES }; UsbCommand c = { CMD_TEST_HITAGS_TRACES };
char filename[FILE_PATH_SIZE] = { 0x00 }; char filename[FILE_PATH_SIZE] = { 0x00 };
FILE* pf; FILE* pf;
@ -385,7 +449,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
} }
int CmdLFHitagWP(const char *Cmd) { static int CmdLFHitagWriter(const char *Cmd) {
UsbCommand c = { CMD_WR_HITAG_S }; UsbCommand c = { CMD_WR_HITAG_S };
hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_data* htd = (hitag_data*)c.d.asBytes;
hitag_function htf = param_get32ex(Cmd,0,0,10); hitag_function htf = param_get32ex(Cmd,0,0,10);
@ -427,35 +491,44 @@ int CmdLFHitagWP(const char *Cmd) {
SendCommand(&c); SendCommand(&c);
UsbCommand resp; UsbCommand resp;
WaitForResponse(CMD_ACK,&resp); if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1;
}
// Check the return status, stored in the first argument // Check the return status, stored in the first argument
if (resp.arg[0] == false) return 1; if (resp.arg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
return 1;
}
return 0; return 0;
} }
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
{"list", CmdLFHitagList, 1, "<outfile> List Hitag trace history"}, {"list", CmdLFHitagList, 0, "<outfile> List Hitag trace history"},
{"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, {"info", CmdLFHitagInfo, 0, "Tag information" },
{"sim", CmdLFHitagSim, 1, "<infile> Simulate Hitag transponder"}, {"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"},
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, {"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"},
{"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, {"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"},
{"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" }, {"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" },
{"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> <tagmode> test all challenges" }, { {"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" },
NULL,NULL, 0, NULL } {"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" },
{ NULL, NULL, 0, NULL }
}; };
int CmdLFHitag(const char *Cmd)
{
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd) static int CmdHelp(const char *Cmd) {
{
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return 0;
} }
int CmdLFHitag(const char *Cmd) {
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

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

View file

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