HitagS Improvements (#721)

* support of HITAG S standard communication mode
* fixed wrong AC (Anti Collision) decoding
* support of block read mode
* fixed wrong uid send when using simulation
* support of communication mode parameter  (client is backward compatible)
* support of start-page parameter (important for some weird tags) (client is backward compatible)
* also expect pages if tag memory size in con0 is 11 (we got some tags)
* corrected hitagS reader cmd help
This commit is contained in:
florianrock 2018-11-30 17:42:22 +01:00 committed by pwpiwi
commit 7b6e320533
8 changed files with 1074 additions and 733 deletions

View file

@ -7,13 +7,20 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
### Changed ### Changed
- Changed hf mfp security. Now it works in all the modes. (drHatson) - Changed hf mfp security. Now it works in all the modes. (drHatson)
- `hf fido` - show/check DER certificate and signatures (Merlok) - `hf fido` - show/check DER certificate and signatures (Merlok)
- Changed `lf hitag reader 0x ... <firstPage> <tagmode>` - to select first page to read and tagmode (0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED)
- Accept hitagS con0 tags with memory bits set to 11 and handle like 2048 tag
### Fixed ### Fixed
- AC-Mode decoding for HitagS
- Wrong UID at HitagS simulation
### Added ### Added
- Support Standard Communication Mode in HITAG S
- Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) - Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok)
- `hf mfp` group of commands (Merlok) - `hf mfp` group of commands (Merlok)
- Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok) - Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok)
- Added `lf hitag reader 03` - read block (instead of pages)
- Added `lf hitag reader 04` - read block (instead of pages)
## [v3.1.0][2018-10-10] ## [v3.1.0][2018-10-10]

View file

@ -229,8 +229,11 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
uint8_t *trace = BigBuf_get_addr(); uint8_t *trace = BigBuf_get_addr();
uint16_t iLen = nbytes(iBits); uint16_t iLen = nbytes(iBits);
// Return when trace is full // Return when trace is full
if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false; if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) {
return false;
}
//Hitag traces appear to use this traceformat: //Hitag traces appear to use this traceformat:
// 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag)
@ -238,6 +241,8 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP
// 8 bits size (number of bits in the trace entry, not number of bytes) // 8 bits size (number of bits in the trace entry, not number of bytes)
// y Bytes data // y Bytes data
rsamples += iSamples; rsamples += iSamples;
trace[traceLen++] = ((rsamples >> 0) & 0xff); trace[traceLen++] = ((rsamples >> 0) & 0xff);
trace[traceLen++] = ((rsamples >> 8) & 0xff); trace[traceLen++] = ((rsamples >> 8) & 0xff);

View file

@ -1086,10 +1086,13 @@ void UsbPacketReceived(uint8_t *packet, int len)
SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes); SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
break; break;
case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file
check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes); check_challenges_cmd((bool)c->arg[0], (byte_t*)c->d.asBytes, (uint8_t)c->arg[1]);
break; break;
case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge
ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], false);
break;
case CMD_READ_HITAG_S_BLK:
ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], true);
break; break;
case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge
if ((hitag_function)c->arg[0] < 10) { if ((hitag_function)c->arg[0] < 10) {

View file

@ -180,10 +180,11 @@ void ReaderHitag(hitag_function htf, hitag_data* htd);
void WriterHitag(hitag_function htf, hitag_data* htd, int page); void WriterHitag(hitag_function htf, hitag_data* htd, int page);
//hitagS.h //hitagS.h
void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock);
void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data);
void ReadHitagS(hitag_function htf, hitag_data* htd);
void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); void WritePageHitagS(hitag_function htf, hitag_data* htd,int page);
void check_challenges(bool file_given, byte_t* data); void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode);
// cmd.h // cmd.h

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,6 @@ size_t nbytes(size_t nbits) {
int CmdLFHitagList(const char *Cmd) 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;
GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false);
@ -52,6 +51,7 @@ int CmdLFHitagList(const char *Cmd)
PrintAndLog(" ETU :nbits: who bytes"); PrintAndLog(" ETU :nbits: who bytes");
PrintAndLog("---------+-----+----+-----------"); PrintAndLog("---------+-----+----+-----------");
int j;
int i = 0; int i = 0;
int prev = -1; int prev = -1;
int len = strlen(Cmd); int len = strlen(Cmd);
@ -93,7 +93,7 @@ int CmdLFHitagList(const char *Cmd)
// or each half bit period in 256 levels. // or each half bit period in 256 levels.
int bits = got[i+8]; int bits = got[i+8];
int len = nbytes(got[i+8]); int len = nbytes(bits);
if (len > 100) { if (len > 100) {
break; break;
@ -101,19 +101,43 @@ int CmdLFHitagList(const char *Cmd)
if (i + len > traceLen) { break;} if (i + len > traceLen) { break;}
uint8_t *frame = (got+i+9); uint8_t *frame = (got+i+9);
/*
int fillupBits = 8 - (bits % 8);
byte_t framefilled[bits+fillupBits];
byte_t* ff = framefilled;
int response_bit[200] = {0};
int z = 0;
for (int y = 0; y < len; y++) {
for (j = 0; j < 8; j++) {
response_bit[z] = 0;
if ((frame[y] & ((mask << 7) >> j)) != 0)
response_bit[z] = 1;
z++;
}
}
z = 0;
for (int y = 0; y < len; y++) {
ff[y] = (response_bit[z] << 7) | (response_bit[z + 1] << 6)
| (response_bit[z + 2] << 5) | (response_bit[z + 3] << 4)
| (response_bit[z + 4] << 3) | (response_bit[z + 5] << 2)
| (response_bit[z + 6] << 1) | response_bit[z + 7];
z += 8;
}
*/
// Break and stick with current result if buffer was not completely full // Break and stick with current result if buffer was not completely full
if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; }
char line[1000] = ""; char line[1000] = "";
int j;
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
//if((parityBits >> (len - j - 1)) & 0x01) { //if((parityBits >> (len - j - 1)) & 0x01) {
if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) {
sprintf(line+(j*4), "%02x! ", frame[j]); sprintf(line+(j*4), "%02x! ", frame[j]);
} } else {
else {
sprintf(line+(j*4), "%02x ", frame[j]); sprintf(line+(j*4), "%02x ", frame[j]);
} }
} }
@ -194,10 +218,27 @@ int CmdLFHitagReader(const char *Cmd) {
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[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[2] = param_get64ex(Cmd,3,0,0); //tag mode
} break;
case 03: { //RHTSF_CHALLENGE BLOCK
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,2,0,16),4,htd->auth.NrAr+4);
c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage
c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode
} break;
case 04: { //RHTSF_KEY BLOCK
c = (UsbCommand){ CMD_READ_HITAG_S_BLK };
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[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);
@ -222,8 +263,11 @@ int CmdLFHitagReader(const char *Cmd) {
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) 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) 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(" 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(" Hitag1 (1*)"); PrintAndLog(" Hitag1 (1*)");
PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" Hitag2 (2*)");
PrintAndLog(" 21 <password> (password mode)"); PrintAndLog(" 21 <password> (password mode)");
@ -334,6 +378,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
//file with all the challenges to try //file with all the challenges to try
c.arg[0] = (uint32_t)file_given; c.arg[0] = (uint32_t)file_given;
c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode
SendCommand(&c); SendCommand(&c);
return 0; return 0;
@ -394,7 +439,7 @@ static command_t CommandTable[] =
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, {"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" },
{"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" }, {"simS", CmdLFHitagSimS, 1, "<hitagS.hts> Simulate HitagS transponder" },
{"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> test all challenges" }, { {"checkChallenges", CmdLFHitagCheckChallenges, 1, "<challenges.cc> <tagmode> test all challenges" }, {
NULL,NULL, 0, NULL } NULL,NULL, 0, NULL }
}; };

View file

@ -16,14 +16,14 @@
#include "hitag2.h" #include "hitag2.h"
typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state
typedef enum TAG_STATE {NO_OP=0,READING_PAGE,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state typedef enum TAG_STATE {NO_OP=0,READING_PAGE,READING_BLOCK,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state
typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits
struct hitagS_tag { struct hitagS_tag {
PSTATE pstate; //protocol-state PSTATE pstate; //protocol-state
TSATE tstate; //tag-state TSATE tstate; //tag-state
uint32_t uid; uint32_t uid;
uint32_t pages[16][4]; uint8_t pages[64][4];
uint64_t key; uint64_t key;
byte_t pwdl0,pwdl1,pwdh0; byte_t pwdl0,pwdl1,pwdh0;
//con0 //con0

View file

@ -137,6 +137,7 @@ typedef struct{
#define CMD_SIMULATE_HITAG_S 0x0368 #define CMD_SIMULATE_HITAG_S 0x0368
#define CMD_TEST_HITAGS_TRACES 0x0367 #define CMD_TEST_HITAGS_TRACES 0x0367
#define CMD_READ_HITAG_S 0x0373 #define CMD_READ_HITAG_S 0x0373
#define CMD_READ_HITAG_S_BLK 0x0374
#define CMD_WR_HITAG_S 0x0375 #define CMD_WR_HITAG_S 0x0375
#define CMD_EMU_HITAG_S 0x0376 #define CMD_EMU_HITAG_S 0x0376