1 //----------------------------------------------------------------------------- 
   2 // Copyright (C) 2012 Roel Verdult 
   4 // This code is licensed to you under the terms of the GNU GPL, version 2 or, 
   5 // at your option, any later version. See the LICENSE.txt file for the text of 
   7 //----------------------------------------------------------------------------- 
   8 // Low frequency Hitag support 
   9 //----------------------------------------------------------------------------- 
  11 #include "cmdlfhitag.h" 
  18 #include "cmdparser.h" 
  26 static int CmdHelp(const char *Cmd
); 
  28 size_t nbytes(size_t nbits
) { 
  29         return (nbits
/8)+((nbits%8
)>0); 
  32 int CmdLFHitagList(const char *Cmd
) 
  34         uint8_t *got 
= malloc(USB_CMD_DATA_SIZE
); 
  35         // Query for the actual size of the trace 
  37         GetFromBigBuf(got
, USB_CMD_DATA_SIZE
, 0, &response
, -1, false); 
  38         uint16_t traceLen 
= response
.arg
[2]; 
  39         if (traceLen 
> USB_CMD_DATA_SIZE
) { 
  40                 uint8_t *p 
= realloc(got
, traceLen
); 
  42                         PrintAndLog("Cannot allocate memory for trace"); 
  47                 GetFromBigBuf(got
, traceLen
, 0, NULL
, -1, false); 
  50         PrintAndLog("recorded activity (TraceLen = %d bytes):"); 
  51         PrintAndLog(" ETU     :nbits: who bytes"); 
  52         PrintAndLog("---------+-----+----+-----------"); 
  57         int len 
= strlen(Cmd
); 
  59         char filename
[FILE_PATH_SIZE
]  = { 0x00 }; 
  62         if (len 
> FILE_PATH_SIZE
)  
  64         memcpy(filename
, Cmd
, len
); 
  66         if (strlen(filename
) > 0) { 
  67                 if ((pf 
= fopen(filename
,"wb")) == NULL
) { 
  68                         PrintAndLog("Error: Could not open file [%s]",filename
); 
  76                 if(i 
> traceLen
) { break; } 
  79                 int timestamp 
= *((uint32_t *)(got
+i
)); 
  80                 if (timestamp 
& 0x80000000) { 
  81                         timestamp 
&= 0x7fffffff; 
  87                 int parityBits 
= *((uint32_t *)(got
+i
+4)); 
  88                 // 4 bytes of additional information... 
  89                 // maximum of 32 additional parity bit information 
  92                 // at each quarter bit period we can send power level (16 levels) 
  93                 // or each half bit period in 256 levels. 
  96                 int len 
= nbytes(bits
); 
 101                 if (i 
+ len 
> traceLen
) { break;} 
 103                 uint8_t *frame 
= (got
+i
+9); 
 105                 int fillupBits = 8 - (bits % 8); 
 106                 byte_t framefilled[bits+fillupBits]; 
 107                 byte_t* ff = framefilled; 
 109                 int response_bit[200] = {0}; 
 111                 for (int y = 0; y < len; y++) { 
 112                         for (j = 0; j < 8; j++) { 
 114                                 if ((frame[y] & ((mask << 7) >> j)) != 0) 
 120                 for (int y = 0; y < len; y++) { 
 121                         ff[y] = (response_bit[z] << 7) | (response_bit[z + 1] << 6) 
 122                                         | (response_bit[z + 2] << 5) | (response_bit[z + 3] << 4) 
 123                                         | (response_bit[z + 4] << 3) | (response_bit[z + 5] << 2) 
 124                                         | (response_bit[z + 6] << 1) | response_bit[z + 7]; 
 132                 // Break and stick with current result if buffer was not completely full 
 133                 if (frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; } 
 135                 char line
[1000] = ""; 
 136                 for (j 
= 0; j 
< len
; j
++) { 
 137                   //if((parityBits >> (len - j - 1)) & 0x01) { 
 138                   if (isResponse 
&& (oddparity8(frame
[j
]) != ((parityBits 
>> (len 
- j 
- 1)) & 0x01))) { 
 139                         sprintf(line
+(j
*4), "%02x!  ", frame
[j
]); 
 141                         sprintf(line
+(j
*4), "%02x   ", frame
[j
]); 
 145                 PrintAndLog(" +%7d:  %3d: %s %s", 
 146                         (prev 
< 0 ? 0 : (timestamp 
- prev
)), 
 148                         (isResponse 
? "TAG" : "   "), 
 152                         fprintf(pf
," +%7d:  %3d: %s %s\n", 
 153                                 (prev 
< 0 ? 0 : (timestamp 
- prev
)), 
 155                                 (isResponse 
? "TAG" : "   "), 
 165                 PrintAndLog("Recorded activity succesfully written to file: %s", filename
); 
 172 int CmdLFHitagSnoop(const char *Cmd
) { 
 173   UsbCommand c 
= {CMD_SNOOP_HITAG
}; 
 178 int CmdLFHitagSim(const char *Cmd
) { 
 180   UsbCommand c 
= {CMD_SIMULATE_HITAG
}; 
 181         char filename
[FILE_PATH_SIZE
] = { 0x00 }; 
 183         bool tag_mem_supplied
; 
 184         int len 
= strlen(Cmd
); 
 185         if (len 
> FILE_PATH_SIZE
) len 
= FILE_PATH_SIZE
; 
 186         memcpy(filename
, Cmd
, len
); 
 188         if (strlen(filename
) > 0) { 
 189                 if ((pf 
= fopen(filename
,"rb+")) == NULL
) { 
 190                         PrintAndLog("Error: Could not open file [%s]",filename
); 
 193                 tag_mem_supplied 
= true; 
 194                 if (fread(c
.d
.asBytes
,1,48,pf
) != 48) { 
 195                         PrintAndLog("Error: File reading error"); 
 201                 tag_mem_supplied 
= false; 
 204         // Does the tag comes with memory 
 205         c
.arg
[0] = (uint32_t)tag_mem_supplied
; 
 211 int CmdLFHitagReader(const char *Cmd
) { 
 212         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)}}; 
 213         hitag_data
* htd 
= (hitag_data
*)c
.d
.asBytes
; 
 214         hitag_function htf 
= param_get32ex(Cmd
,0,0,10); 
 217                 case 01: { //RHTSF_CHALLENGE 
 218                         c 
= (UsbCommand
){ CMD_READ_HITAG_S 
}; 
 219                         num_to_bytes(param_get32ex(Cmd
,1,0,16),4,htd
->auth
.NrAr
); 
 220                         num_to_bytes(param_get32ex(Cmd
,2,0,16),4,htd
->auth
.NrAr
+4); 
 221                         c
.arg
[1] = param_get64ex(Cmd
,3,0,0); //firstpage 
 222                         c
.arg
[2] = param_get64ex(Cmd
,4,0,0); //tag mode 
 224                 case 02: { //RHTSF_KEY 
 225                         c 
= (UsbCommand
){ CMD_READ_HITAG_S 
}; 
 226                         num_to_bytes(param_get64ex(Cmd
,1,0,16),6,htd
->crypto
.key
); 
 227                         c
.arg
[1] = param_get64ex(Cmd
,2,0,0); //firstpage 
 228                         c
.arg
[2] = param_get64ex(Cmd
,3,0,0); //tag mode 
 230                 case 03: { //RHTSF_CHALLENGE BLOCK 
 231                         c 
= (UsbCommand
){ CMD_READ_HITAG_S_BLK 
}; 
 232                         num_to_bytes(param_get32ex(Cmd
,1,0,16),4,htd
->auth
.NrAr
); 
 233                         num_to_bytes(param_get32ex(Cmd
,2,0,16),4,htd
->auth
.NrAr
+4); 
 234                         c
.arg
[1] = param_get64ex(Cmd
,3,0,0); //firstpage 
 235                         c
.arg
[2] = param_get64ex(Cmd
,4,0,0); //tag mode 
 237                 case 04: { //RHTSF_KEY BLOCK 
 238                         c 
= (UsbCommand
){ CMD_READ_HITAG_S_BLK 
}; 
 239                         num_to_bytes(param_get64ex(Cmd
,1,0,16),6,htd
->crypto
.key
); 
 240                         c
.arg
[1] = param_get64ex(Cmd
,2,0,0); //firstpage 
 241                         c
.arg
[2] = param_get64ex(Cmd
,3,0,0); //tag mode 
 243                 case RHT2F_PASSWORD
: { 
 244                         num_to_bytes(param_get32ex(Cmd
,1,0,16),4,htd
->pwd
.password
); 
 246                 case RHT2F_AUTHENTICATE
: { 
 247                         num_to_bytes(param_get32ex(Cmd
,1,0,16),4,htd
->auth
.NrAr
); 
 248                         num_to_bytes(param_get32ex(Cmd
,2,0,16),4,htd
->auth
.NrAr
+4); 
 251                         num_to_bytes(param_get64ex(Cmd
,1,0,16),6,htd
->crypto
.key
); 
 252                         //                      num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); 
 254                 case RHT2F_TEST_AUTH_ATTEMPTS
: { 
 255                         // No additional parameters needed 
 257                 case RHT2F_UID_ONLY
: { 
 258                         // No additional parameters needed 
 261                         PrintAndLog("\nError: unkown reader function %d",htf
); 
 263                         PrintAndLog("Usage: hitag reader <Reader Function #>"); 
 264                         PrintAndLog("Reader Functions:"); 
 265                         PrintAndLog(" HitagS (0*)"); 
 266                         PrintAndLog("  01 <nr> <ar> (Challenge) <firstPage> <tagmode> read all pages from a Hitag S tag"); 
 267                         PrintAndLog("  02 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all pages from a Hitag S tag"); 
 268                         PrintAndLog("  03 <nr> <ar> (Challenge) <firstPage> <tagmode> read all blocks from a Hitag S tag"); 
 269                         PrintAndLog("  04 <key> (set to 0 if no authentication is needed) <firstPage> <tagmode> read all blocks from a Hitag S tag"); 
 270                         PrintAndLog("  Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); 
 271                         PrintAndLog(" Hitag1 (1*)"); 
 272                         PrintAndLog(" Hitag2 (2*)"); 
 273                         PrintAndLog("  21 <password> (password mode)"); 
 274                         PrintAndLog("  22 <nr> <ar> (authentication)"); 
 275                         PrintAndLog("  23 <key> (authentication) key is in format: ISK high + ISK low"); 
 276                         PrintAndLog("  25 (test recorded authentications)"); 
 277                         PrintAndLog("  26 just read UID"); 
 282         // Copy the hitag2 function into the first argument 
 285         // Send the command to the proxmark 
 286         clearCommandBuffer(); 
 290         WaitForResponse(CMD_ACK
,&resp
); 
 292         // Check the return status, stored in the first argument 
 293         if (resp
.arg
[0] == false) return 1; 
 295         uint32_t id 
= bytes_to_num(resp
.d
.asBytes
,4); 
 297         if (htf 
== RHT2F_UID_ONLY
){ 
 298                 PrintAndLog("Valid Hitag2 tag found - UID: %08x",id
); 
 303                 sprintf(filename
,"%08x_%04x.ht2",id
,(rand() & 0xffff)); 
 304                 if ((pf 
= fopen(filename
,"wb")) == NULL
) { 
 305                   PrintAndLog("Error: Could not open file [%s]",filename
); 
 309                 // Write the 48 tag memory bytes to file and finalize 
 310                 fwrite(resp
.d
.asBytes
,1,48,pf
); 
 313                 PrintAndLog("Succesfully saved tag memory to [%s]",filename
); 
 321 int CmdLFHitagSimS(const char *Cmd
) { 
 322         UsbCommand c 
= { CMD_SIMULATE_HITAG_S 
}; 
 323         char filename
[FILE_PATH_SIZE
] = { 0x00 }; 
 325         bool tag_mem_supplied
; 
 326         int len 
= strlen(Cmd
); 
 327         if (len 
> FILE_PATH_SIZE
) 
 328                 len 
= FILE_PATH_SIZE
; 
 329         memcpy(filename
, Cmd
, len
); 
 331         if (strlen(filename
) > 0) { 
 332                 if ((pf 
= fopen(filename
, "rb+")) == NULL
) { 
 333                         PrintAndLog("Error: Could not open file [%s]", filename
); 
 336                 tag_mem_supplied 
= true; 
 337                 if (fread(c
.d
.asBytes
, 1, 4*64, pf
) != 4*64) { 
 338                         PrintAndLog("Error: File reading error"); 
 344                 tag_mem_supplied 
= false; 
 347         // Does the tag comes with memory 
 348         c
.arg
[0] = (uint32_t) tag_mem_supplied
; 
 354 int CmdLFHitagCheckChallenges(const char *Cmd
) { 
 355         UsbCommand c 
= { CMD_TEST_HITAGS_TRACES 
}; 
 356         char filename
[FILE_PATH_SIZE
] = { 0x00 }; 
 359         int len 
= strlen(Cmd
); 
 360         if (len 
> FILE_PATH_SIZE
) len 
= FILE_PATH_SIZE
; 
 361         memcpy(filename
, Cmd
, len
); 
 363         if (strlen(filename
) > 0) { 
 364                 if ((pf 
= fopen(filename
,"rb+")) == NULL
) { 
 365                         PrintAndLog("Error: Could not open file [%s]",filename
); 
 369                 if (fread(c
.d
.asBytes
,1,8*60,pf
) != 8*60) { 
 370                         PrintAndLog("Error: File reading error"); 
 379         //file with all the challenges to try 
 380         c
.arg
[0] = (uint32_t)file_given
; 
 381         c
.arg
[1] = param_get64ex(Cmd
,2,0,0); //get mode 
 388 int CmdLFHitagWP(const char *Cmd
) { 
 389         UsbCommand c 
= { CMD_WR_HITAG_S 
}; 
 390         hitag_data
* htd 
= (hitag_data
*)c
.d
.asBytes
; 
 391         hitag_function htf 
= param_get32ex(Cmd
,0,0,10); 
 393                 case 03: { //WHTSF_CHALLENGE 
 394                         num_to_bytes(param_get64ex(Cmd
,1,0,16),8,htd
->auth
.NrAr
); 
 395                         c
.arg
[2]= param_get32ex(Cmd
, 2, 0, 10); 
 396                         num_to_bytes(param_get32ex(Cmd
,3,0,16),4,htd
->auth
.data
); 
 401                         num_to_bytes(param_get64ex(Cmd
,1,0,16),6,htd
->crypto
.key
); 
 402                         c
.arg
[2]= param_get32ex(Cmd
, 2, 0, 10); 
 403                         num_to_bytes(param_get32ex(Cmd
,3,0,16),4,htd
->crypto
.data
); 
 407                         PrintAndLog("Error: unkown writer function %d",htf
); 
 408                         PrintAndLog("Hitag writer functions"); 
 409                         PrintAndLog(" HitagS (0*)"); 
 410                         PrintAndLog("  03 <nr,ar> (Challenge) <page> <byte0...byte3> write page on a Hitag S tag"); 
 411                         PrintAndLog("  04 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); 
 412                         PrintAndLog(" Hitag1 (1*)"); 
 413                         PrintAndLog(" Hitag2 (2*)"); 
 414                         PrintAndLog("  24 <key> (set to 0 if no authentication is needed) <page> <byte0...byte3> write page on a Hitag S tag"); 
 418         // Copy the hitag function into the first argument 
 421   // Send the command to the proxmark 
 425   WaitForResponse(CMD_ACK
,&resp
); 
 427   // Check the return status, stored in the first argument 
 428   if (resp
.arg
[0] == false) return 1; 
 433 static command_t CommandTable
[] =  
 435   {"help",              CmdHelp
,           1, "This help"}, 
 436   {"list",              CmdLFHitagList
,    1, "<outfile> List Hitag trace history"}, 
 437   {"reader",            CmdLFHitagReader
,  1, "Act like a Hitag Reader"}, 
 438   {"sim",               CmdLFHitagSim
,     1, "<infile> Simulate Hitag transponder"}, 
 439   {"snoop",             CmdLFHitagSnoop
,   1, "Eavesdrop Hitag communication"}, 
 440   {"writer",            CmdLFHitagWP
,      1, "Act like a Hitag Writer" }, 
 441   {"simS",              CmdLFHitagSimS
,    1, "<hitagS.hts> Simulate HitagS transponder" },  
 442   {"checkChallenges",   CmdLFHitagCheckChallenges
,   1, "<challenges.cc> <tagmode> test all challenges" }, { 
 446 int CmdLFHitag(const char *Cmd
) 
 448   CmdsParse(CommandTable
, Cmd
); 
 452 int CmdHelp(const char *Cmd
) 
 454   CmdsHelp(CommandTable
);