mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-12 04:35:28 -07:00
This is the major changes made to the HITAG2 commands. Its heavly based on RFIDLers implementation and its been converted to work with Proxmark3. Special thanks to @kevsecurity for his amazing implementations of the Gone in 360 Seconds paper by Roel, Flavio & Balasch. Thanks to @adamlaurie for his RFIDler project. It wouldnt been doable without it.
This commit is contained in:
parent
fc2a3dd2c5
commit
c8849af5e0
@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `lf hitag dump --nrar` - now supports attack 1 from "gone in 360 seconds" paper. Thanks @kevsecurity! (@iceman1001)
|
||||
- Added `lf hitag selftest` - converted from RFIDLers selftest (@iceman1001)
|
||||
- Added `lf hitag chk` - dictionary attack against card (@iceman1001)
|
||||
- Added `lf hitag lookup` - verify collected challenges aginst dictionary (@iceman1001)
|
||||
- Updated windows workflow to use latest setup-wsl script (@iceman1001)
|
||||
- Added a micro second clock in the client (@iceman1001)
|
||||
- Fix `hf mfdes read` - buffer overflow when reading large files (@iceman1001)
|
||||
|
@ -71,7 +71,7 @@ else
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS)))
|
||||
SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c
|
||||
SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c hitag2_crack.c
|
||||
APP_CFLAGS += -I../common/hitag2
|
||||
else
|
||||
SRC_HITAG =
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "thinfilm.h"
|
||||
#include "felica.h"
|
||||
#include "hitag2.h"
|
||||
#include "hitag2_crack.h"
|
||||
#include "hitagS.h"
|
||||
#include "em4x50.h"
|
||||
#include "em4x70.h"
|
||||
@ -1131,16 +1132,32 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
#ifdef WITH_HITAG
|
||||
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
|
||||
SniffHitag2(true);
|
||||
// SniffHitag2(packet->oldarg[0]);
|
||||
//hitag_sniff();
|
||||
reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content
|
||||
SimulateHitag2(true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG2_CRACK: {
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
ht2_crack(payload->NrAr);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function
|
||||
ReaderHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, true);
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
|
||||
switch (payload->cmd) {
|
||||
case RHT2F_UID_ONLY: {
|
||||
ht2_read_uid(NULL, true, true, false);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
ReaderHitag(payload, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAGS_SIMULATE: { // Simulate Hitag s tag, args = memory content
|
||||
@ -1148,25 +1165,28 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAGS_TEST_TRACES: { // Tests every challenge within the given file
|
||||
Hitag_check_challenges(packet->data.asBytes, packet->oldarg[0], true);
|
||||
Hitag_check_challenges(packet->data.asBytes, packet->length, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAGS_READ: { //Reader for only Hitag S tags, args = key or challenge
|
||||
ReadHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, true);
|
||||
case CMD_LF_HITAGS_READ: { // Reader for only Hitag S tags, args = key or challenge
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
ReadHitagS(payload, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAGS_WRITE: { //writer for Hitag tags args=data to write,page and key or challenge
|
||||
if ((hitag_function)packet->oldarg[0] < 10) {
|
||||
WritePageHitagS((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2], true);
|
||||
} else {
|
||||
WriterHitag((hitag_function)packet->oldarg[0], (hitag_data *)packet->data.asBytes, packet->oldarg[2], true);
|
||||
}
|
||||
case CMD_LF_HITAGS_WRITE: {
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
WritePageHitagS(payload, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG2_WRITE: {
|
||||
lf_hitag_data_t *payload = (lf_hitag_data_t *) packet->data.asBytes;
|
||||
WriterHitag(payload, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG_ELOAD: {
|
||||
lf_hitag_t *payload = (lf_hitag_t *) packet->data.asBytes;
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
memcpy((uint8_t *)mem, payload->data, payload->len);
|
||||
memcpy(mem, payload->data, payload->len);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
861
armsrc/hitag2.c
861
armsrc/hitag2.c
File diff suppressed because it is too large
Load Diff
@ -23,8 +23,12 @@
|
||||
#include "hitag.h"
|
||||
|
||||
void SniffHitag2(bool ledcontrol);
|
||||
void hitag_sniff(void);
|
||||
void SimulateHitag2(bool ledcontrol);
|
||||
void ReaderHitag(hitag_function htf, const hitag_data *htd, bool ledcontrol);
|
||||
void WriterHitag(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
|
||||
void EloadHitag(const uint8_t *data, uint16_t len);
|
||||
void ReaderHitag(const lf_hitag_data_t *payload, bool ledcontrol);
|
||||
void WriterHitag(const lf_hitag_data_t *payload, bool ledcontrol);
|
||||
|
||||
bool ht2_packbits(uint8_t *nrz_samples, size_t nrzs, uint8_t *rx, size_t *rxlen);
|
||||
int ht2_read_uid(uint8_t *uid, bool ledcontrol, bool send_answer, bool keep_field_up);
|
||||
int ht2_tx_rx(uint8_t *tx, size_t txlen, uint8_t *rx, size_t *rxlen, bool ledcontrol, bool keep_field_up);
|
||||
#endif
|
||||
|
468
armsrc/hitagS.c
468
armsrc/hitagS.c
@ -52,7 +52,7 @@ static uint32_t temp_uid;
|
||||
static int temp2 = 0;
|
||||
static int sof_bits; // number of start-of-frame bits
|
||||
static uint8_t pwdh0, pwdl0, pwdl1; // password bytes
|
||||
static uint32_t rnd = 0x74124485; // randomnumber
|
||||
static uint32_t rnd = 0x74124485; // random number
|
||||
//#define SENDBIT_TEST
|
||||
|
||||
/* array index 3 2 1 0 // bytes in sim.bin file are 0 1 2 3
|
||||
@ -125,12 +125,13 @@ static void calc_crc(unsigned char *crc, unsigned char data, unsigned char Bitco
|
||||
}
|
||||
|
||||
static void hitag_send_bit(int bit, bool ledcontrol) {
|
||||
|
||||
if (ledcontrol) LED_A_ON();
|
||||
// Reset clock for the next bit
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
switch (m) {
|
||||
case AC2K:
|
||||
case AC2K: {
|
||||
if (bit == 0) {
|
||||
// AC Coding --__
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
@ -156,7 +157,8 @@ static void hitag_send_bit(int bit, bool ledcontrol) {
|
||||
}
|
||||
if (ledcontrol) LED_A_OFF();
|
||||
break;
|
||||
case AC4K:
|
||||
}
|
||||
case AC4K: {
|
||||
if (bit == 0) {
|
||||
// AC Coding --__
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
@ -181,7 +183,8 @@ static void hitag_send_bit(int bit, bool ledcontrol) {
|
||||
}
|
||||
if (ledcontrol) LED_A_OFF();
|
||||
break;
|
||||
case MC4K:
|
||||
}
|
||||
case MC4K: {
|
||||
if (bit == 0) {
|
||||
// Manchester: Unloaded, then loaded |__--|
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
@ -201,7 +204,8 @@ static void hitag_send_bit(int bit, bool ledcontrol) {
|
||||
}
|
||||
if (ledcontrol) LED_A_OFF();
|
||||
break;
|
||||
case MC8K:
|
||||
}
|
||||
case MC8K: {
|
||||
if (bit == 0) {
|
||||
// Manchester: Unloaded, then loaded |__--|
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
@ -221,26 +225,33 @@ static void hitag_send_bit(int bit, bool ledcontrol) {
|
||||
}
|
||||
if (ledcontrol) LED_A_OFF();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hitag_send_frame(const uint8_t *frame, size_t frame_len, bool ledcontrol) {
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("hitag_send_frame: (%i) %02X %02X %02X %02X", frame_len, frame[0], frame[1], frame[2], frame[3]);
|
||||
}
|
||||
|
||||
// The beginning of the frame is hidden in some high level; pause until our bits will have an effect
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
switch (m) {
|
||||
case AC4K:
|
||||
case MC8K:
|
||||
case MC8K: {
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; //FADV
|
||||
break;
|
||||
}
|
||||
case AC2K:
|
||||
case MC4K:
|
||||
case MC4K: {
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; //STD + ADV
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SOF - send start of frame
|
||||
@ -317,43 +328,101 @@ static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len, bool
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
}
|
||||
|
||||
static void hitagS_init_clock(void) {
|
||||
|
||||
// Enable Peripheral Clock for
|
||||
// TIMER_CLOCK0, used to measure exact timing before answering
|
||||
// TIMER_CLOCK1, used to capture edges of the tag frames
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
||||
|
||||
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
||||
|
||||
// Disable timer during configuration
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
||||
|
||||
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
||||
// external trigger rising edge, load RA on falling edge of TIOA.
|
||||
AT91C_BASE_TC1->TC_CMR =
|
||||
AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
|
||||
AT91C_TC_ETRGEDG_FALLING |
|
||||
AT91C_TC_ABETRG |
|
||||
AT91C_TC_LDRA_FALLING |
|
||||
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
|
||||
AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit)
|
||||
|
||||
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
|
||||
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
|
||||
|
||||
// Enable and reset counters
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// synchronized startup procedure
|
||||
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
|
||||
// while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared)
|
||||
|
||||
// return to zero
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV > 0);
|
||||
|
||||
}
|
||||
|
||||
static void hitagS_stop_clock(void) {
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
}
|
||||
|
||||
/*
|
||||
* to check if the right uid was selected
|
||||
*/
|
||||
static int check_select(const uint8_t *rx, uint32_t uid) {
|
||||
|
||||
unsigned char resp[48];
|
||||
uint32_t ans = 0x0;
|
||||
for (int i = 0; i < 48; i++)
|
||||
resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int i = 0; i < 48; i++) {
|
||||
resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ans += resp[5 + i] << (31 - i);
|
||||
}
|
||||
|
||||
// global var?
|
||||
temp_uid = ans;
|
||||
|
||||
if (ans == tag.uid)
|
||||
if (ans == tag.uid) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hitagS_set_frame_modulation(void) {
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
case HT_STANDARD: {
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
}
|
||||
case HT_ADVANCED: {
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
}
|
||||
case HT_FAST_ADVANCED: {
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,16 +480,18 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tx[i] = (tag.uid >> (24 - (i * 8))) & 0xFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 45: {
|
||||
//select command from reader received
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
DbpString("SELECT");
|
||||
}
|
||||
|
||||
if (check_select(rx, tag.uid) == 1) {
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
DbpString("SELECT match");
|
||||
}
|
||||
|
||||
//if the right tag was selected
|
||||
*txlen = 32;
|
||||
@ -434,8 +505,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
tx[3] = 0xff;
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
|
||||
*txlen = 40;
|
||||
crc = CRC_PRESET;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
calc_crc(&crc, tx[i], 8);
|
||||
}
|
||||
@ -443,8 +516,8 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
tx[4] = crc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 64: {
|
||||
//challenge message received
|
||||
Dbprintf("Challenge for UID: %X", temp_uid);
|
||||
@ -499,9 +572,9 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
tag.pages[0][3] = 0x88;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 40:
|
||||
case 40: {
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("WRITE");
|
||||
//data received to be written
|
||||
@ -535,6 +608,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 20: {
|
||||
//write page, write block, read page or read block command received
|
||||
if ((rx[0] & 0xf0) == 0xc0) { //read page
|
||||
@ -567,9 +641,12 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
sof_bits = 0;
|
||||
*txlen = 0;
|
||||
}
|
||||
|
||||
} else if ((rx[0] & 0xf0) == 0xd0) { //read block
|
||||
|
||||
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
|
||||
*txlen = 32 * 4;
|
||||
|
||||
//send page,...,page+3 data
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tx[0 + i * 4] = tag.pages[page + 0 + i * 4][0];
|
||||
@ -594,8 +671,11 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
sof_bits = 0;
|
||||
*txlen = 0;
|
||||
}
|
||||
|
||||
} else if ((rx[0] & 0xf0) == 0x80) { //write page
|
||||
|
||||
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
|
||||
|
||||
if ((tag.LCON && page == 1)
|
||||
|| (tag.LKP && (page == 2 || page == 3))) {
|
||||
//deny
|
||||
@ -609,8 +689,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
}
|
||||
|
||||
} else if ((rx[0] & 0xf0) == 0x90) { //write block
|
||||
|
||||
uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16);
|
||||
hitagS_set_frame_modulation();
|
||||
|
||||
if (page % 4 != 0 || page == 0) {
|
||||
//deny
|
||||
*txlen = 0;
|
||||
@ -623,12 +705,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
||||
tag.tstate = HT_WRITING_BLOCK_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,7 +723,6 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr
|
||||
|
||||
StopTicks();
|
||||
|
||||
// int frame_count = 0;
|
||||
int response = 0, overflow = 0;
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
@ -666,6 +749,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr
|
||||
|
||||
// read tag data into memory
|
||||
if (tag_mem_supplied) {
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
tag.pages[i][j] = 0x0;
|
||||
@ -700,7 +784,8 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr
|
||||
tag.max_page = 0;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
|
||||
for (int i = 0; i < tag.max_page; i++) {
|
||||
Dbprintf("Page[%2d]: %02X %02X %02X %02X", i,
|
||||
(tag.pages[i][3]) & 0xFF,
|
||||
@ -709,6 +794,8 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr
|
||||
tag.pages[i][0] & 0xFF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//con1
|
||||
tag.auth = 0;
|
||||
if ((tag.pages[1][1] & 0x80) == 0x80) {
|
||||
@ -814,8 +901,10 @@ void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontr
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) {
|
||||
|
||||
// Check if rising edge in modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
|
||||
// Retrieve the new timing values
|
||||
int ra = (AT91C_BASE_TC1->TC_RA / T0) + overflow;
|
||||
overflow = 0;
|
||||
@ -901,6 +990,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
// Reset values for receiving frames
|
||||
memset(rx, 0x00, sizeofrx);
|
||||
*rxlen = 0;
|
||||
|
||||
int lastbit = 1;
|
||||
bool bSkip = true;
|
||||
*resptime = 0;
|
||||
@ -914,8 +1004,8 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC0->TC_CV + (overcount << 16) < (T0 * HITAG_T_PROG_MAX)) {
|
||||
// detect and track counter overflows
|
||||
|
||||
// detect and track counter overflows
|
||||
uint32_t tmpcv = AT91C_BASE_TC0->TC_CV;
|
||||
if (tmpcv < prevcv) {
|
||||
overcount++;
|
||||
@ -924,10 +1014,13 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
|
||||
// Retrieve the new timing values
|
||||
uint32_t ra = (AT91C_BASE_TC1->TC_RA + (overcount << 16)) / T0;
|
||||
|
||||
// Reset timer every frame, we have to capture the last edge for timing
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
prevcv = 0;
|
||||
overcount = 0;
|
||||
|
||||
@ -935,7 +1028,8 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
|
||||
// Capture tag frame (manchester decoding using only falling edges)
|
||||
|
||||
if (!bStarted) {
|
||||
if (bStarted == false) {
|
||||
|
||||
if (ra >= HITAG_T_EOF) {
|
||||
bStarted = true;
|
||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
||||
@ -944,28 +1038,37 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
} else {
|
||||
errorCount++;
|
||||
}
|
||||
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
|
||||
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
|
||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
||||
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
|
||||
// We have to skip this half period at start and add the 'one' the second time
|
||||
if (!bSkip) {
|
||||
if (bSkip == false) {
|
||||
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
}
|
||||
|
||||
lastbit = !lastbit;
|
||||
bSkip = !bSkip;
|
||||
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
||||
// bit is same as last bit
|
||||
rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
|
||||
} else {
|
||||
// Ignore weird value, is to small to mean anything
|
||||
errorCount++;
|
||||
@ -973,11 +1076,13 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||
}
|
||||
|
||||
// if we saw over 100 weird 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
|
||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
||||
if ((*rxlen) > 0) {
|
||||
if (AT91C_BASE_TC1->TC_CV > (T0 * HITAG_T_EOF)) {
|
||||
if ((*rxlen)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -998,7 +1103,6 @@ static void sendReceiveHitagS(uint8_t *tx, size_t txlen, uint8_t *rx, size_t siz
|
||||
// falling edge occurred halfway the period. with respect to this falling edge,
|
||||
// we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'.
|
||||
// All timer values are in terms of T0 units
|
||||
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * t_wait) {};
|
||||
|
||||
// Transmit the reader frame
|
||||
@ -1011,48 +1115,82 @@ static void sendReceiveHitagS(uint8_t *tx, size_t txlen, uint8_t *rx, size_t siz
|
||||
size_t rxlen = 0;
|
||||
hitagS_receive_frame(rx, sizeofrx, &rxlen, &resptime, ledcontrol);
|
||||
int k = 0;
|
||||
|
||||
// Check if frame was captured and store it
|
||||
if (rxlen > 0) {
|
||||
|
||||
uint8_t response_bit[sizeofrx * 8];
|
||||
for (int i = 0; i < rxlen; i++) {
|
||||
|
||||
for (size_t i = 0; i < rxlen; i++) {
|
||||
response_bit[i] = (rx[i / 8] >> (7 - (i % 8))) & 1;
|
||||
}
|
||||
|
||||
Dbprintf("htS: rxlen...... %zu", rxlen);
|
||||
Dbprintf("htS: sizeofrx... %zu", sizeofrx);
|
||||
|
||||
memset(rx, 0x00, sizeofrx);
|
||||
|
||||
if (ac_seq) {
|
||||
|
||||
DbpString("htS: AntiCollision Sequence ( ac seq )");
|
||||
Dbhexdump(rxlen, response_bit, false);
|
||||
|
||||
// Tag Response is AC encoded
|
||||
// We used UID Request Advanced, meaning AC SEQ header is 111.
|
||||
for (int i = 6; i < rxlen; i += 2) {
|
||||
|
||||
rx[k / 8] |= response_bit[i] << (7 - (k % 8));
|
||||
|
||||
k++;
|
||||
if (k >= 8 * sizeofrx)
|
||||
|
||||
if (k > 8 * sizeofrx) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DbpString("htS: ac sequence compress");
|
||||
Dbhexdump(k / 8, rx, false);
|
||||
|
||||
} else {
|
||||
for (int i = 5; i < rxlen; i++) { // ignore first 5 bits: SOF (actually 1 or 6 depending on response protocol)
|
||||
|
||||
DbpString("htS: skipping 5 bit header");
|
||||
|
||||
// ignore first 5 bits: SOF (actually 1 or 6 depending on response protocol)
|
||||
// or rather a header.
|
||||
for (size_t i = 5; i < rxlen; i++) {
|
||||
|
||||
rx[k / 8] |= response_bit[i] << (7 - (k % 8));
|
||||
k++;
|
||||
if (k >= 8 * sizeofrx)
|
||||
|
||||
if (k > 8 * sizeofrx) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
LogTraceBits(rx, k, resptime, resptime, false);
|
||||
}
|
||||
*prxbits = k;
|
||||
}
|
||||
|
||||
static size_t concatbits(uint8_t *dstbuf, size_t dstbufskip, const uint8_t *srcbuf, size_t srcbufstart, size_t srcbuflen) {
|
||||
static size_t concatbits(uint8_t *dst, size_t dstskip, const uint8_t *src, size_t srcstart, size_t srclen) {
|
||||
// erase dstbuf bits that will be overriden
|
||||
dstbuf[dstbufskip / 8] &= 0xFF - ((1 << (7 - (dstbufskip % 8) + 1)) - 1);
|
||||
for (size_t i = (dstbufskip / 8) + 1; i <= (dstbufskip + srcbuflen) / 8; i++) {
|
||||
dstbuf[i] = 0;
|
||||
dst[dstskip / 8] &= 0xFF - ((1 << (7 - (dstskip % 8) + 1)) - 1);
|
||||
for (size_t i = (dstskip / 8) + 1; i <= (dstskip + srclen) / 8; i++) {
|
||||
dst[i] = 0;
|
||||
}
|
||||
for (size_t i = 0; i < srcbuflen; i++) {
|
||||
|
||||
for (size_t i = 0; i < srclen; i++) {
|
||||
// equiv of dstbufbits[dstbufskip + i] = srcbufbits[srcbufstart + i]
|
||||
dstbuf[(dstbufskip + i) / 8] |= ((srcbuf[(srcbufstart + i) / 8] >> (7 - ((srcbufstart + i) % 8))) & 1) << (7 - ((dstbufskip + i) % 8));
|
||||
dst[(dstskip + i) / 8] |= ((src[(srcstart + i) / 8] >> (7 - ((srcstart + i) % 8))) & 1) << (7 - ((dstskip + i) % 8));
|
||||
}
|
||||
return dstbufskip + srcbuflen;
|
||||
|
||||
return dstskip + srclen;
|
||||
}
|
||||
|
||||
static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) {
|
||||
static int selectHitagS(const lf_hitag_data_t *packet, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) {
|
||||
|
||||
StopTicks();
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
@ -1075,50 +1213,28 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx,
|
||||
// Disable modulation at default, which means enable the field
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
||||
// Enable Peripheral Clock for
|
||||
// TIMER_CLOCK0, used to measure exact timing before answering
|
||||
// TIMER_CLOCK1, used to capture edges of the tag frames
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
|
||||
hitagS_init_clock();
|
||||
|
||||
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
||||
|
||||
// Disable timer during configuration
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
||||
|
||||
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
||||
// external trigger rising edge, load RA on falling edge of TIOA.
|
||||
AT91C_BASE_TC1->TC_CMR =
|
||||
AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
|
||||
AT91C_TC_ETRGEDG_FALLING |
|
||||
AT91C_TC_ABETRG |
|
||||
AT91C_TC_LDRA_FALLING;
|
||||
|
||||
// Enable and reset counters
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// synchronized startup procedure
|
||||
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
|
||||
|
||||
//start authentication
|
||||
// UID request standard 00110
|
||||
// UID request Advanced 1100x
|
||||
// UID request FAdvanced 11010
|
||||
size_t txlen = 0;
|
||||
size_t rxlen = 0;
|
||||
uint8_t cmd = 0x18;
|
||||
uint8_t cmd = 0x18; // 11000 UID Request Advanced
|
||||
txlen = concatbits(tx, txlen, &cmd, 8 - 5, 5);
|
||||
sendReceiveHitagS(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, true);
|
||||
|
||||
if (rxlen != 32) {
|
||||
Dbprintf("UID Request failed!");
|
||||
DbpString("UID Request failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tag.uid = (rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0]);
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("UID: %02X %02X %02X %02X", rx[0], rx[1], rx[2], rx[3]);
|
||||
}
|
||||
|
||||
//select uid
|
||||
txlen = 0;
|
||||
cmd = 0x00;
|
||||
@ -1165,25 +1281,29 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx,
|
||||
tag.LCK1 = (conf_pages[2] >> 1) & 0x1;
|
||||
tag.LCK0 = (conf_pages[2] >> 0) & 0x1;
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("conf 0: %02X conf 1: %02X conf 2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
|
||||
}
|
||||
|
||||
if (tag.auth == 1) {
|
||||
uint64_t key = 0;
|
||||
//if the tag is in authentication mode try the key or challenge
|
||||
if (htf == RHTSF_KEY || htf == WHTSF_KEY) {
|
||||
if (packet->cmd == RHTSF_KEY || packet->cmd == WHTSF_KEY) {
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
DbpString("Authenticating using key:");
|
||||
Dbhexdump(6, htd->crypto.key, false);
|
||||
Dbhexdump(6, packet->key, false);
|
||||
}
|
||||
key = ((uint64_t)htd->crypto.key[0]) << 0 |
|
||||
((uint64_t)htd->crypto.key[1]) << 8 |
|
||||
((uint64_t)htd->crypto.key[2]) << 16 |
|
||||
((uint64_t)htd->crypto.key[3]) << 24 |
|
||||
((uint64_t)htd->crypto.key[4]) << 32 |
|
||||
((uint64_t)htd->crypto.key[5]) << 40
|
||||
key = ((uint64_t)packet->key[0]) << 0 |
|
||||
((uint64_t)packet->key[1]) << 8 |
|
||||
((uint64_t)packet->key[2]) << 16 |
|
||||
((uint64_t)packet->key[3]) << 24 |
|
||||
((uint64_t)packet->key[4]) << 32 |
|
||||
((uint64_t)packet->key[5]) << 40
|
||||
;
|
||||
|
||||
uint64_t state = ht2_hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
|
||||
|
||||
uint8_t auth_ks[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auth_ks[i] = ht2_hitag2_byte(&state) ^ 0xff;
|
||||
@ -1194,37 +1314,44 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx,
|
||||
txlen = concatbits(tx, txlen, revrnd, 0, 32);
|
||||
txlen = concatbits(tx, txlen, auth_ks, 0, 32);
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0],
|
||||
tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]);
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X"
|
||||
, tx[0], tx[1], tx[2], tx[3]
|
||||
, tx[4], tx[5], tx[6], tx[7]
|
||||
);
|
||||
}
|
||||
|
||||
} else if (packet->cmd == RHTSF_CHALLENGE || packet->cmd == WHTSF_CHALLENGE) {
|
||||
|
||||
} else if (htf == RHTSF_CHALLENGE || htf == WHTSF_CHALLENGE) {
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
DbpString("Authenticating using nr,ar pair:");
|
||||
Dbhexdump(8, htd->auth.NrAr, false);
|
||||
Dbhexdump(8, packet->NrAr, false);
|
||||
}
|
||||
|
||||
uint64_t NrAr = 0;
|
||||
NrAr = ((uint64_t)htd->auth.NrAr[7]) << 0 |
|
||||
((uint64_t)htd->auth.NrAr[6]) << 8 |
|
||||
((uint64_t)htd->auth.NrAr[5]) << 16 |
|
||||
((uint64_t)htd->auth.NrAr[4]) << 24 |
|
||||
((uint64_t)htd->auth.NrAr[3]) << 32 |
|
||||
((uint64_t)htd->auth.NrAr[2]) << 40 |
|
||||
((uint64_t)htd->auth.NrAr[1]) << 48 |
|
||||
((uint64_t)htd->auth.NrAr[0]) << 56;
|
||||
NrAr = ((uint64_t)packet->NrAr[7]) << 0 |
|
||||
((uint64_t)packet->NrAr[6]) << 8 |
|
||||
((uint64_t)packet->NrAr[5]) << 16 |
|
||||
((uint64_t)packet->NrAr[4]) << 24 |
|
||||
((uint64_t)packet->NrAr[3]) << 32 |
|
||||
((uint64_t)packet->NrAr[2]) << 40 |
|
||||
((uint64_t)packet->NrAr[1]) << 48 |
|
||||
((uint64_t)packet->NrAr[0]) << 56;
|
||||
|
||||
txlen = 64;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
tx[i] = ((NrAr >> (56 - (i * 8))) & 0xFF);
|
||||
}
|
||||
|
||||
} else {
|
||||
Dbprintf("Error , unknown function: %d", htf);
|
||||
Dbprintf("Error , unknown function: " _RED_("%d"), packet->cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sendReceiveHitagS(tx, txlen, rx, sizeofrx, &rxlen, t_wait, ledcontrol, false);
|
||||
|
||||
if (rxlen != 40) {
|
||||
Dbprintf("Authenticate failed! %i", rxlen);
|
||||
Dbprintf("Authenticate failed! " _RED_("%i"), rxlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1238,19 +1365,21 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx,
|
||||
pwdh0 = 0;
|
||||
pwdl0 = 0;
|
||||
pwdl1 = 0;
|
||||
if (htf == RHTSF_KEY || htf == WHTSF_KEY) {
|
||||
if (packet->cmd == RHTSF_KEY || packet->cmd == WHTSF_KEY) {
|
||||
|
||||
uint64_t state = ht2_hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ht2_hitag2_byte(&state);
|
||||
}
|
||||
|
||||
uint8_t con2 = rx[0] ^ ht2_hitag2_byte(&state);
|
||||
pwdh0 = rx[1] ^ ht2_hitag2_byte(&state);
|
||||
pwdl0 = rx[2] ^ ht2_hitag2_byte(&state);
|
||||
pwdl1 = rx[3] ^ ht2_hitag2_byte(&state);
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("con2 %02X pwdh0 %02X pwdl0 %02X pwdl1 %02X", con2, pwdh0, pwdl0, pwdl1);
|
||||
|
||||
}
|
||||
//Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16));
|
||||
//rnd += 1;
|
||||
}
|
||||
@ -1263,21 +1392,26 @@ static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx,
|
||||
* If the key was given the password will be decrypted.
|
||||
* Reads every page of a hitag S transpoder.
|
||||
*/
|
||||
void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol) {
|
||||
void ReadHitagS(const lf_hitag_data_t *payload, bool ledcontrol) {
|
||||
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
|
||||
uint8_t tx[HITAG_FRAME_LEN];
|
||||
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
|
||||
if (selectHitagS(payload, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
|
||||
|
||||
if (selectHitagS(htf, htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
|
||||
hitagS_stop_clock();
|
||||
set_tracing(false);
|
||||
lf_finalize(ledcontrol);
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
reply_ng(CMD_LF_HITAGS_READ, PM3_ERFTRANS, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int pageNum = 0;
|
||||
|
||||
while ((BUTTON_PRESS() == false) && (data_available() == false)) {
|
||||
|
||||
WDT_HIT();
|
||||
@ -1319,18 +1453,18 @@ void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol) {
|
||||
pageNum++;
|
||||
//display key and password if possible
|
||||
if (pageNum == 2 && tag.auth == 1 && tag.LKP) {
|
||||
if (htf == RHTSF_KEY) {
|
||||
if (payload->cmd == RHTSF_KEY) {
|
||||
Dbprintf("Page[ 2]: %02X %02X %02X %02X",
|
||||
htd->crypto.key[1],
|
||||
htd->crypto.key[0],
|
||||
payload->key[1],
|
||||
payload->key[0],
|
||||
pwdl1,
|
||||
pwdl0
|
||||
);
|
||||
Dbprintf("Page[ 3]: %02X %02X %02X %02X",
|
||||
htd->crypto.key[5],
|
||||
htd->crypto.key[4],
|
||||
htd->crypto.key[3],
|
||||
htd->crypto.key[2]
|
||||
payload->key[5],
|
||||
payload->key[4],
|
||||
payload->key[3],
|
||||
payload->key[2]
|
||||
);
|
||||
} else {
|
||||
//if the authentication is done with a challenge the key and password are unknown
|
||||
@ -1344,78 +1478,89 @@ void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hitagS_stop_clock();
|
||||
set_tracing(false);
|
||||
|
||||
lf_finalize(ledcontrol);
|
||||
|
||||
// TODO reply_mix(CMD_ACK, 1, 0, 0, 0, 0); and send dump as well, to be decoded in the client
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
reply_ng(CMD_LF_HITAGS_READ, PM3_SUCCESS, (uint8_t *)tag.pages, sizeof(tag.pages));
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticates to the Tag with the given Key or Challenge.
|
||||
* Writes the given 32Bit data into page_
|
||||
*/
|
||||
void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol) {
|
||||
void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol) {
|
||||
|
||||
bool bSuccessful = false;
|
||||
//check for valid input
|
||||
if (page == 0) {
|
||||
if (payload->page == 0) {
|
||||
Dbprintf("Error, invalid page");
|
||||
reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
reply_ng(CMD_LF_HITAGS_WRITE, PM3_EINVARG, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
|
||||
uint8_t tx[HITAG_FRAME_LEN];
|
||||
size_t txlen = 0;
|
||||
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
|
||||
if (selectHitagS(htf, htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
|
||||
int res = PM3_ESOFT;
|
||||
|
||||
if (selectHitagS(payload, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol) == -1) {
|
||||
res = PM3_ERFTRANS;
|
||||
goto write_end;
|
||||
}
|
||||
|
||||
//check if the given page exists
|
||||
if (page > tag.max_page) {
|
||||
Dbprintf("page number too big for this tag");
|
||||
if (payload->page > tag.max_page) {
|
||||
Dbprintf("Error, page number too large");
|
||||
res = PM3_EINVARG;
|
||||
goto write_end;
|
||||
}
|
||||
|
||||
//send write page request
|
||||
txlen = 0;
|
||||
|
||||
uint8_t cmd = 0x08;
|
||||
txlen = concatbits(tx, txlen, &cmd, 8 - 4, 4);
|
||||
uint8_t addr = page;
|
||||
|
||||
uint8_t addr = payload->page;
|
||||
txlen = concatbits(tx, txlen, &addr, 0, 8);
|
||||
|
||||
uint8_t crc = CRC8Hitag1Bits(tx, txlen);
|
||||
txlen = concatbits(tx, txlen, &crc, 0, 8);
|
||||
|
||||
sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, t_wait, ledcontrol, false);
|
||||
|
||||
if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) {
|
||||
Dbprintf("no write access on page %d", page);
|
||||
Dbprintf("no write access on page " _YELLOW_("%d"), payload->page);
|
||||
res = PM3_ESOFT;
|
||||
goto write_end;
|
||||
}
|
||||
|
||||
//ACK received to write the page. send data
|
||||
uint8_t data[4] = {0, 0, 0, 0};
|
||||
switch (htf) {
|
||||
switch (payload->cmd) {
|
||||
case WHTSF_CHALLENGE:
|
||||
data[0] = htd->auth.data[3];
|
||||
data[1] = htd->auth.data[2];
|
||||
data[2] = htd->auth.data[1];
|
||||
data[3] = htd->auth.data[0];
|
||||
data[0] = payload->data[3];
|
||||
data[1] = payload->data[2];
|
||||
data[2] = payload->data[1];
|
||||
data[3] = payload->data[0];
|
||||
break;
|
||||
case WHTSF_KEY:
|
||||
data[0] = htd->crypto.data[3];
|
||||
data[1] = htd->crypto.data[2];
|
||||
data[2] = htd->crypto.data[1];
|
||||
data[3] = htd->crypto.data[0];
|
||||
data[0] = payload->data[3];
|
||||
data[1] = payload->data[2];
|
||||
data[2] = payload->data[1];
|
||||
data[3] = payload->data[0];
|
||||
break;
|
||||
default:
|
||||
default: {
|
||||
res = PM3_EINVARG;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
txlen = 0;
|
||||
txlen = concatbits(tx, txlen, data, 0, 32);
|
||||
crc = CRC8Hitag1Bits(tx, txlen);
|
||||
@ -1424,16 +1569,16 @@ void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool l
|
||||
sendReceiveHitagS(tx, txlen, rx, ARRAYLEN(rx), &rxlen, t_wait, ledcontrol, false);
|
||||
|
||||
if ((rxlen != 2) || (rx[0] >> (8 - 2) != 0x1)) {
|
||||
Dbprintf("write on page %d failed", page);
|
||||
res = PM3_ESOFT; // write failed
|
||||
} else {
|
||||
Dbprintf("write on page %d successful", page);
|
||||
bSuccessful = true;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
|
||||
write_end:
|
||||
hitagS_stop_clock();
|
||||
set_tracing(false);
|
||||
lf_finalize(ledcontrol);
|
||||
reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
reply_ng(CMD_LF_HITAGS_WRITE, res, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1444,10 +1589,11 @@ write_end:
|
||||
* detects these challenges.
|
||||
*/
|
||||
void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol) {
|
||||
|
||||
//check for valid input
|
||||
if (datalen < 8) {
|
||||
Dbprintf("Error, need chals");
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
Dbprintf("Error, missing challenges");
|
||||
reply_ng(CMD_LF_HITAGS_TEST_TRACES, PM3_EINVARG, NULL, 0);
|
||||
return;
|
||||
}
|
||||
uint32_t dataoffset = 0;
|
||||
@ -1460,38 +1606,42 @@ void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontr
|
||||
// Watchdog hit
|
||||
WDT_HIT();
|
||||
|
||||
hitag_data htd;
|
||||
memset(&htd, 0, sizeof(htd));
|
||||
lf_hitag_data_t payload;
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
payload.cmd = RHTSF_CHALLENGE;
|
||||
|
||||
memcpy(htd.auth.NrAr, data + dataoffset, 8);
|
||||
memcpy(payload.NrAr, data + dataoffset, 8);
|
||||
|
||||
int res = selectHitagS(RHTSF_CHALLENGE, &htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
|
||||
int res = selectHitagS(&payload, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
|
||||
Dbprintf("Challenge %s: %02X %02X %02X %02X %02X %02X %02X %02X",
|
||||
res == -1 ? "failed " : "success",
|
||||
htd.auth.NrAr[0], htd.auth.NrAr[1],
|
||||
htd.auth.NrAr[2], htd.auth.NrAr[3],
|
||||
htd.auth.NrAr[4], htd.auth.NrAr[5],
|
||||
htd.auth.NrAr[6], htd.auth.NrAr[7]
|
||||
payload.NrAr[0], payload.NrAr[1],
|
||||
payload.NrAr[2], payload.NrAr[3],
|
||||
payload.NrAr[4], payload.NrAr[5],
|
||||
payload.NrAr[6], payload.NrAr[7]
|
||||
);
|
||||
|
||||
if (res == -1) {
|
||||
// Need to do a dummy UID select that will fail
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(2);
|
||||
selectHitagS(RHTSF_CHALLENGE, &htd, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
|
||||
selectHitagS(&payload, tx, ARRAYLEN(tx), rx, ARRAYLEN(rx), t_wait, ledcontrol);
|
||||
}
|
||||
|
||||
dataoffset += 8;
|
||||
if (dataoffset >= datalen - 8)
|
||||
if (dataoffset >= datalen - 8) {
|
||||
break;
|
||||
}
|
||||
// reset field
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
// min t_reset = 2ms
|
||||
SpinDelay(2);
|
||||
}
|
||||
|
||||
hitagS_stop_clock();
|
||||
set_tracing(false);
|
||||
lf_finalize(ledcontrol);
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
reply_ng(CMD_ACK, PM3_SUCCESS, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -22,11 +22,10 @@
|
||||
#define _HITAGS_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "hitag.h"
|
||||
|
||||
void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol);
|
||||
void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol);
|
||||
void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
|
||||
void ReadHitagS(const lf_hitag_data_t *payload, bool ledcontrol);
|
||||
void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol);
|
||||
void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol);
|
||||
#endif
|
||||
|
@ -263,6 +263,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/common/cardhelper.c
|
||||
${PM3_ROOT}/common/generator.c
|
||||
${PM3_ROOT}/common/bruteforce.c
|
||||
${PM3_ROOT}/common/hitag2/hitag2_crypto.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1dump.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1utils.c
|
||||
${PM3_ROOT}/client/src/crypto/libpcrypto.c
|
||||
|
@ -1,13 +1,25 @@
|
||||
#
|
||||
# Mifare Default Keys
|
||||
# -- Iceman version --
|
||||
# -- contribute to this list, sharing is caring --
|
||||
#
|
||||
# Lets see how long it takes before other project takes this file
|
||||
# and claim they created it.
|
||||
#
|
||||
# factory HT2 pwd
|
||||
4D494B52
|
||||
# factory HT2 crypto key
|
||||
4F4E4D494B52
|
||||
#
|
||||
# GE HT2 reader
|
||||
#
|
||||
# TSPL
|
||||
5453504C
|
||||
05040202
|
||||
25293C2F
|
||||
# Gone in 360 seconds
|
||||
FFFF814632FF
|
||||
#
|
||||
# Paxton HT2
|
||||
BDF5E846
|
||||
#
|
||||
#
|
||||
# GE HT2 reader
|
||||
# TSPL
|
||||
5453504C
|
||||
05040202
|
||||
25293C2F
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define HITAG_NRAR_SIZE 8
|
||||
#define HITAG_CRYPTOKEY_SIZE 6
|
||||
#define HITAG_PASSWORD_SIZE 4
|
||||
#define HITAG_UID_SIZE 4
|
||||
@ -37,16 +38,18 @@
|
||||
|
||||
#define HITAG2_CONFIG_BLOCK 3
|
||||
#define HITAG2_CONFIG_OFFSET (HITAG_BLOCK_SIZE * HITAG2_CONFIG_BLOCK)
|
||||
#define HITAG_DICTIONARY "ht2_default"
|
||||
|
||||
int CmdLFHitag(const char *Cmd);
|
||||
|
||||
int readHitagUid(void);
|
||||
void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
||||
void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response);
|
||||
void annotateHitag2(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits, bool is_response, const uint64_t *keys, uint32_t keycount, bool isdecrypted);
|
||||
void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
||||
|
||||
void annotateHitag2_init(void);
|
||||
|
||||
bool hitag2_get_plain(uint8_t *plain, uint8_t *plen);
|
||||
void hitag2_annotate_plain(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, uint8_t bits);
|
||||
|
||||
uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit);
|
||||
#endif
|
||||
|
@ -501,7 +501,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
|
||||
uint32_t end_of_transmission_timestamp = 0;
|
||||
uint8_t topaz_reader_command[9];
|
||||
char explanation[40] = {0};
|
||||
char explanation[60] = {0};
|
||||
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
|
||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||
|
||||
@ -736,9 +736,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
|
||||
// mark short bytes (less than 8 Bit + Parity)
|
||||
if (protocol == ISO_14443A ||
|
||||
protocol == PROTO_MIFARE ||
|
||||
protocol == PROTO_MFPLUS ||
|
||||
protocol == THINFILM) {
|
||||
protocol == PROTO_MIFARE ||
|
||||
protocol == PROTO_MFPLUS ||
|
||||
protocol == THINFILM) {
|
||||
|
||||
// approximated with 128 * (9 * data_len);
|
||||
uint16_t bitime = 1056 + 32;
|
||||
@ -774,10 +774,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
|
||||
end_of_transmission_timestamp = hdr->timestamp + duration;
|
||||
|
||||
if (prev_eot)
|
||||
if (prev_eot) {
|
||||
*prev_eot = end_of_transmission_timestamp;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Always annotate these protocols both reader/tag messages
|
||||
switch (protocol) {
|
||||
@ -793,7 +792,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
annotateHitag1(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||
break;
|
||||
case PROTO_HITAG2:
|
||||
annotateHitag2(explanation, sizeof(explanation), frame, data_len, parityBytes[0], hdr->isResponse);
|
||||
annotateHitag2(explanation, sizeof(explanation), frame, data_len, parityBytes[0], hdr->isResponse, mfDicKeys, mfDicKeysCount, false);
|
||||
break;
|
||||
case PROTO_HITAGS:
|
||||
annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||
@ -979,6 +978,71 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
}
|
||||
}
|
||||
|
||||
if (protocol == PROTO_HITAG2) {
|
||||
|
||||
uint8_t ht2plain[9] = {0};
|
||||
uint8_t n = 0;
|
||||
if (hitag2_get_plain(ht2plain, &n)) {
|
||||
|
||||
memset(explanation, 0x00, sizeof(explanation));
|
||||
|
||||
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
|
||||
// This part prints the number of bits in the trace entry for hitag.
|
||||
uint8_t nbits = parityBytes[0];
|
||||
|
||||
annotateHitag2(explanation, sizeof(explanation), ht2plain, n, nbits, hdr->isResponse, NULL, 0, true);
|
||||
|
||||
// iceman: colorise crc bytes here will need a refactor of code from above.
|
||||
for (int j = 0; j < n && (j / TRACE_MAX_HEX_BYTES) < TRACE_MAX_HEX_BYTES; j++) {
|
||||
|
||||
|
||||
if (j == 0) {
|
||||
|
||||
// only apply this to lesser than one byte
|
||||
if (n == 1) {
|
||||
|
||||
if (nbits == 5) {
|
||||
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
|
||||
} else {
|
||||
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (nbits == 0) {
|
||||
snprintf(line[0], 120, "%2u: %02X ", (n * 8), ht2plain[0]);
|
||||
} else {
|
||||
snprintf(line[0], 120, "%2u: %02X ", ((n - 1) * 8) + nbits, ht2plain[0]);
|
||||
}
|
||||
}
|
||||
offset = 4;
|
||||
|
||||
} else {
|
||||
snprintf(line[j / 18] + ((j % 18) * 4) + offset, 120, "%02X ", ht2plain[j]);
|
||||
}
|
||||
}
|
||||
|
||||
num_lines = MIN((n - 1) / TRACE_MAX_HEX_BYTES + 1, TRACE_MAX_HEX_BYTES);
|
||||
|
||||
for (int j = 0; j < num_lines ; j++) {
|
||||
if (hdr->isResponse) {
|
||||
PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s",
|
||||
str_padder,
|
||||
line[j],
|
||||
" ",
|
||||
explanation);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " | | * |" _YELLOW_("%-*s")" | " _YELLOW_("%s") "| " _YELLOW_("%s"),
|
||||
str_padder,
|
||||
line[j],
|
||||
" ",
|
||||
explanation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_last_record(tracepos, traceLen)) {
|
||||
return traceLen;
|
||||
}
|
||||
@ -1416,7 +1480,7 @@ int CmdTraceList(const char *Cmd) {
|
||||
if (diclen > 0) {
|
||||
uint8_t *keyBlock = NULL;
|
||||
int res = loadFileDICTIONARY_safe(dictionary, (void **) &keyBlock, 6, &dicKeysCount);
|
||||
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
|
||||
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
|
||||
PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)");
|
||||
} else {
|
||||
dicKeys = calloc(dicKeysCount, sizeof(uint64_t));
|
||||
@ -1436,6 +1500,30 @@ int CmdTraceList(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( protocol == PROTO_HITAG2) {
|
||||
|
||||
if (strlen(dictionary) == 0) {
|
||||
snprintf(dictionary, sizeof(dictionary), HITAG_DICTIONARY);
|
||||
}
|
||||
|
||||
// load keys
|
||||
uint8_t *keyBlock = NULL;
|
||||
int res = loadFileDICTIONARY_safe(dictionary, (void **) &keyBlock, HITAG_CRYPTOKEY_SIZE, &dicKeysCount);
|
||||
if (res != PM3_SUCCESS || dicKeysCount == 0 || keyBlock == NULL) {
|
||||
PrintAndLogEx(FAILED, "An error occurred while loading the dictionary!");
|
||||
} else {
|
||||
dicKeys = calloc(dicKeysCount, sizeof(uint64_t));
|
||||
for (int i = 0; i < dicKeysCount; i++) {
|
||||
uint64_t key = bytes_to_num(keyBlock + i * HITAG_CRYPTOKEY_SIZE, HITAG_CRYPTOKEY_SIZE);
|
||||
memcpy((uint8_t *) &dicKeys[i], &key, sizeof(uint64_t));
|
||||
}
|
||||
dictionaryLoad = true;
|
||||
}
|
||||
if (keyBlock != NULL) {
|
||||
free(keyBlock);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (use_relative) {
|
||||
PrintAndLogEx(NORMAL, " Gap | Duration | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation");
|
||||
@ -1463,16 +1551,19 @@ int CmdTraceList(const char *Cmd) {
|
||||
while (tracepos < gs_traceLen) {
|
||||
tracepos = printTraceLine(tracepos, gs_traceLen, gs_trace, protocol, show_wait_cycles, mark_crc, prev_EOT, use_us, dicKeys, dicKeysCount);
|
||||
|
||||
if (kbd_enter_pressed())
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionaryLoad)
|
||||
if (dictionaryLoad) {
|
||||
free((void *) dicKeys);
|
||||
}
|
||||
}
|
||||
|
||||
if (show_hex)
|
||||
if (show_hex) {
|
||||
PrintAndLogEx(HINT, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -127,34 +127,38 @@ void des3_decrypt(void *out, const void *in, const void *key, uint8_t keycount)
|
||||
// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001.
|
||||
int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
|
||||
uint8_t iiv[16] = {0};
|
||||
if (iv)
|
||||
if (iv) {
|
||||
memcpy(iiv, iv, 16);
|
||||
}
|
||||
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
if (mbedtls_aes_setkey_enc(&aes, key, 128))
|
||||
if (mbedtls_aes_setkey_enc(&aes, key, 128)) {
|
||||
return 1;
|
||||
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output))
|
||||
}
|
||||
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output)) {
|
||||
return 2;
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) {
|
||||
uint8_t iiv[16] = {0};
|
||||
if (iv)
|
||||
if (iv) {
|
||||
memcpy(iiv, iv, 16);
|
||||
}
|
||||
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
if (mbedtls_aes_setkey_dec(&aes, key, 128))
|
||||
if (mbedtls_aes_setkey_dec(&aes, key, 128)) {
|
||||
return 1;
|
||||
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output))
|
||||
}
|
||||
if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output)) {
|
||||
return 2;
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication.
|
||||
@ -171,13 +175,14 @@ int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int lengt
|
||||
memset(mac, 0x00, 8);
|
||||
|
||||
int res = aes_cmac(iv, key, input, cmac_tmp, length);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
mac[i] = cmac_tmp[i * 2 + 1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t fixed_rand_value[250] = {0};
|
||||
@ -188,21 +193,23 @@ static int fixed_rand(void *rng_state, unsigned char *output, size_t len) {
|
||||
memset(output, 0x00, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int sha1hash(uint8_t *input, int length, uint8_t *hash) {
|
||||
if (!hash || !input)
|
||||
if (!hash || !input) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
mbedtls_sha1(input, length, hash);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int sha256hash(uint8_t *input, int length, uint8_t *hash) {
|
||||
if (!hash || !input)
|
||||
if (!hash || !input) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
mbedtls_sha256_context sctx;
|
||||
mbedtls_sha256_init(&sctx);
|
||||
@ -211,12 +218,13 @@ int sha256hash(uint8_t *input, int length, uint8_t *hash) {
|
||||
mbedtls_sha256_finish(&sctx, hash);
|
||||
mbedtls_sha256_free(&sctx);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int sha512hash(uint8_t *input, int length, uint8_t *hash) {
|
||||
if (!hash || !input)
|
||||
if (!hash || !input) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
mbedtls_sha512_context sctx;
|
||||
mbedtls_sha512_init(&sctx);
|
||||
@ -225,33 +233,35 @@ int sha512hash(uint8_t *input, int length, uint8_t *hash) {
|
||||
mbedtls_sha512_finish(&sctx, hash);
|
||||
mbedtls_sha512_free(&sctx);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int ecdsa_init_str(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, const char *key_d, const char *key_x, const char *key_y) {
|
||||
if (!ctx)
|
||||
if (!ctx) {
|
||||
return 1;
|
||||
|
||||
int res;
|
||||
}
|
||||
|
||||
mbedtls_ecdsa_init(ctx);
|
||||
res = mbedtls_ecp_group_load(&ctx->grp, curveid);
|
||||
if (res)
|
||||
int res = mbedtls_ecp_group_load(&ctx->grp, curveid);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (key_d) {
|
||||
res = mbedtls_mpi_read_string(&ctx->d, 16, key_d);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_x && key_y) {
|
||||
res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y);
|
||||
if (res)
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
|
||||
@ -278,7 +288,7 @@ static int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveid,
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int ecdsa_key_create(mbedtls_ecp_group_id curveid, uint8_t *key_d, uint8_t *key_xy) {
|
||||
@ -519,8 +529,9 @@ int ecdsa_nist_test(bool verbose) {
|
||||
size_t siglen = 0;
|
||||
|
||||
// NIST ecdsa test
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, " ECDSA NIST test: " NOLF);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "ECDSA NIST test " NOLF);
|
||||
}
|
||||
// make signature
|
||||
res = ecdsa_signature_create_test(curveid, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen);
|
||||
// PrintAndLogEx(INFO, "res: %x signature[%x]: %s", (res < 0)? -res : res, siglen, sprint_hex(signature, siglen));
|
||||
@ -540,15 +551,16 @@ int ecdsa_nist_test(bool verbose) {
|
||||
uint8_t sval_s[33] = {0};
|
||||
param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen);
|
||||
if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) {
|
||||
PrintAndLogEx(INFO, "R or S check error");
|
||||
PrintAndLogEx(NORMAL, "( " _RED_("R or S check error") " )");
|
||||
res = 100;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// verify signature
|
||||
res = ecdsa_signature_verify_keystr(curveid, T_Q_X, T_Q_Y, input, length, signature, siglen, true);
|
||||
if (res)
|
||||
if (res) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// verify wrong signature
|
||||
input[0] ^= 0xFF;
|
||||
@ -559,8 +571,8 @@ int ecdsa_nist_test(bool verbose) {
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(NORMAL, _GREEN_("passed"));
|
||||
PrintAndLogEx(INFO, " ECDSA binary signature create/check test: " NOLF);
|
||||
PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
|
||||
PrintAndLogEx(INFO, "ECDSA binary signature create/check test " NOLF);
|
||||
}
|
||||
|
||||
// random ecdsa test
|
||||
@ -587,12 +599,12 @@ int ecdsa_nist_test(bool verbose) {
|
||||
goto exit;
|
||||
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, _GREEN_("passed\n"));
|
||||
PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
exit:
|
||||
if (verbose)
|
||||
PrintAndLogEx(NORMAL, _RED_("failed\n"));
|
||||
PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,15 @@
|
||||
// Hitag2 Crypto
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "hitag2_crypto.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "util.h"
|
||||
#include "string.h"
|
||||
#include "commonutil.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
#include "ui.h"
|
||||
#endif
|
||||
|
||||
/* 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.
|
||||
@ -27,39 +32,337 @@
|
||||
// No warranties or guarantees of any kind.
|
||||
// This code is released into the public domain by its author.
|
||||
|
||||
|
||||
// Single bit Hitag2 functions:
|
||||
#ifndef i4
|
||||
#define i4(x,a,b,c,d) ((uint32_t)((((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))
|
||||
#endif
|
||||
|
||||
static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
|
||||
static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
|
||||
static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
|
||||
static uint32_t ht2_f20(const uint64_t x) {
|
||||
uint32_t i5;
|
||||
static uint32_t ht2_f20(const uint64_t state) {
|
||||
|
||||
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, 16, 20, 22, 25)) & 1) * 4
|
||||
+ ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8
|
||||
+ ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16;
|
||||
uint32_t i5 = ((ht2_f4a >> i4(state, 1, 2, 4, 5)) & 1) * 1
|
||||
+ ((ht2_f4b >> i4(state, 7, 11, 13, 14)) & 1) * 2
|
||||
+ ((ht2_f4b >> i4(state, 16, 20, 22, 25)) & 1) * 4
|
||||
+ ((ht2_f4b >> i4(state, 27, 28, 30, 32)) & 1) * 8
|
||||
+ ((ht2_f4a >> i4(state, 33, 42, 43, 45)) & 1) * 16;
|
||||
|
||||
return (ht2_f5c >> i5) & 1;
|
||||
}
|
||||
|
||||
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
|
||||
uint32_t i;
|
||||
// return a single bit from a value
|
||||
static int ht2_bitn(uint64_t x, int bit) {
|
||||
const uint64_t bitmask = (uint64_t)(1) << bit;
|
||||
return (x & bitmask) ? 1 : 0;
|
||||
}
|
||||
|
||||
// the sub-function R that rollback depends upon
|
||||
int ht2_fnR(uint64_t state) {
|
||||
// renumbered bits because my state is 0-47, not 1-48
|
||||
return (
|
||||
ht2_bitn(state, 1) ^ ht2_bitn(state, 2) ^ ht2_bitn(state, 5) ^
|
||||
ht2_bitn(state, 6) ^ ht2_bitn(state, 7) ^ ht2_bitn(state, 15) ^
|
||||
ht2_bitn(state, 21) ^ ht2_bitn(state, 22) ^ ht2_bitn(state, 25) ^
|
||||
ht2_bitn(state, 29) ^ ht2_bitn(state, 40) ^ ht2_bitn(state, 41) ^
|
||||
ht2_bitn(state, 42) ^ ht2_bitn(state, 45) ^ ht2_bitn(state, 46) ^
|
||||
ht2_bitn(state, 47)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
static void ht2_rollback(hitag_state_t *hstate, unsigned int steps) {
|
||||
for (int i = 0; i < steps; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | ht2_fnR(hstate->shiftreg);
|
||||
}
|
||||
}
|
||||
*/
|
||||
// the rollback function that lets us go backwards in time
|
||||
void ht2_rollback(hitag_state_t *hstate, uint32_t steps) {
|
||||
for (uint32_t i = 0; i < steps; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | ht2_fnR(hstate->shiftreg);
|
||||
hstate->lfsr = LFSR_INV(hstate->lfsr);
|
||||
}
|
||||
}
|
||||
|
||||
// the three filter sub-functions that feed fnf
|
||||
#define ht2_fa(x) ht2_bitn(0x2C79, (x))
|
||||
#define ht2_fb(x) ht2_bitn(0x6671, (x))
|
||||
#define ht2_fc(x) ht2_bitn(0x7907287B, (x))
|
||||
|
||||
// the filter function that generates a bit of output from the prng state
|
||||
int ht2_fnf(uint64_t state) {
|
||||
|
||||
uint32_t x1 = (ht2_bitn(state, 2) << 0) | (ht2_bitn(state, 3) << 1) | (ht2_bitn(state, 5) << 2) | (ht2_bitn(state, 6) << 3);
|
||||
uint32_t x2 = (ht2_bitn(state, 8) << 0) | (ht2_bitn(state, 12) << 1) | (ht2_bitn(state, 14) << 2) | (ht2_bitn(state, 15) << 3);
|
||||
uint32_t x3 = (ht2_bitn(state, 17) << 0) | (ht2_bitn(state, 21) << 1) | (ht2_bitn(state, 23) << 2) | (ht2_bitn(state, 26) << 3);
|
||||
uint32_t x4 = (ht2_bitn(state, 28) << 0) | (ht2_bitn(state, 29) << 1) | (ht2_bitn(state, 31) << 2) | (ht2_bitn(state, 33) << 3);
|
||||
uint32_t x5 = (ht2_bitn(state, 34) << 0) | (ht2_bitn(state, 43) << 1) | (ht2_bitn(state, 44) << 2) | (ht2_bitn(state, 46) << 3);
|
||||
|
||||
uint32_t x6 = (ht2_fa(x1) << 0) | (ht2_fb(x2) << 1) | (ht2_fb(x3) << 2) | (ht2_fb(x4) << 3) | (ht2_fa(x5) << 4);
|
||||
return ht2_fc(x6);
|
||||
}
|
||||
|
||||
// builds the lfsr for the prng (quick calcs for hitag2_nstep())
|
||||
/*
|
||||
static void ht2_buildlfsr(hitag_state_t *hstate) {
|
||||
if (hstate == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t state = hstate->shiftreg;
|
||||
uint64_t temp = state ^ (state >> 1);
|
||||
hstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
*/
|
||||
#ifndef ON_DEVICE
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
uint64_t ht2_recoverkey(hitag_state_t *hstate, uint32_t uid, uint32_t nRenc) {
|
||||
|
||||
// hstate->shiftreg = (uint64_t)(((hstate->shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate->shiftreg));
|
||||
// hstate->shiftreg = (uint64_t)(((hstate->shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate->shiftreg));
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
PrintAndLogEx(INFO, "shiftreg.... %" PRIx64, hstate->shiftreg);
|
||||
#endif
|
||||
|
||||
// key lower 16 bits are lower 16 bits of prng state
|
||||
uint64_t key = hstate->shiftreg & 0xffff;
|
||||
uint32_t nRxork = (hstate->shiftreg >> 16) & 0xffffffff;
|
||||
|
||||
// rollback and extract bits b
|
||||
uint32_t b = 0;
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uid >> (31 - i)) & 0x1);
|
||||
b = (b << 1) | (unsigned int) ht2_fnf(hstate->shiftreg);
|
||||
}
|
||||
|
||||
uint32_t nR = nRenc ^ b;
|
||||
uint64_t keyupper = nRxork ^ nR;
|
||||
key = key | (keyupper << 16);
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "b..... %08" PRIx32 " %08" PRIx32 " %012" PRIx64, b, nRenc, hstate->shiftreg);
|
||||
PrintAndLogEx(INFO, "key... %012" PRIx64 " %012" PRIx64 "\n", key, REV64(key));
|
||||
#endif
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parameters:
|
||||
* Hitag_State* pstate - output, internal state after initialisation
|
||||
* uint64_t sharedkey - 48 bit key shared between reader & tag
|
||||
* uint32_t serialnum - 32 bit tag serial number
|
||||
* uint32_t iv - 32 bit random IV from reader, part of tag authentication
|
||||
*/
|
||||
void ht2_hitag2_init_ex(hitag_state_t *hstate, uint64_t sharedkey, uint32_t serialnum, uint32_t iv) {
|
||||
// init state, from serial number and lowest 16 bits of shared key
|
||||
uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum;
|
||||
|
||||
// mix the initialisation vector and highest 32 bits of the shared key
|
||||
iv ^= (uint32_t)(sharedkey >> 16);
|
||||
|
||||
// move 16 bits from (IV xor Shared Key) to top of uint64_t state
|
||||
// these will be XORed in turn with output of the crypto function
|
||||
state |= (uint64_t) iv << 48;
|
||||
iv >>= 16;
|
||||
|
||||
// unrolled loop is faster on PIC32 (MIPS), do 32 times
|
||||
// shift register, then calc new bit
|
||||
state >>= 1;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
|
||||
// highest 16 bits of IV XOR Shared Key
|
||||
state |= (uint64_t) iv << 47;
|
||||
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state = (state >> 1) ^ (uint64_t) ht2_f20(state) << 46;
|
||||
state ^= (uint64_t) ht2_f20(state) << 47;
|
||||
|
||||
// LSFR
|
||||
|
||||
hstate->shiftreg = state;
|
||||
/* naive version for reference, LFSR has 16 taps
|
||||
pstate->lfsr = state ^ (state >> 2) ^ (state >> 3) ^ (state >> 6)
|
||||
^ (state >> 7) ^ (state >> 8) ^ (state >> 16) ^ (state >> 22)
|
||||
^ (state >> 23) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (state >> 42) ^ (state >> 43) ^ (state >> 46) ^ (state >> 47);
|
||||
*/
|
||||
{
|
||||
// optimise with one 64-bit intermediate
|
||||
uint64_t temp = state ^ (state >> 1);
|
||||
hstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return up to 32 crypto bits.
|
||||
* Last bit is in least significant bit, earlier bits are shifted left.
|
||||
* Note that the Hitag transmission protocol is least significant bit,
|
||||
* so we may want to change this, or add a function, that returns the
|
||||
* crypto output bits in the other order.
|
||||
*
|
||||
* Parameters:
|
||||
* Hitag_State* pstate - in/out, internal cipher state after initialisation
|
||||
* uint32_t steps - number of bits requested, (capped at 32)
|
||||
*/
|
||||
uint32_t ht2_hitag2_nstep(hitag_state_t *hstate, uint32_t steps) {
|
||||
uint64_t state = hstate->shiftreg;
|
||||
uint32_t result = 0;
|
||||
uint64_t lfsr = hstate->lfsr;
|
||||
|
||||
if (steps == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
// update shift registers
|
||||
if (lfsr & 1) {
|
||||
state = (state >> 1) | 0x800000000000;
|
||||
lfsr = (lfsr >> 1) ^ 0xB38083220073;
|
||||
// accumulate next bit of crypto
|
||||
result = (result << 1) | ht2_f20(state);
|
||||
} else {
|
||||
state >>= 1;
|
||||
lfsr >>= 1;
|
||||
result = (result << 1) | ht2_f20(state);
|
||||
}
|
||||
} while (--steps);
|
||||
|
||||
hstate->shiftreg = state;
|
||||
hstate->lfsr = lfsr;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t iv) {
|
||||
|
||||
uint64_t x = ((key & 0xFFFF) << 32) + serial;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (uint32_t i = 0; i < 32; i++) {
|
||||
x >>= 1;
|
||||
x += (uint64_t)(ht2_f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
|
||||
x += (uint64_t)(ht2_f20(x) ^ (((iv >> i) ^ (key >> (i + 16))) & 1)) << 47;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
uint64_t ht2_hitag2_round(uint64_t *state) {
|
||||
int ht2_try_state(uint64_t s, uint32_t uid, uint32_t aR2, uint32_t nR1, uint32_t nR2, uint64_t *key) {
|
||||
|
||||
hitag_state_t hstate;
|
||||
hstate.shiftreg = s;
|
||||
hstate.lfsr = 0;
|
||||
|
||||
hstate.shiftreg = (uint64_t)(((hstate.shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate.shiftreg));
|
||||
hstate.shiftreg = (uint64_t)(((hstate.shiftreg << 1) & 0xffffffffffff) | (uint64_t)ht2_fnR(hstate.shiftreg));
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
hitag_state_t hs2;
|
||||
hs2.shiftreg = s;
|
||||
hs2.lfsr = 0;
|
||||
ht2_rollback(&hs2, 2);
|
||||
|
||||
PrintAndLogEx(INFO, "hstate shiftreg.... %" PRIx64 " lfsr... %" PRIx64, hstate.shiftreg, hstate.lfsr);
|
||||
PrintAndLogEx(INFO, "hstate shiftreg.... %" PRIx64 " lfsr... %" PRIx64, hs2.shiftreg, hs2.lfsr);
|
||||
#endif
|
||||
|
||||
// recover key
|
||||
uint64_t keyrev = hstate.shiftreg & 0xffff;
|
||||
uint64_t nR1xk = (hstate.shiftreg >> 16) & 0xffffffff;
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
PrintAndLogEx(INFO, "keyrev...... %012" PRIx64 " nR1xk... %08" PRIx64, keyrev, nR1xk);
|
||||
#endif
|
||||
|
||||
uint32_t b = 0;
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
hstate.shiftreg = ((hstate.shiftreg) << 1) | ((uid >> (31 - i)) & 0x1);
|
||||
b = (b << 1) | (unsigned int) ht2_fnf(hstate.shiftreg);
|
||||
}
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
PrintAndLogEx(INFO, "b..... %08" PRIx32 " %08" PRIx32 " %012" PRIx64, b, nR1, hstate.shiftreg);
|
||||
#endif
|
||||
|
||||
keyrev |= (nR1xk ^ nR1 ^ b) << 16;
|
||||
|
||||
#ifndef ON_DEVICE
|
||||
PrintAndLogEx(INFO, "key... %012" PRIx64 " %012" PRIx64, keyrev, REV64(keyrev));
|
||||
#endif
|
||||
|
||||
// test key
|
||||
ht2_hitag2_init_ex(&hstate, keyrev, uid, nR2);
|
||||
|
||||
if ((aR2 ^ ht2_hitag2_nstep(&hstate, 32)) == 0xFFFFFFFF) {
|
||||
*key = REV64(keyrev);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
||||
// "MIKRON" = O N M I K R
|
||||
// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key
|
||||
// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear
|
||||
// Random = 65 6E 45 72 - Random IV, transmitted in clear
|
||||
//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream
|
||||
|
||||
// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6".
|
||||
// The inverse of the first 4 bytes is sent to the tag to authenticate.
|
||||
// The rest is encrypted by XORing it with the subsequent keystream.
|
||||
|
||||
/*
|
||||
* Return 8 crypto bits.
|
||||
* Last bit is in least significant bit, earlier bits are shifted left.
|
||||
* Note that the Hitag transmission protocol is least significant bit,
|
||||
* so we may want to change this, or add a function, that returns the
|
||||
* crypto output bits in the other order.
|
||||
*
|
||||
* Parameters:
|
||||
* uint64_t *state - in/out, internal cipher state after initialisation
|
||||
*/
|
||||
uint64_t ht2_hitag2_bit(uint64_t *state) {
|
||||
uint64_t x = *state;
|
||||
|
||||
x = (x >> 1) +
|
||||
@ -72,21 +375,25 @@ uint64_t ht2_hitag2_round(uint64_t *state) {
|
||||
return ht2_f20(x);
|
||||
}
|
||||
|
||||
// "MIKRON" = O N M I K R
|
||||
// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key
|
||||
// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear
|
||||
// Random = 65 6E 45 72 - Random IV, transmitted in clear
|
||||
//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream
|
||||
// Take a state and create one byte (8bits) of crypto
|
||||
uint32_t ht2_hitag2_byte(uint64_t *state) {
|
||||
uint32_t c = 0;
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 7; // 7
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 6; // 6
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 5; // 5
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 4;
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 3;
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 2;
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 1;
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6".
|
||||
// The inverse of the first 4 bytes is sent to the tag to authenticate.
|
||||
// The rest is encrypted by XORing it with the subsequent keystream.
|
||||
|
||||
uint32_t ht2_hitag2_byte(uint64_t *x) {
|
||||
uint32_t i, c;
|
||||
for (i = 0, c = 0; i < 8; i++) {
|
||||
c += (uint32_t) ht2_hitag2_round(x) << (i ^ 7);
|
||||
}
|
||||
uint32_t ht2_hitag2_word(uint64_t *state, uint32_t steps) {
|
||||
uint32_t c = 0;
|
||||
do {
|
||||
c += (uint32_t) ht2_hitag2_bit(state) << (steps - 1);
|
||||
} while (--steps);
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -108,19 +415,23 @@ void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv) {
|
||||
tag->cs = ht2_hitag2_init(REV64(key), REV32(uid), REV32(iv_));
|
||||
}
|
||||
|
||||
int ht2_hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) {
|
||||
int ht2_hitag2_cipher_authenticate(uint64_t *state, const uint8_t *authenticator_is) {
|
||||
uint8_t authenticator_should[4];
|
||||
authenticator_should[0] = ~ht2_hitag2_byte(cs);
|
||||
authenticator_should[1] = ~ht2_hitag2_byte(cs);
|
||||
authenticator_should[2] = ~ht2_hitag2_byte(cs);
|
||||
authenticator_should[3] = ~ht2_hitag2_byte(cs);
|
||||
authenticator_should[0] = ~ht2_hitag2_byte(state);
|
||||
authenticator_should[1] = ~ht2_hitag2_byte(state);
|
||||
authenticator_should[2] = ~ht2_hitag2_byte(state);
|
||||
authenticator_should[3] = ~ht2_hitag2_byte(state);
|
||||
return (memcmp(authenticator_should, authenticator_is, 4) == 0);
|
||||
}
|
||||
|
||||
int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) {
|
||||
void ht2_hitag2_cipher_transcrypt(uint64_t *state, uint8_t *data, uint16_t bytes, uint16_t bits) {
|
||||
int i;
|
||||
for (i = 0; i < bytes; i++) data[i] ^= ht2_hitag2_byte(cs);
|
||||
for (i = 0; i < bits; i++) data[bytes] ^= ht2_hitag2_round(cs) << (7 - i);
|
||||
return 0;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
data[i] ^= ht2_hitag2_byte(state);
|
||||
}
|
||||
|
||||
for (i = 0; i < bits; i++) {
|
||||
data[bytes] ^= ht2_hitag2_bit(state) << (7 - i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,12 @@
|
||||
#define __HITAG2_CRYPTO_H
|
||||
|
||||
#include "common.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef LFSR_INV
|
||||
#define LFSR_INV(state) (((state) << 1) | (__builtin_parityll((state) & ((0xce0044c101cd >> 1) | (1ull << 47)))))
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t uid;
|
||||
@ -32,11 +38,27 @@ typedef struct {
|
||||
uint8_t sectors[12][4];
|
||||
} hitag2_t;
|
||||
|
||||
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV);
|
||||
uint64_t ht2_hitag2_round(uint64_t *state);
|
||||
uint32_t ht2_hitag2_byte(uint64_t *x);
|
||||
void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv);
|
||||
int ht2_hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is);
|
||||
int ht2_hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ;
|
||||
typedef struct {
|
||||
uint64_t shiftreg; // naive shift register, required for nonlinear fn input
|
||||
uint64_t lfsr; // fast lfsr, used to make software faster
|
||||
} hitag_state_t;
|
||||
|
||||
void ht2_hitag2_init_ex(hitag_state_t *hstate, uint64_t sharedkey, uint32_t serialnum, const uint32_t iv);
|
||||
void ht2_rollback(hitag_state_t *hstate, uint32_t steps);
|
||||
uint64_t ht2_recoverkey(hitag_state_t *hstate, uint32_t uid, uint32_t nRenc);
|
||||
uint32_t ht2_hitag2_nstep(hitag_state_t *hstate, uint32_t steps);
|
||||
uint32_t ht2_hitag_acid(hitag_state_t *hstate, uint32_t steps);
|
||||
|
||||
int ht2_try_state(uint64_t s, uint32_t uid, uint32_t aR2, uint32_t nR1, uint32_t nR2, uint64_t *key);
|
||||
|
||||
uint32_t ht2_hitag2_word(uint64_t *state, uint32_t steps);
|
||||
uint64_t ht2_hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t iv);
|
||||
uint64_t ht2_hitag2_bit(uint64_t *state);
|
||||
uint32_t ht2_hitag2_byte(uint64_t *state);
|
||||
void ht2_hitag2_cipher_reset(hitag2_t *tag, const uint8_t *iv);
|
||||
int ht2_hitag2_cipher_authenticate(uint64_t *state, const uint8_t *authenticator_is);
|
||||
void ht2_hitag2_cipher_transcrypt(uint64_t *state, uint8_t *data, uint16_t bytes, uint16_t bits) ;
|
||||
|
||||
int ht2_fnf(uint64_t state);
|
||||
int ht2_fnR(uint64_t state);
|
||||
#endif
|
||||
|
@ -42,10 +42,8 @@ static const uint8_t g_odd_byte_parity[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
//extern const uint8_t OddByteParity[256];
|
||||
|
||||
#define ODD_PARITY8(x) { g_odd_byte_parity[x] }
|
||||
#define EVEN_PARITY8(x) { !g_odd_byte_parity[x] }
|
||||
#define ODD_PARITY8(x) g_odd_byte_parity[x]
|
||||
#define EVEN_PARITY8(x) !g_odd_byte_parity[x]
|
||||
|
||||
static inline uint8_t oddparity8(const uint8_t x) {
|
||||
return g_odd_byte_parity[x];
|
||||
@ -60,7 +58,7 @@ static inline uint8_t evenparity16(uint16_t x) {
|
||||
x ^= x >> 8;
|
||||
return EVEN_PARITY8(x) ;
|
||||
#else
|
||||
return (__builtin_parity(x) & 0xFF);
|
||||
return __builtin_parity(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -77,9 +75,9 @@ static inline uint8_t evenparity32(uint32_t x) {
|
||||
#if !defined __GNUC__
|
||||
x ^= x >> 16;
|
||||
x ^= x >> 8;
|
||||
return EVEN_PARITY8(x);
|
||||
return EVEN_PARITY8(x) ;
|
||||
#else
|
||||
return (__builtin_parity(x) & 0xFF);
|
||||
return __builtin_parity(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,17 @@ extern bool g_tearoff_enabled;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// endian change for 48bit
|
||||
#ifndef BSWAP_48
|
||||
#define BSWAP_48(x) \
|
||||
(((uint64_t)(x) << 40) & 0x0000ff0000000000ULL) | \
|
||||
(((uint64_t)(x) << 24) & 0x000000ff00000000ULL) | \
|
||||
(((uint64_t)(x) << 8) & 0x00000000ff000000ULL) | \
|
||||
(((uint64_t)(x) >> 8) & 0x000000000ff0000ULL) | \
|
||||
(((uint64_t)(x) >> 24) & 0x00000000000ff00ULL) | \
|
||||
(((uint64_t)(x) >> 40) & 0x0000000000000ffULL)
|
||||
#endif
|
||||
|
||||
// endian change for 32bit
|
||||
#ifdef __GNUC__
|
||||
#ifndef BSWAP_32
|
||||
|
@ -39,37 +39,28 @@ typedef enum {
|
||||
RHT2F_UID_ONLY = 26,
|
||||
WHT2F_PASSWORD = 27,
|
||||
HT2_LAST_CMD = WHT2F_PASSWORD,
|
||||
} hitag_function;
|
||||
|
||||
typedef struct {
|
||||
uint8_t password[4];
|
||||
} PACKED rht2d_password;
|
||||
} PACKED hitag_function;
|
||||
|
||||
typedef struct {
|
||||
hitag_function cmd;
|
||||
int16_t page;
|
||||
uint8_t data[4];
|
||||
uint8_t NrAr[8];
|
||||
uint8_t data[4];
|
||||
} PACKED rht2d_authenticate;
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[6];
|
||||
uint8_t data[4];
|
||||
} PACKED rht2d_crypto;
|
||||
uint8_t pwd[4];
|
||||
|
||||
typedef struct {
|
||||
// Hitag 1 section.
|
||||
// will reuse pwd or key field.
|
||||
uint8_t key_no;
|
||||
uint8_t logdata_0[4];
|
||||
uint8_t logdata_1[4];
|
||||
uint8_t nonce[4];
|
||||
uint8_t key[4];
|
||||
} PACKED rht1d_authenticate;
|
||||
|
||||
typedef union {
|
||||
rht2d_password pwd;
|
||||
rht1d_authenticate ht1auth;
|
||||
rht2d_authenticate auth;
|
||||
rht2d_crypto crypto;
|
||||
} hitag_data;
|
||||
} PACKED lf_hitag_data_t;
|
||||
|
||||
typedef struct {
|
||||
int status;
|
||||
uint8_t data[48];
|
||||
} PACKED lf_hitag_crack_response_t;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Hitag S
|
||||
|
@ -67,9 +67,9 @@ def hitag2_init(key, uid, nonce):
|
||||
#print '%012x' % state
|
||||
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
|
||||
for i in range(0, 32):
|
||||
nonce_bit = (f20(state) ^ ((nonce >> (31-i)) & 1))
|
||||
nonce_bit = (f20(state) ^ ((nonce >> (31 - i)) & 1))
|
||||
#print nonce_bit
|
||||
state = (state >> 1) | (((nonce_bit ^ (key >> (31-i))) & 1) << 47)
|
||||
state = (state >> 1) | (((nonce_bit ^ (key >> (31 - i))) & 1) << 47)
|
||||
#print '%012x' % state
|
||||
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
|
||||
return state
|
||||
@ -81,6 +81,7 @@ def lfsr_feedback(state):
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (state >> 42) ^ (state >> 43) ^ (state >> 46)
|
||||
^ (state >> 47)) & 1)
|
||||
|
||||
def lfsr(state):
|
||||
return (state >> 1) + (lfsr_feedback(state) << 47)
|
||||
|
||||
@ -93,15 +94,17 @@ def lfsr_feedback_inv(state):
|
||||
^ (state >> 46)) & 1)
|
||||
|
||||
def lfsr_inv(state):
|
||||
return ((state << 1) + (lfsr_feedback_inv(state))) & ((1<<48)-1)
|
||||
return ((state << 1) + (lfsr_feedback_inv(state))) & ((1 << 48) - 1)
|
||||
|
||||
def hitag2(state, length=48):
|
||||
c = 0
|
||||
for i in range(0, length):
|
||||
c = (c << 1) | f20(state)
|
||||
#print '%012x' % state
|
||||
#print '%012x' % (int("{0:048b}".format(state)[::-1],2))
|
||||
#print ('%012x' % state)
|
||||
state = lfsr(state)
|
||||
#print ('%012x' % (int("{0:048b}".format(state)[::-1],2)))
|
||||
#print('%08X %08X' % (c, state))
|
||||
#print('final: %08X %08X' % (c, state))
|
||||
return c
|
||||
|
||||
if __name__ == "__main__":
|
||||
@ -111,8 +114,15 @@ if __name__ == "__main__":
|
||||
uid = int(sys.argv[2], 16)
|
||||
n = int(sys.argv[3])
|
||||
for i in range(n):
|
||||
nonce = random.randrange(2**32)
|
||||
state = hitag2_init(key, uid, nonce)
|
||||
print('%08X %08X' % (nonce, hitag2(state, 32)^0xffffffff))
|
||||
nonceA = random.randrange(2**32)
|
||||
stateA = hitag2_init(key, uid, nonceA)
|
||||
csA = hitag2(stateA, 32) ^ 0xffffffff
|
||||
# print('%08X %08X' % (nonceA, csA))
|
||||
|
||||
nonceB = random.randrange(2**32)
|
||||
stateB = hitag2_init(key, uid, nonceB)
|
||||
csB = hitag2(stateB, 32) ^ 0xffffffff
|
||||
print('./ht2crack5opencl %08X %08X %08X %08X %08X' % (uid, nonceA, csA, nonceB, csB))
|
||||
print('lf hitag lookup --uid %08X --nr %08X --ar %08X --key %012X' % (uid, nonceA, csA, key))
|
||||
else:
|
||||
print("Usage: python %s <key> <uid> <nr of nRaR to generate>" % sys.argv[0])
|
||||
|
@ -414,6 +414,7 @@ while true; do
|
||||
if ! CheckExecute "nfc decode test - signature" "$CLIENTBIN -c 'nfc decode -d 03FF010194113870696C65742E65653A656B616172743A3266195F26063132303832325904202020205F28033233335F2701316E1B5A13333038363439303039303030323636343030355304EBF2CE704103000000AC536967010200803A2448FCA7D354A654A81BD021150D1A152D1DF4D7A55D2B771F12F094EAB6E5E10F2617A2F8DAD4FD38AFF8EA39B71C19BD42618CDA86EE7E144636C8E0E7CFC4096E19C3680E09C78A0CDBC05DA2D698E551D5D709717655E56FE3676880B897D2C70DF5F06ECE07C71435255144F8EE41AF110E7B180DA0E6C22FB8FDEF61800025687474703A2F2F70696C65742E65652F6372742F33303836343930302D303030312E637274FE'" "30864900-0001.crt"; then break; fi
|
||||
|
||||
echo -e "\n${C_BLUE}Testing LF:${C_NC}"
|
||||
if ! CheckExecute "lf hitag2 test" "$CLIENTBIN -c 'lf hitag selftest'" "Tests \( ok"; then break; fi
|
||||
if ! CheckExecute "lf cotag demod test" "$CLIENTBIN -c 'data load -f traces/lf_cotag_220_8331.pm3; data norm; data cthreshold -u 50 -d -20; data envelope; data raw --ar -c 272; lf cotag demod'" \
|
||||
"COTAG Found: FC 220, CN: 8331 Raw: FFB841170363FFFE00001E7F00000000"; then break; fi
|
||||
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi
|
||||
|
Loading…
x
Reference in New Issue
Block a user