mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-11 15:56:09 -07:00
added hitag2 reading in crypto mode functionality
This commit is contained in:
parent
2d495a814d
commit
bde10a5057
3 changed files with 126 additions and 26 deletions
133
armsrc/hitag2.c
133
armsrc/hitag2.c
|
@ -25,6 +25,7 @@
|
||||||
static bool bQuiet;
|
static bool bQuiet;
|
||||||
|
|
||||||
bool bCrypto;
|
bool bCrypto;
|
||||||
|
bool bAuthenticating;
|
||||||
bool bPwd;
|
bool bPwd;
|
||||||
|
|
||||||
struct hitag2_tag {
|
struct hitag2_tag {
|
||||||
|
@ -41,8 +42,7 @@ struct hitag2_tag {
|
||||||
byte_t sectors[12][4];
|
byte_t sectors[12][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hitag2_tag tag;
|
static struct hitag2_tag tag = {
|
||||||
static const struct hitag2_tag resetdata = {
|
|
||||||
.state = TAG_STATE_RESET,
|
.state = TAG_STATE_RESET,
|
||||||
.sectors = { // Password mode: | Crypto mode:
|
.sectors = { // Password mode: | Crypto mode:
|
||||||
[0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID
|
[0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID
|
||||||
|
@ -73,6 +73,8 @@ size_t auth_table_len = AUTH_TABLE_LENGTH;
|
||||||
|
|
||||||
byte_t password[4];
|
byte_t password[4];
|
||||||
byte_t NrAr[8];
|
byte_t NrAr[8];
|
||||||
|
byte_t key[8];
|
||||||
|
uint64_t cipher_state;
|
||||||
|
|
||||||
/* Following is a modified version of cryptolib.com/ciphers/hitag2/ */
|
/* 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.
|
// Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007.
|
||||||
|
@ -163,23 +165,23 @@ int hitag2_reset(void)
|
||||||
|
|
||||||
int hitag2_init(void)
|
int hitag2_init(void)
|
||||||
{
|
{
|
||||||
memcpy(&tag, &resetdata, sizeof(tag));
|
// memcpy(&tag, &resetdata, sizeof(tag));
|
||||||
hitag2_reset();
|
hitag2_reset();
|
||||||
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 byte_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) |
|
||||||
((uint64_t)tag->sectors[1][1] << 24) |
|
((uint64_t)tag->sectors[1][1] << 24) |
|
||||||
((uint64_t)tag->sectors[1][2] << 32) |
|
((uint64_t)tag->sectors[1][2] << 32) |
|
||||||
((uint64_t)tag->sectors[1][3] << 40);
|
((uint64_t)tag->sectors[1][3] << 40);
|
||||||
uint32_t uid = ((uint32_t)tag->sectors[0][0]) |
|
uint32_t uid = ((uint32_t)tag->sectors[0][0]) |
|
||||||
((uint32_t)tag->sectors[0][1] << 8) |
|
((uint32_t)tag->sectors[0][1] << 8) |
|
||||||
((uint32_t)tag->sectors[0][2] << 16) |
|
((uint32_t)tag->sectors[0][2] << 16) |
|
||||||
((uint32_t)tag->sectors[0][3] << 24);
|
((uint32_t)tag->sectors[0][3] << 24);
|
||||||
uint32_t iv_ = (((uint32_t)(iv[0]))) |
|
uint32_t iv_ = (((uint32_t)(iv[0]))) |
|
||||||
(((uint32_t)(iv[1])) << 8) |
|
(((uint32_t)(iv[1])) << 8) |
|
||||||
(((uint32_t)(iv[2])) << 16) |
|
(((uint32_t)(iv[2])) << 16) |
|
||||||
|
@ -489,7 +491,7 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen)
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// Unexpected response
|
// Unexpected response
|
||||||
default: {
|
default: {
|
||||||
Dbprintf("Uknown frame length: %d",rxlen);
|
Dbprintf("Uknown frame length: %d",rxlen);
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
|
@ -497,6 +499,78 @@ bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) {
|
||||||
|
// Reset the transmission frame length
|
||||||
|
*txlen = 0;
|
||||||
|
|
||||||
|
if(bCrypto) {
|
||||||
|
hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find out which command was send by selecting on length (in bits)
|
||||||
|
switch (rxlen) {
|
||||||
|
// No answer, try to resurrect
|
||||||
|
case 0: {
|
||||||
|
// Stop if there is no answer while we are in crypto mode (after sending NrAr)
|
||||||
|
if (bCrypto) {
|
||||||
|
DbpString("Authentication failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*txlen = 5;
|
||||||
|
memcpy(tx,"\xc0",nbytes(*txlen));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Received UID, crypto tag answer
|
||||||
|
case 32: {
|
||||||
|
if (!bCrypto) {
|
||||||
|
uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40;
|
||||||
|
uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24;
|
||||||
|
cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0);
|
||||||
|
memset(tx,0x00,4);
|
||||||
|
memset(tx+4,0xff,4);
|
||||||
|
hitag2_cipher_transcrypt(&cipher_state,tx+4,4,0);
|
||||||
|
*txlen = 64;
|
||||||
|
bCrypto = true;
|
||||||
|
bAuthenticating = true;
|
||||||
|
} else {
|
||||||
|
// Check if we received answer tag (at)
|
||||||
|
if (bAuthenticating) {
|
||||||
|
bAuthenticating = false;
|
||||||
|
} else {
|
||||||
|
// Store the received block
|
||||||
|
memcpy(tag.sectors[blocknr],rx,4);
|
||||||
|
blocknr++;
|
||||||
|
}
|
||||||
|
if (blocknr > 7) {
|
||||||
|
DbpString("Read succesful!");
|
||||||
|
// We are done... for now
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(bCrypto) {
|
||||||
|
// We have to return now to avoid double encryption
|
||||||
|
if (!bAuthenticating) {
|
||||||
|
hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) {
|
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;
|
||||||
|
@ -521,7 +595,7 @@ bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txl
|
||||||
memcpy(tx,NrAr,8);
|
memcpy(tx,NrAr,8);
|
||||||
bCrypto = true;
|
bCrypto = true;
|
||||||
} else {
|
} else {
|
||||||
DbpString("Read succesful!");
|
DbpString("Authentication succesful!");
|
||||||
// We are done... for now
|
// We are done... for now
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -807,8 +881,8 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
|
||||||
bQuiet = false;
|
bQuiet = false;
|
||||||
|
|
||||||
// Clean up trace and prepare it for storing frames
|
// Clean up trace and prepare it for storing frames
|
||||||
iso14a_set_tracing(TRUE);
|
iso14a_set_tracing(TRUE);
|
||||||
iso14a_clear_trace();
|
iso14a_clear_trace();
|
||||||
auth_table_len = 0;
|
auth_table_len = 0;
|
||||||
auth_table_pos = 0;
|
auth_table_pos = 0;
|
||||||
memset(auth_table, 0x00, AUTH_TABLE_LENGTH);
|
memset(auth_table, 0x00, AUTH_TABLE_LENGTH);
|
||||||
|
@ -992,27 +1066,39 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
|
||||||
bool bQuitTraceFull = false;
|
bool bQuitTraceFull = false;
|
||||||
|
|
||||||
// Clean up trace and prepare it for storing frames
|
// Clean up trace and prepare it for storing frames
|
||||||
iso14a_set_tracing(TRUE);
|
iso14a_set_tracing(TRUE);
|
||||||
iso14a_clear_trace();
|
iso14a_clear_trace();
|
||||||
DbpString("Starting Hitag reader family");
|
DbpString("Starting Hitag reader family");
|
||||||
|
|
||||||
// Check configuration
|
// Check configuration
|
||||||
switch(htf) {
|
switch(htf) {
|
||||||
case RHT2F_PASSWORD: {
|
case RHT2F_PASSWORD: {
|
||||||
Dbprintf("List identifier in password mode");
|
Dbprintf("List identifier in password mode");
|
||||||
memcpy(password,htd->pwd.password,4);
|
memcpy(password,htd->pwd.password,4);
|
||||||
blocknr = 0;
|
blocknr = 0;
|
||||||
bQuitTraceFull = false;
|
bQuitTraceFull = false;
|
||||||
bQuiet = false;
|
bQuiet = false;
|
||||||
bPwd = false;
|
bPwd = false;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case RHT2F_AUTHENTICATE: {
|
case RHT2F_AUTHENTICATE: {
|
||||||
DbpString("Authenticating in crypto mode");
|
DbpString("Authenticating using nr,ar pair:");
|
||||||
memcpy(NrAr,htd->auth.NrAr,8);
|
memcpy(NrAr,htd->auth.NrAr,8);
|
||||||
Dbprintf("Reader-challenge:");
|
|
||||||
Dbhexdump(8,NrAr,false);
|
Dbhexdump(8,NrAr,false);
|
||||||
bQuiet = false;
|
bQuiet = false;
|
||||||
bCrypto = false;
|
bCrypto = false;
|
||||||
|
bAuthenticating = false;
|
||||||
|
bQuitTraceFull = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case RHT2F_CRYPTO: {
|
||||||
|
DbpString("Authenticating using key:");
|
||||||
|
memcpy(key,htd->crypto.key,6);
|
||||||
|
Dbhexdump(6,key,false);
|
||||||
|
blocknr = 0;
|
||||||
|
bQuiet = false;
|
||||||
|
bCrypto = false;
|
||||||
|
bAuthenticating = false;
|
||||||
bQuitTraceFull = true;
|
bQuitTraceFull = true;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -1125,6 +1211,9 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
|
||||||
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: {
|
||||||
|
bStop = !hitag2_crypto(rx,rxlen,tx,&txlen);
|
||||||
|
} 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;
|
||||||
|
|
|
@ -143,7 +143,7 @@ int CmdLFHitagSnoop(const char *Cmd) {
|
||||||
|
|
||||||
int CmdLFHitagSim(const char *Cmd) {
|
int CmdLFHitagSim(const char *Cmd) {
|
||||||
UsbCommand c = {CMD_SIMULATE_HITAG};
|
UsbCommand c = {CMD_SIMULATE_HITAG};
|
||||||
char filename[256];
|
char filename[256] = { 0x00 };
|
||||||
FILE* pf;
|
FILE* pf;
|
||||||
bool tag_mem_supplied;
|
bool tag_mem_supplied;
|
||||||
|
|
||||||
|
@ -184,6 +184,10 @@ int CmdLFHitagReader(const char *Cmd) {
|
||||||
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: {
|
||||||
|
num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key);
|
||||||
|
// num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4);
|
||||||
|
} break;
|
||||||
case RHT2F_TEST_AUTH_ATTEMPTS: {
|
case RHT2F_TEST_AUTH_ATTEMPTS: {
|
||||||
// No additional parameters needed
|
// No additional parameters needed
|
||||||
} break;
|
} break;
|
||||||
|
@ -195,6 +199,7 @@ int CmdLFHitagReader(const char *Cmd) {
|
||||||
PrintAndLog(" Hitag2 (2*)",htf);
|
PrintAndLog(" Hitag2 (2*)",htf);
|
||||||
PrintAndLog(" 21 <password> (password mode)",htf);
|
PrintAndLog(" 21 <password> (password mode)",htf);
|
||||||
PrintAndLog(" 22 <nr> <ar> (authentication)",htf);
|
PrintAndLog(" 22 <nr> <ar> (authentication)",htf);
|
||||||
|
PrintAndLog(" 23 <key> (authentication)",htf);
|
||||||
PrintAndLog(" 25 (test recorded authentications)",htf);
|
PrintAndLog(" 25 (test recorded authentications)",htf);
|
||||||
return 1;
|
return 1;
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -12,9 +12,10 @@
|
||||||
#define _HITAG2_H_
|
#define _HITAG2_H_
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RHT2F_PASSWORD = 21,
|
RHT2F_PASSWORD = 21,
|
||||||
RHT2F_AUTHENTICATE = 22,
|
RHT2F_AUTHENTICATE = 22,
|
||||||
RHT2F_TEST_AUTH_ATTEMPTS = 25,
|
RHT2F_CRYPTO = 23,
|
||||||
|
RHT2F_TEST_AUTH_ATTEMPTS = 25,
|
||||||
} hitag_function;
|
} hitag_function;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -25,9 +26,14 @@ typedef struct {
|
||||||
byte_t NrAr[8];
|
byte_t NrAr[8];
|
||||||
} PACKED rht2d_authenticate;
|
} PACKED rht2d_authenticate;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
byte_t key[4];
|
||||||
|
} PACKED rht2d_crypto;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
rht2d_password pwd;
|
rht2d_password pwd;
|
||||||
rht2d_authenticate auth;
|
rht2d_authenticate auth;
|
||||||
|
rht2d_crypto crypto;
|
||||||
} hitag_data;
|
} hitag_data;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue