mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 02:27:26 -07:00
Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3
This commit is contained in:
commit
693b2bc3d0
62 changed files with 1138 additions and 989 deletions
|
@ -3,6 +3,9 @@ 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]
|
||||
- Change `script run hf_bruteforce -s start_id -e end_id -t timeout -x mifare_card_type` - The hf_bruteforce card script now requires Mifare type (mfc or mfu) (@dunderhay)
|
||||
- Updated `hf_bruteforce.lua` script - added support for brute forcing Mifare Ultralight EV1 cards (@dunderhay)
|
||||
- Added `hf mf personlize` - personalize the UID of a Mifare Classic EV1 card (@pwpiwi)
|
||||
- Change - hint texts added to all lf clone commands (@iceman1001)
|
||||
- Change `lf keri demod` - adjusted the internal id. (@mwalker33)
|
||||
- Added seamless integration with cryptohelper (@iceman1001)
|
||||
|
@ -35,7 +38,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added `commands.md` - document with all proxmark client commands. Generated with XX_internal_command_dump_markdown_XX. (@iceman1001)
|
||||
- Change `lf pac clone` - new option `c <card id>` to allow cloning PAC/Stanley tag from card ID (@danshuk)
|
||||
- Change `lf pac read` - decoded PAC/Stanley card ID (@danshuk)
|
||||
- Change mifare classic keytable output refactored and uses colors (@iceman1001)
|
||||
- Change mifare classic keytable output refactored and uses colors (@iceman1001)
|
||||
- Fix `hf mf nested` - now writes the correct blockno (@iceman1001)
|
||||
- Change `lf t55xx dump` - now supports saving to JSON (@iceman1001)
|
||||
- Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi)
|
||||
|
@ -605,8 +608,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Updated the Reveng 1.31 sourcecode to 1.40 from Reveng project homepage (@iceman1001)
|
||||
- Added possibility to write direct to a Legic Prime Tag (MIM256/1024) without using values from the `BigBuffer` -> `hf legic writeRaw <addr> <value>` (@icsom)
|
||||
- Added possibility to decrease DCF values at address 0x05 & 0x06 on a Legic Prime Tag
|
||||
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
|
||||
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
|
||||
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
|
||||
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
|
||||
write the DCF-Values (both at once) with `hf legic write 0x05 0x02` (@icsom)
|
||||
- Added script `legic.lua` for display and edit Data of Legic-Prime Tags (@icsom)
|
||||
- Added the experimental HITAG_S support (@spenneb)
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
|
||||
| FAQ's & Updates | Installation | Use of the Proxmark |
|
||||
| ------------------- |:-------------------:| -------------------:|
|
||||
|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|
||||
|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|
||||
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
|[Proxmark3 GUI](#proxmark3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
|[What has changed?](#what-has-changed) | **[Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md)** | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|
||||
|[Development](#development) | **[Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md)** | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|
||||
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
|[Proxmark3 GUI](#proxmark3-gui)|**[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)**|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) |[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|
|
||||
|[Notes on UART](/doc/uart_notes.md)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)|
|
||||
|[Notes on frame format](/doc/new_frame_format.md)||[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* To delete the trace data from flash:
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
|
||||
|
@ -97,7 +97,7 @@ void RunMod() {
|
|||
if (trace_len > 0) {
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
|
||||
uint8_t* trace_buffer = BigBuf_get_addr();
|
||||
uint8_t *trace_buffer = BigBuf_get_addr();
|
||||
if (!exists_in_spiffs(HF_14ASNIFF_LOGFILE)) {
|
||||
rdv40_spiffs_write(
|
||||
HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
@ -117,7 +117,7 @@ void RunMod() {
|
|||
|
||||
SpinErr(LED_A, 200, 5);
|
||||
SpinDelay(100);
|
||||
|
||||
|
||||
LEDsoff();
|
||||
SpinDelay(300);
|
||||
DownloadTraceInstructions();
|
||||
|
|
|
@ -63,7 +63,7 @@ void DownloadLogInstructions() {
|
|||
|
||||
bool log_exists;
|
||||
|
||||
void append(uint8_t* entry, size_t entry_len) {
|
||||
void append(uint8_t *entry, size_t entry_len) {
|
||||
|
||||
LED_B_ON();
|
||||
if (log_exists == false) {
|
||||
|
@ -106,22 +106,22 @@ uint32_t IceEM410xdemod() {
|
|||
|
||||
if (size == 128) {
|
||||
sprintf((char *)entry, "EM XL TAG ID: %06lx%08lx%08lx - (%05ld_%03ld_%08ld)\n",
|
||||
hi,
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
hi,
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
} else {
|
||||
sprintf((char *)entry, "EM TAG ID: %02lx%08lx - (%05ld_%03ld_%08ld)\n",
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
}
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -173,7 +173,7 @@ uint32_t IceAWIDdemod() {
|
|||
}
|
||||
}
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -210,14 +210,14 @@ uint32_t IceIOdemod() {
|
|||
memset(entry, 0, sizeof(entry));
|
||||
|
||||
sprintf((char *)entry, "IO Prox XSF(%02d)%02x:%05d (%08lx%08lx)\n"
|
||||
, version
|
||||
, facilitycode
|
||||
, number
|
||||
, hi
|
||||
, lo
|
||||
);
|
||||
, version
|
||||
, facilitycode
|
||||
, number
|
||||
, hi
|
||||
, lo
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -250,13 +250,13 @@ uint32_t IceHIDDemod() {
|
|||
if (hi2 != 0) { //extra large HID tags 88/192 bits
|
||||
|
||||
sprintf((char *)entry, "HID large: %lx%08lx%08lx (%ld)\n",
|
||||
hi2,
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF
|
||||
);
|
||||
hi2,
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
|
||||
} else { //standard HID tags 44/96 bits
|
||||
uint8_t bitlen = 0;
|
||||
|
@ -297,15 +297,15 @@ uint32_t IceHIDDemod() {
|
|||
}
|
||||
|
||||
sprintf((char *)entry, "HID: %lx%08lx (%ld) Format: %d bit FC: %ld Card: %ld\n",
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF,
|
||||
bitlen,
|
||||
fac,
|
||||
cardnum
|
||||
);
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF,
|
||||
bitlen,
|
||||
fac,
|
||||
cardnum
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
}
|
||||
|
||||
Dbprintf("%s", entry);
|
||||
|
@ -349,7 +349,7 @@ void RunMod() {
|
|||
|
||||
uint32_t res;
|
||||
|
||||
// since we steal 12800 from bigbuffer, no need to sample it.
|
||||
// since we steal 12800 from bigbuffer, no need to sample it.
|
||||
DoAcquisition_config(false, 28000);
|
||||
res = IceHIDDemod();
|
||||
if (res == PM3_SUCCESS) {
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Standalone/standalone.h"
|
||||
#include "util.h"
|
||||
#include "ticks.h"
|
||||
#include "commonutil.h"
|
||||
|
||||
#ifdef WITH_LCD
|
||||
#include "LCD.h"
|
||||
|
@ -548,7 +549,7 @@ void ListenReaderField(uint8_t limit) {
|
|||
// iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader.
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40);
|
||||
#else
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
|
||||
#endif
|
||||
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
|
||||
hf_baseline = hf_av;
|
||||
|
@ -721,10 +722,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_GET_CONFIG: {
|
||||
case CMD_LF_SAMPLING_PRINT_CONFIG: {
|
||||
printConfig();
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_GET_CONFIG: {
|
||||
sample_config *config = getSamplingConfig();
|
||||
reply_ng(CMD_LF_SAMPLING_GET_CONFIG, PM3_SUCCESS, (uint8_t *)config, sizeof(sample_config));
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_SET_CONFIG: {
|
||||
sample_config c;
|
||||
memcpy(&c, packet->data.asBytes, sizeof(sample_config));
|
||||
|
@ -1242,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// SniffMifare(packet->oldarg[0]);
|
||||
// break;
|
||||
// }
|
||||
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
||||
struct p {
|
||||
uint8_t keytype;
|
||||
uint8_t pers_option;
|
||||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
uint64_t authkey = bytes_to_num(payload->key, 6);
|
||||
MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_SETMOD: {
|
||||
MifareSetMod(packet->data.asBytes);
|
||||
break;
|
||||
|
|
|
@ -408,7 +408,7 @@ void fix_ac_decoding(uint8_t *input, size_t len) {
|
|||
*/
|
||||
|
||||
|
||||
// looks at number of received bits.
|
||||
// looks at number of received bits.
|
||||
// 0 = collision?
|
||||
// 32 = good response
|
||||
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
|
||||
|
@ -582,15 +582,15 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t
|
|||
Dbhexdump(4, logdata_1, false);
|
||||
bSuccessful = true;
|
||||
return false;
|
||||
/*
|
||||
// read next page of card until done
|
||||
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
|
||||
tx[1] = blocknr << 4;
|
||||
crc = hitag_crc(tx, 12);
|
||||
tx[1] |= crc >> 4;
|
||||
tx[2] = crc << 4;
|
||||
*txlen = 20;
|
||||
*/
|
||||
/*
|
||||
// read next page of card until done
|
||||
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
|
||||
tx[1] = blocknr << 4;
|
||||
crc = hitag_crc(tx, 12);
|
||||
tx[1] |= crc >> 4;
|
||||
tx[2] = crc << 4;
|
||||
*txlen = 20;
|
||||
*/
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1091,7 +1091,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
uint32_t block = 0;
|
||||
for (size_t i = 0; i < 12; i++) {
|
||||
|
||||
// num2bytes?
|
||||
// num2bytes?
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
block <<= 8;
|
||||
block |= tag.sectors[i][j];
|
||||
|
@ -1105,30 +1105,30 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
size_t nrzs = 0, periods = 0;
|
||||
|
||||
// uint32_t command_start = 0, command_duration = 0;
|
||||
// int16_t checked = 0;
|
||||
// int16_t checked = 0;
|
||||
|
||||
// SIMULATE
|
||||
|
||||
while (!BUTTON_PRESS()) {
|
||||
|
||||
LED_D_ON();
|
||||
|
||||
|
||||
// lf_reset_counter();
|
||||
LED_A_OFF();
|
||||
WDT_HIT();
|
||||
|
||||
/*
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 100) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
*/
|
||||
/*
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 100) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
*/
|
||||
|
||||
rxlen = 0;
|
||||
|
||||
|
@ -1220,8 +1220,8 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
if (nrzs < 5) {
|
||||
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
|
||||
continue;
|
||||
} else {
|
||||
for (size_t i = 0; i < 5; i++){
|
||||
} else {
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
if (nrz_samples[i] != 1) {
|
||||
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one", i);
|
||||
}
|
||||
|
@ -1229,7 +1229,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
}
|
||||
|
||||
// Pack the response into a byte array
|
||||
for (size_t i = 5; i < 37; i++){
|
||||
for (size_t i = 5; i < 37; i++) {
|
||||
uint8_t bit = nrz_samples[i];
|
||||
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
|
@ -1401,7 +1401,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
// hitagS settings
|
||||
t_wait_1 = 204;
|
||||
t_wait_2 = 128;
|
||||
/*tag_size = 256;*/
|
||||
flipped_bit = 0;
|
||||
tag_size = 8;
|
||||
DBG DbpString("Configured for hitagS reader");
|
||||
|
@ -1657,7 +1656,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
uint32_t command_start = 0;
|
||||
uint32_t command_duration = 0;
|
||||
uint32_t response_start = 0;
|
||||
uint32_t response_duration = 0;
|
||||
uint32_t response_duration = 0;
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||
|
@ -1731,14 +1730,14 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
tag_size = 8;
|
||||
DbpString("Configured for hitagS writer");
|
||||
} else if (htf < 20) {
|
||||
// hitag1 settings
|
||||
// hitag1 settings
|
||||
t_wait_1 = 204;
|
||||
t_wait_2 = 128;
|
||||
tag_size = 256;
|
||||
flipped_bit = 0;
|
||||
DbpString("Configured for hitag1 writer");
|
||||
} else if (htf < 30) {
|
||||
// hitag2 settings
|
||||
// hitag2 settings
|
||||
t_wait_1 = HITAG_T_WAIT_1_MIN;
|
||||
t_wait_2 = HITAG_T_WAIT_2_MIN;
|
||||
tag_size = 48;
|
||||
|
@ -1783,7 +1782,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
}
|
||||
}
|
||||
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
lf_wait_periods(t_wait_2);
|
||||
command_start += t_wait_2;
|
||||
|
||||
|
|
|
@ -38,70 +38,60 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
|
|||
uint8_t temp[20];
|
||||
int i;
|
||||
uint8_t *spaceptr = NULL;
|
||||
|
||||
|
||||
// get uid as hexstring
|
||||
if(!hitag2_get_uid(uidhex))
|
||||
{
|
||||
if (!hitag2_get_uid(uidhex)) {
|
||||
UserMessage("Cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert uid hexstring to binarray
|
||||
hextobinarray(uid, uidhex);
|
||||
|
||||
|
||||
// convert nR and aR hexstrings to binarray
|
||||
spaceptr = strchr(nrarhex, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("Please supply a valid nR aR pair\r\n");
|
||||
return false;
|
||||
}
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32) {
|
||||
UserMessage("nR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
|
||||
UserMessage("aR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a valid encrypted command
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar))
|
||||
{
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
|
||||
UserMessage("Cannot find a valid encrypted command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// find the 'read page 0' command and recover key stream
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
|
||||
UserMessage("Cannot find encrypted 'read page0' command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// empty the response string
|
||||
response[0] = 0x00;
|
||||
|
||||
|
||||
// read all pages using key stream
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if (hitag2crack_read_page(pagehex, i, nrar, keybits))
|
||||
{
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (hitag2crack_read_page(pagehex, i, nrar, keybits)) {
|
||||
sprintf(temp, "%1d: %s\r\n", i, pagehex);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
sprintf(temp, "%1d:\r\n", i);
|
||||
}
|
||||
// add page string to response
|
||||
strcat(response, temp);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -113,16 +103,16 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
|
|||
bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]) {
|
||||
uint8_t guess[10];
|
||||
uint8_t responsestr[9];
|
||||
|
||||
|
||||
// UserMessage("Finding valid encrypted command:");
|
||||
// we're going to hold bits 5, 7, 8 and 9 and brute force the rest
|
||||
// e.g. x x x x x 0 x 0 0 0
|
||||
for (uint8_t a=0; a<2; a++) {
|
||||
for (uint8_t b=0; b<2; b++) {
|
||||
for (uint8_t c=0; c<2; c++) {
|
||||
for (uint8_t d=0; d<2; d++) {
|
||||
for (uint8_t e=0; e<2; e++) {
|
||||
for (uint8_t g=0; g<2; g++) {
|
||||
for (uint8_t a = 0; a < 2; a++) {
|
||||
for (uint8_t b = 0; b < 2; b++) {
|
||||
for (uint8_t c = 0; c < 2; c++) {
|
||||
for (uint8_t d = 0; d < 2; d++) {
|
||||
for (uint8_t e = 0; e < 2; e++) {
|
||||
for (uint8_t g = 0; g < 2; g++) {
|
||||
// build binarray
|
||||
guess[0] = a;
|
||||
guess[1] = b;
|
||||
|
@ -175,65 +165,50 @@ bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8
|
|||
|
||||
UserMessage("Finding 'read page 0' command:");
|
||||
// we're going to brute the missing 4 bits of the valid encrypted command
|
||||
for (a=0; a<2; a++)
|
||||
{
|
||||
for (b=0; b<2; b++)
|
||||
{
|
||||
for (c=0; c<2; c++)
|
||||
{
|
||||
for (d=0; d<2; d++)
|
||||
{
|
||||
for (a = 0; a < 2; a++) {
|
||||
for (b = 0; b < 2; b++) {
|
||||
for (c = 0; c < 2; c++) {
|
||||
for (d = 0; d < 2; d++) {
|
||||
// create our guess by bit flipping the pattern of bits
|
||||
// representing the inverted bit and the 3 page bits
|
||||
// in both the non-inverted and inverted parts of the
|
||||
// encrypted command.
|
||||
memcpy(guess, e_firstcmd, 10);
|
||||
if (a)
|
||||
{
|
||||
if (a) {
|
||||
guess[5] = !guess[5];
|
||||
guess[0] = !guess[0];
|
||||
}
|
||||
if (b)
|
||||
{
|
||||
if (b) {
|
||||
guess[7] = !guess[7];
|
||||
guess[2] = !guess[2];
|
||||
}
|
||||
if (c)
|
||||
{
|
||||
if (c) {
|
||||
guess[8] = !guess[8];
|
||||
guess[3] = !guess[3];
|
||||
}
|
||||
if (d)
|
||||
{
|
||||
if (d) {
|
||||
guess[9] = !guess[9];
|
||||
guess[4] = !guess[4];
|
||||
}
|
||||
|
||||
|
||||
// try the guess
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) {
|
||||
// check if it was valid
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
|
||||
// convert response to binarray
|
||||
hextobinarray(e_uid, responsestr);
|
||||
// test if the guess was 'read page 0' command
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid))
|
||||
{
|
||||
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RFIDLER_DEBUG
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
#endif
|
||||
}
|
||||
|
@ -262,56 +237,51 @@ bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, u
|
|||
uint8_t e_ext_cmd[40];
|
||||
uint8_t responsestr[9];
|
||||
int i;
|
||||
|
||||
|
||||
// copy encrypted cmd to cipherbits
|
||||
memcpy(cipherbits, e_cmd, 10);
|
||||
|
||||
|
||||
// copy encrypted uid to cipherbits
|
||||
memcpy(cipherbits + 10, e_uid, 32);
|
||||
|
||||
|
||||
// copy cmd to plainbits
|
||||
binstringtobinarray(plainbits, READP0CMD);
|
||||
|
||||
|
||||
// copy uid to plainbits
|
||||
memcpy(plainbits + 10, uid, 32);
|
||||
|
||||
// xor the plainbits with the cipherbits to get keybits
|
||||
hitag2crack_xor(keybits, plainbits, cipherbits, 42);
|
||||
|
||||
|
||||
// create extended cmd -> 4 * READP0CMD = 40 bits
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
for (i = 0; i < 4; i++) {
|
||||
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
|
||||
}
|
||||
|
||||
|
||||
// xor extended cmd with keybits
|
||||
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
|
||||
|
||||
|
||||
// send extended encrypted cmd
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40)) {
|
||||
// test if it was valid
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// hitag2crack_xor XORs the source with the pad to produce the target.
|
||||
// source, target and pad are binarrays of length len.
|
||||
void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int len) {
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
target[i] = source[i] ^ pad[i];
|
||||
}
|
||||
}
|
||||
|
@ -329,40 +299,34 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
uint8_t e_response[32];
|
||||
uint8_t response[32];
|
||||
int i;
|
||||
|
||||
if ((pagenum < 0) || (pagenum > 7))
|
||||
{
|
||||
|
||||
if ((pagenum < 0) || (pagenum > 7)) {
|
||||
UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// create cmd
|
||||
binstringtobinarray(cmd, READP0CMD);
|
||||
if (pagenum & 0x1)
|
||||
{
|
||||
if (pagenum & 0x1) {
|
||||
cmd[9] = !cmd[9];
|
||||
cmd[4] = !cmd[4];
|
||||
}
|
||||
if (pagenum & 0x2)
|
||||
{
|
||||
if (pagenum & 0x2) {
|
||||
cmd[8] = !cmd[8];
|
||||
cmd[3] = !cmd[3];
|
||||
}
|
||||
if (pagenum & 0x4)
|
||||
{
|
||||
if (pagenum & 0x4) {
|
||||
cmd[7] = !cmd[7];
|
||||
cmd[2] = !cmd[2];
|
||||
}
|
||||
|
||||
|
||||
// encrypt command
|
||||
hitag2crack_xor(e_cmd, cmd, keybits, 10);
|
||||
|
||||
|
||||
// send encrypted command
|
||||
if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10)) {
|
||||
// check if it is valid
|
||||
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) {
|
||||
// convert to binarray
|
||||
hextobinarray(e_response, e_responsestr);
|
||||
// decrypt response
|
||||
|
@ -370,17 +334,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
// convert to hexstring
|
||||
binarraytohex(responsestr, response, 32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -397,8 +357,7 @@ bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, i
|
|||
int ret = 0;
|
||||
|
||||
// get the UID
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -407,22 +366,19 @@ bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, i
|
|||
CryptoActive = false;
|
||||
|
||||
// get the UID again
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send encrypted command
|
||||
if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false)) {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n");
|
||||
#endif
|
||||
|
@ -442,34 +398,29 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
|
|||
int ret = 0;
|
||||
|
||||
// START_AUTH kills active crypto session
|
||||
CryptoActive= false;
|
||||
|
||||
if(!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX))
|
||||
{
|
||||
CryptoActive = false;
|
||||
|
||||
if (!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) {
|
||||
UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// skip 1/2 bit to synchronise manchester
|
||||
HW_Skip_Bits = 1;
|
||||
ret = read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY);
|
||||
|
||||
// check if response was a valid length (5 sync bits + 32 bits response)
|
||||
if (ret == 37)
|
||||
{
|
||||
if (ret == 37) {
|
||||
// check sync bits
|
||||
if (memcmp(tmp, Hitag2Sync, 5) != 0)
|
||||
{
|
||||
if (memcmp(tmp, Hitag2Sync, 5) != 0) {
|
||||
UserMessage("hitag2crack_tx_rx: no sync\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// convert response to hexstring
|
||||
binarraytohex(responsestr, tmp + 5, 32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_tx_rx: wrong rx len\r\n");
|
||||
#endif
|
||||
|
@ -485,58 +436,53 @@ bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) {
|
|||
uint32_t initvector;
|
||||
uint8_t *spaceptr;
|
||||
uint8_t *dataptr;
|
||||
|
||||
|
||||
// extract vals from input
|
||||
dataptr = input;
|
||||
spaceptr = strchr(dataptr, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (strlen(dataptr) != 12)
|
||||
{
|
||||
|
||||
if (strlen(dataptr) != 12) {
|
||||
UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sharedkey = rev64(hexreversetoulonglong(dataptr));
|
||||
|
||||
dataptr = spaceptr+1;
|
||||
|
||||
dataptr = spaceptr + 1;
|
||||
spaceptr = strchr(dataptr, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("/r/nno UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
*spaceptr = 0x00;
|
||||
if (strlen(dataptr) != 8)
|
||||
{
|
||||
if (strlen(dataptr) != 8) {
|
||||
UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
serialnum = rev32(hexreversetoulong(dataptr));
|
||||
|
||||
dataptr = spaceptr+1;
|
||||
|
||||
if (strlen(dataptr) != 8)
|
||||
{
|
||||
|
||||
dataptr = spaceptr + 1;
|
||||
|
||||
if (strlen(dataptr) != 8) {
|
||||
UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
initvector = rev32(hexreversetoulong(dataptr));
|
||||
|
||||
|
||||
// start up crypto engine
|
||||
hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector);
|
||||
|
||||
|
||||
strcpy(response, "Success\r\n");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -545,21 +491,20 @@ bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) {
|
|||
uint8_t binhex[9];
|
||||
uint8_t binstr[33];
|
||||
uint32_t binulong;
|
||||
|
||||
if (strlen(hex) != 8)
|
||||
{
|
||||
|
||||
if (strlen(hex) != 8) {
|
||||
UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
binulong = hextoulong(hex);
|
||||
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32);
|
||||
binarraytobinstring(binstr, bin, 32);
|
||||
binarraytohex(binhex, bin, 32);
|
||||
// UserMessage("ar = %s\r\n", binstr);
|
||||
// UserMessage("arhex = %s\r\n", binhex);
|
||||
|
||||
|
||||
strcpy(response, binhex);
|
||||
return true;
|
||||
}
|
||||
|
@ -570,17 +515,16 @@ bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) {
|
|||
uint8_t binstr[33];
|
||||
uint32_t binulong;
|
||||
int len;
|
||||
|
||||
|
||||
len = strlen(e_binstr);
|
||||
if (len > 32)
|
||||
{
|
||||
if (len > 32) {
|
||||
UserMessage("\r\nbinary string must be <= 32 bits\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
binstringtobinarray(e_bin, e_binstr);
|
||||
binulong = binarraytoulong(e_bin, len);
|
||||
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, len), len);
|
||||
binarraytobinstring(binstr, bin, len);
|
||||
strcpy(response, binstr);
|
||||
|
@ -595,7 +539,7 @@ bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex) {
|
|||
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr) {
|
||||
return hitag2crack_decrypt_bin(response, e_binstr);
|
||||
}
|
||||
|
||||
|
||||
// hitag2_keystream uses the first crack algorithm described in the paper,
|
||||
// Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits
|
||||
// of keystream.
|
||||
|
@ -618,102 +562,90 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
|
|||
int i;
|
||||
uint8_t *spaceptr = NULL;
|
||||
|
||||
/*
|
||||
keybits = malloc(2080);
|
||||
if (!keybits) {
|
||||
UserMessage("cannot malloc keybits\r\n");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
keybits = malloc(2080);
|
||||
if (!keybits) {
|
||||
UserMessage("cannot malloc keybits\r\n");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// get uid as hexstring
|
||||
if(!hitag2_get_uid(uidhex))
|
||||
{
|
||||
if (!hitag2_get_uid(uidhex)) {
|
||||
UserMessage("Cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert uid hexstring to binarray
|
||||
hextobinarray(uid, uidhex);
|
||||
|
||||
|
||||
// convert nR and aR hexstrings to binarray
|
||||
spaceptr = strchr(nrarhex, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("Please supply a valid nR aR pair\r\n");
|
||||
return false;
|
||||
}
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32) {
|
||||
UserMessage("nR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
|
||||
UserMessage("aR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a valid encrypted command
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar))
|
||||
{
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
|
||||
UserMessage("Cannot find a valid encrypted command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// find the 'read page 0' command and recover key stream
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
|
||||
UserMessage("Cannot find encrypted 'read page0' command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// using the 40 bits of keystream in keybits, sending commands with ever
|
||||
// increasing lengths to acquire 2048 bits of key stream.
|
||||
kslen = 40;
|
||||
|
||||
while (kslen < 2048)
|
||||
{
|
||||
|
||||
while (kslen < 2048) {
|
||||
ksoffset = 0;
|
||||
if (!hitag2crack_send_auth(nrar))
|
||||
{
|
||||
if (!hitag2crack_send_auth(nrar)) {
|
||||
UserMessage("hitag2crack_send_auth failed\r\n");
|
||||
return false;
|
||||
}
|
||||
// while we have at least 52 bits of keystream, consume it with
|
||||
// extended read page 0 commands. 52 = 10 (min command len) +
|
||||
// 32 (response) + 10 (min command len we'll send)
|
||||
while ((kslen - ksoffset) >= 52)
|
||||
{
|
||||
while ((kslen - ksoffset) >= 52) {
|
||||
// consume the keystream, updating ksoffset as we go
|
||||
if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar))
|
||||
{
|
||||
if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar)) {
|
||||
UserMessage("hitag2crack_consume_keystream failed\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// send an extended command to retrieve more keystream, updating kslen
|
||||
// as we go
|
||||
if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid)) {
|
||||
UserMessage("hitag2crack_extend_keystream failed\r\n");
|
||||
return false;
|
||||
}
|
||||
UserMessage("Recovered %d bits of keystream\r\n", kslen);
|
||||
|
||||
}
|
||||
|
||||
for (i=0; i<2048; i+=256)
|
||||
{
|
||||
|
||||
for (i = 0; i < 2048; i += 256) {
|
||||
binarraytohex(keybitshex, keybits + i, 256);
|
||||
UserMessage("%s\r\n", keybitshex);
|
||||
}
|
||||
|
||||
response[0] = 0x00;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -724,8 +656,7 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
|
|||
uint8_t e_page3str[9];
|
||||
|
||||
// get the UID
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -734,15 +665,13 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
|
|||
CryptoActive = false;
|
||||
|
||||
// get the UID again
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -767,46 +696,41 @@ bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, u
|
|||
// 42 = 32 bit response + 10 bit command reserved for next command. conlen
|
||||
// cannot be longer than 510 bits to fit into the small RWD buffer.
|
||||
conlen = kslen - *ksoffset - 42;
|
||||
if (conlen < 10)
|
||||
{
|
||||
if (conlen < 10) {
|
||||
UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// sanitise conlen
|
||||
if (conlen > 510)
|
||||
{
|
||||
if (conlen > 510) {
|
||||
conlen = 510;
|
||||
}
|
||||
|
||||
|
||||
// calculate how many repeated commands to send in this extended command.
|
||||
numcmds = conlen / 10;
|
||||
|
||||
|
||||
// build extended command
|
||||
for (i=0; i<numcmds; i++)
|
||||
{
|
||||
for (i = 0; i < numcmds; i++) {
|
||||
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
|
||||
}
|
||||
|
||||
// xor extended cmd with keybits
|
||||
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + *ksoffset, numcmds * 10);
|
||||
|
||||
|
||||
// send encrypted command
|
||||
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_consume_keystream:\r\n tx/rx cmd failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// test response
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) == 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) == 0) {
|
||||
UserMessage("hitag2crack_consume_keystream:\r\n got error response from card\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// dont bother decrypting the response - we already know the keybits
|
||||
|
||||
|
||||
// update ksoffset with command length and response
|
||||
*ksoffset += (numcmds * 10) + 32;
|
||||
}
|
||||
|
@ -825,36 +749,32 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
uint8_t responsestr[9];
|
||||
uint8_t e_response[32];
|
||||
int i;
|
||||
|
||||
|
||||
// calc number of command iterations to send
|
||||
cmdlen = *kslen - ksoffset;
|
||||
if (cmdlen < 10)
|
||||
{
|
||||
if (cmdlen < 10) {
|
||||
UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
numcmds = cmdlen / 10;
|
||||
|
||||
|
||||
// build extended command
|
||||
for (i=0; i<numcmds; i++)
|
||||
{
|
||||
for (i = 0; i < numcmds; i++) {
|
||||
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
|
||||
}
|
||||
|
||||
|
||||
// xor extended cmd with keybits
|
||||
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + ksoffset, numcmds * 10);
|
||||
|
||||
|
||||
// send extended encrypted cmd
|
||||
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_extend_keystream:\r\n tx/rx cmd failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// test response
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) == 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) == 0) {
|
||||
UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -867,7 +787,7 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
|
||||
// update kslen
|
||||
*kslen = ksoffset + (numcmds * 10) + 32;
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -875,49 +795,39 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive) {
|
||||
uint8_t tmp[9];
|
||||
int i;
|
||||
|
||||
|
||||
response[0] = '\0';
|
||||
// auth to tag
|
||||
if (hitag2_crypto_auth(tmp, key))
|
||||
{
|
||||
if (hitag2_crypto_auth(tmp, key)) {
|
||||
// read tag, one page at a time
|
||||
for (i= 0; i <= 7; ++i)
|
||||
{
|
||||
if(!read_tag(tmp, i, i))
|
||||
{
|
||||
for (i = 0; i <= 7; ++i) {
|
||||
if (!read_tag(tmp, i, i)) {
|
||||
// if read fails, it could be because of auth,
|
||||
// so try to reauth
|
||||
if (!hitag2_crypto_auth(tmp, key))
|
||||
{
|
||||
if (!hitag2_crypto_auth(tmp, key)) {
|
||||
// if we can't reauth, it's a real failure
|
||||
return false;
|
||||
}
|
||||
// temp failure (probably due to page protections)
|
||||
strcpy(tmp, "XXXXXXXX");
|
||||
strcpy(tmp, "XXXXXXXX");
|
||||
}
|
||||
// page contents are in tmp
|
||||
strcat(response, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
tmp[8]= '\0';
|
||||
for(i= 0; i <= 7 ; ++i)
|
||||
{
|
||||
UserMessageNum("%d: ", i);
|
||||
memcpy(tmp, response + (i * 8), 8);
|
||||
UserMessage("%s\r\n", tmp);
|
||||
}
|
||||
UserMessage("%s", "\r\n");
|
||||
if (interactive) {
|
||||
tmp[8] = '\0';
|
||||
for (i = 0; i <= 7 ; ++i) {
|
||||
UserMessageNum("%d: ", i);
|
||||
memcpy(tmp, response + (i * 8), 8);
|
||||
UserMessage("%s\r\n", tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
hitag2_nvm_store_tag(response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserMessage("%s", "\r\n");
|
||||
} else {
|
||||
hitag2_nvm_store_tag(response);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1952,11 +1952,11 @@ void check_challenges(bool file_given, uint8_t *data) {
|
|||
u1++;
|
||||
|
||||
} else if (STATE == 2 && rxlen >= 44) {
|
||||
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
|
||||
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
|
||||
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
|
||||
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
|
||||
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
|
||||
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
|
||||
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
|
||||
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
|
||||
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
|
||||
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
|
||||
STATE = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1817,15 +1817,15 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
|||
++check;
|
||||
|
||||
// test if the field exists
|
||||
#if defined RDV4
|
||||
#if defined RDV4
|
||||
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_RDV40)) {
|
||||
|
||||
|
||||
analogCnt++;
|
||||
|
||||
|
||||
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40];
|
||||
|
||||
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||
|
||||
|
||||
if (analogCnt >= 32) {
|
||||
|
||||
if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
|
||||
|
@ -1847,13 +1847,13 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
|||
}
|
||||
#else
|
||||
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) {
|
||||
|
||||
|
||||
analogCnt++;
|
||||
|
||||
|
||||
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF];
|
||||
|
||||
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||
|
||||
|
||||
if (analogCnt >= 32) {
|
||||
|
||||
if ((MAX_ADC_HF_VOLTAGE * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
|
||||
|
|
|
@ -81,7 +81,7 @@ void setSamplingConfig(sample_config *sc) {
|
|||
printConfig();
|
||||
}
|
||||
|
||||
sample_config *getSamplingConfig() {
|
||||
sample_config *getSamplingConfig(void) {
|
||||
return &config;
|
||||
}
|
||||
|
||||
|
@ -117,8 +117,8 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
|
|||
|
||||
if (use_malloc) {
|
||||
|
||||
if (sample_size == NULL || *sample_size == 0 ) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
if (sample_size == NULL || *sample_size == 0) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
data.buffer = BigBuf_get_addr();
|
||||
} else {
|
||||
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
||||
|
@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (sample_size == NULL || *sample_size == 0 ) {
|
||||
if (sample_size == NULL || *sample_size == 0) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
}
|
||||
data.buffer = BigBuf_get_addr();
|
||||
|
@ -221,7 +221,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
|
|||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||
// 50ms for the resonant antenna to settle.
|
||||
if (reader_field)
|
||||
SpinDelay(50);
|
||||
SpinDelay(50);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
|
|
|
@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) {
|
|||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
|
||||
//-----------------------------------------------------------------------------
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||
|
||||
uint16_t isOK = PM3_EUNDEF;
|
||||
uint8_t uid[10];
|
||||
uint32_t cuid;
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t block_number = 0;
|
||||
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
break;;
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
}
|
||||
isOK = PM3_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
crypto1_deinit(pcs);
|
||||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0);
|
||||
LED_B_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Work with emulator memory
|
||||
//
|
||||
|
@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) {
|
|||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
}
|
||||
|
||||
int respLen;
|
||||
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) {
|
|||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
|
||||
|
||||
LED_B_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
|
|
@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card?
|
|||
void MifareHasStaticNonce(); // Has the tag a static nonce?
|
||||
|
||||
void MifareSetMod(uint8_t *datain);
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||
|
||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
||||
void OnSuccessMagic();
|
||||
void OnErrorMagic(uint8_t reason);
|
||||
|
|
|
@ -537,13 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
|
||||
// find reader field
|
||||
if (cardSTATE == MFEMUL_NOFIELD) {
|
||||
|
||||
|
||||
#if defined RDV4
|
||||
vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
|
||||
#else
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
|
||||
#endif
|
||||
|
||||
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
cardSTATE_TO_IDLE();
|
||||
LED_A_ON();
|
||||
|
|
|
@ -130,7 +130,7 @@ CORESRCS = uart_posix.c \
|
|||
util_posix.c \
|
||||
scandir.c \
|
||||
crc16.c \
|
||||
comms.c
|
||||
comms.c
|
||||
|
||||
CMDSRCS = crapto1/crapto1.c \
|
||||
crapto1/crypto1.c \
|
||||
|
|
|
@ -315,7 +315,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
|
|||
}
|
||||
|
||||
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
||||
|
||||
|
||||
int ret_val = PM3_SUCCESS;
|
||||
|
||||
// We want to mount before multiple operation so the lazy writes/append will not
|
||||
|
@ -349,7 +349,7 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
|||
bytes_sent += bytes_in_packet;
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
|
||||
uint8_t retry = 3;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
|
@ -377,7 +377,7 @@ out:
|
|||
// We want to unmount after these to set things back to normal but more than this
|
||||
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
@ -400,8 +400,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
|||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32);
|
||||
if (strlen((char*)destfilename) == 0) {
|
||||
param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32);
|
||||
if (strlen((char *)destfilename) == 0) {
|
||||
PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
|
||||
errors = true;
|
||||
}
|
||||
|
@ -429,12 +429,12 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = flashmem_spiffs_load(destfilename, data, datalen);
|
||||
|
||||
|
||||
free(data);
|
||||
|
||||
if ( res == PM3_SUCCESS )
|
||||
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -861,7 +861,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
|
||||
|
||||
uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
|
||||
BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03);
|
||||
|
||||
for (uint16_t blocknum = 0; blocknum < applimit; ++blocknum) {
|
||||
|
@ -894,36 +894,36 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen);
|
||||
|
||||
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
|
||||
|
||||
|
||||
|
||||
// decode block 6
|
||||
if (memcmp(decrypted + (8*6), empty, 8) != 0 ) {
|
||||
if (memcmp(decrypted + (8 * 6), empty, 8) != 0) {
|
||||
if (use_sc) {
|
||||
DecodeBlock6(decrypted + (8*6));
|
||||
DecodeBlock6(decrypted + (8 * 6));
|
||||
}
|
||||
}
|
||||
|
||||
// decode block 7-8-9
|
||||
if (memcmp(decrypted + (8*7), empty, 8) != 0 ) {
|
||||
|
||||
// decode block 7-8-9
|
||||
if (memcmp(decrypted + (8 * 7), empty, 8) != 0) {
|
||||
|
||||
//todo: remove preamble/sentinal
|
||||
|
||||
uint32_t top = 0, mid, bot;
|
||||
mid = bytes_to_num(decrypted + (8*7), 4);
|
||||
bot = bytes_to_num(decrypted + (8*7) + 4, 4);
|
||||
mid = bytes_to_num(decrypted + (8 * 7), 4);
|
||||
bot = bytes_to_num(decrypted + (8 * 7) + 4, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "Block 7 binary");
|
||||
PrintAndLogEx(INFO, "Block 7 binary");
|
||||
|
||||
char hexstr[8+1] = {0};
|
||||
hex_to_buffer((uint8_t *)hexstr, decrypted + (8*7), 8, sizeof(hexstr) - 1, 0, 0, true);
|
||||
|
||||
char binstr[8*8+1] = {0};
|
||||
char hexstr[8 + 1] = {0};
|
||||
hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true);
|
||||
|
||||
char binstr[8 * 8 + 1] = {0};
|
||||
hextobinstring(binstr, hexstr);
|
||||
uint8_t i=0;
|
||||
while (i<strlen(binstr) && binstr[i++] == '0');
|
||||
uint8_t i = 0;
|
||||
while (i < strlen(binstr) && binstr[i++] == '0');
|
||||
|
||||
PrintAndLogEx(SUCCESS, "%s", binstr + i);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "Wiegand decode");
|
||||
wiegand_message_t packed = initialize_message_object(top, mid, bot);
|
||||
HIDTryUnpack(&packed, true);
|
||||
|
@ -931,7 +931,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
} else {
|
||||
PrintAndLogEx(INFO, "No credential found.");
|
||||
}
|
||||
|
||||
|
||||
free(decrypted);
|
||||
free(fptr);
|
||||
}
|
||||
|
@ -1757,7 +1757,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
|
|||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "block %02X: %s\n", blockno, sprint_hex(result->blockdata, sizeof(result->blockdata)));
|
||||
|
||||
|
||||
if (blockno == 6) {
|
||||
if (IsCryptoHelperPresent()) {
|
||||
DecodeBlock6(result->blockdata);
|
||||
|
|
|
@ -218,15 +218,15 @@ static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_res
|
|||
|
||||
uint16_t resp_len = 18;
|
||||
uint8_t rdbl_cmd[] = {0x30, blk};
|
||||
uint8_t rdbl_cnt_cmd[] ={0x80};
|
||||
uint8_t rdbl_cnt_cmd[] = {0x80};
|
||||
|
||||
int status = lto_send_cmd_raw(rdbl_cmd, sizeof(rdbl_cmd), block_responce, &resp_len, true, false, verbose);
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT ) {
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT) {
|
||||
return PM3_EWRONGANSVER; // READ BLOCK failed
|
||||
}
|
||||
|
||||
status = lto_send_cmd_raw(rdbl_cnt_cmd, sizeof(rdbl_cnt_cmd), block_cnt_responce, &resp_len, false, false, verbose);
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT ) {
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT) {
|
||||
return PM3_EWRONGANSVER; // READ BLOCK CONTINUE failed
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose) {
|
|||
uint8_t block_data_d16_d31[18];
|
||||
uint8_t block_data[32];
|
||||
|
||||
for(uint8_t i = st_blk; i < end_blk + 1; i++) {
|
||||
for (uint8_t i = st_blk; i < end_blk + 1; i++) {
|
||||
|
||||
ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose);
|
||||
|
||||
|
@ -286,8 +286,8 @@ static int CmdHfLTOReadBlock(const char *Cmd) {
|
|||
case 'h':
|
||||
return usage_lto_rdbl();
|
||||
case 's':
|
||||
st_blk = param_get8(Cmd, cmdp+1);
|
||||
if ( end_blk < st_blk ) {
|
||||
st_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
@ -295,10 +295,11 @@ static int CmdHfLTOReadBlock(const char *Cmd) {
|
|||
break;
|
||||
|
||||
case 'e':
|
||||
end_blk = param_get8(Cmd, cmdp+1);
|
||||
if ( end_blk < st_blk ) {
|
||||
end_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break; }
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
|
||||
|
@ -328,7 +329,7 @@ static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) {
|
|||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
wrbl_d00_d15[i] = data[i];
|
||||
wrbl_d16_d31[i] = data[i+16];
|
||||
wrbl_d16_d31[i] = data[i + 16];
|
||||
}
|
||||
|
||||
int status = lto_send_cmd_raw(wrbl_cmd, sizeof(wrbl_cmd), resp, &resp_len, true, false, verbose);
|
||||
|
@ -390,15 +391,15 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
|
|||
case 'h':
|
||||
return usage_lto_wrbl();
|
||||
case 'b':
|
||||
blk = param_get8(Cmd, cmdp+1);
|
||||
blk = param_get8(Cmd, cmdp + 1);
|
||||
b_opt_selected = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
if (param_gethex(Cmd, cmdp+1, blkData, 64)) {
|
||||
if (param_gethex(Cmd, cmdp + 1, blkData, 64)) {
|
||||
PrintAndLogEx(WARNING, "block data must include 64 HEX symbols");
|
||||
errors = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
d_opt_selected = true;
|
||||
cmdp += 2;
|
||||
|
@ -409,7 +410,7 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Validations
|
||||
if (errors) {
|
||||
usage_lto_wrbl();
|
||||
|
@ -440,7 +441,7 @@ int dumpLTO(uint8_t *dump, bool verbose) {
|
|||
uint8_t block_data_d00_d15[18];
|
||||
uint8_t block_data_d16_d31[18];
|
||||
|
||||
for(uint8_t i = 0; i < 255; i++) {
|
||||
for (uint8_t i = 0; i < 255; i++) {
|
||||
|
||||
ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose);
|
||||
|
||||
|
@ -504,10 +505,10 @@ static int CmdHfLTODump(const char *Cmd) {
|
|||
int ret_val = dumpLTO(dump, true);
|
||||
if (ret_val != PM3_SUCCESS) {
|
||||
free(dump);
|
||||
return ret_val;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// save to file
|
||||
// save to file
|
||||
if (filename[0] == '\0') {
|
||||
memcpy(serial_number, sprint_hex_inrow(dump, sizeof(serial_number)), sizeof(serial_number));
|
||||
char tmp_name[17] = "hf_lto_";
|
||||
|
@ -538,10 +539,10 @@ int restoreLTO(uint8_t *dump_data, bool verbose) {
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
uint8_t blkData[32] = {0};
|
||||
uint8_t blkData[32] = {0};
|
||||
|
||||
//Block address 0 and 1 are read-only
|
||||
for(uint8_t blk = 2; blk < 255; blk++) {
|
||||
for (uint8_t blk = 2; blk < 255; blk++) {
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
blkData[i] = dump_data[i + blk * 32];
|
||||
|
@ -550,7 +551,7 @@ int restoreLTO(uint8_t *dump_data, bool verbose) {
|
|||
ret_val = lto_wrbl(blk, blkData, verbose);
|
||||
|
||||
if (ret_val == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk);
|
||||
PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk);
|
||||
} else {
|
||||
lto_switch_off_field();
|
||||
return ret_val;
|
||||
|
@ -566,7 +567,7 @@ static int CmdHfLTRestore(const char *Cmd) {
|
|||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
int is_data_loaded = PM3_ESOFT;
|
||||
|
||||
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char extension[FILE_PATH_SIZE] = {0};
|
||||
|
||||
|
@ -623,7 +624,7 @@ static int CmdHfLTRestore(const char *Cmd) {
|
|||
} else {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
|
@ -3129,7 +3129,7 @@ out:
|
|||
}
|
||||
|
||||
sector_t *k_sector = NULL;
|
||||
uint8_t k_sectorsCount = 16;
|
||||
uint8_t k_sectorsCount = 40;
|
||||
|
||||
void showSectorTable() {
|
||||
if (k_sector != NULL) {
|
||||
|
@ -4798,6 +4798,95 @@ static int CmdHFMFNDEF(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFMFPersonalize(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf mf personalize",
|
||||
"Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
|
||||
"Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
|
||||
"\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
|
||||
arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
|
||||
arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
|
||||
char keytypestr[2] = "a";
|
||||
uint8_t keytype = 0x00;
|
||||
int keytypestr_len;
|
||||
int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t *)keytypestr, 1, &keytypestr_len);
|
||||
str_lower(keytypestr);
|
||||
|
||||
if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'b')) {
|
||||
PrintAndLogEx(ERR, "ERROR: not a valid key type. Key type must be A or B");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (keytypestr[0] == 'b') {
|
||||
keytype = 0x01;
|
||||
}
|
||||
|
||||
uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int key_len;
|
||||
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
|
||||
if (res || (!res && key_len > 0 && key_len != 6)) {
|
||||
PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char pers_optionstr[6];
|
||||
int opt_len;
|
||||
uint8_t pers_option;
|
||||
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t *)pers_optionstr, 5, &opt_len);
|
||||
str_lower(pers_optionstr);
|
||||
|
||||
if (res || (!res && opt_len > 0 && opt_len != 5)
|
||||
|| (strncmp(pers_optionstr, "uidf0", 5) && strncmp(pers_optionstr, "uidf1", 5) && strncmp(pers_optionstr, "uidf2", 5) && strncmp(pers_optionstr, "uidf3", 5))) {
|
||||
PrintAndLogEx(ERR, "ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (!strncmp(pers_optionstr, "uidf0", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF0;
|
||||
} else if (!strncmp(pers_optionstr, "uidf1", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF1;
|
||||
} else if (!strncmp(pers_optionstr, "uidf2", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF2;
|
||||
} else {
|
||||
pers_option = MIFARE_EV1_UIDF3;
|
||||
}
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
struct {
|
||||
uint8_t keytype;
|
||||
uint8_t pers_option;
|
||||
uint8_t key[6];
|
||||
} PACKED payload;
|
||||
payload.keytype = keytype;
|
||||
payload.pers_option = pers_option;
|
||||
|
||||
memcpy(payload.key, key, 6);
|
||||
|
||||
SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500)) return PM3_ETIMEOUT;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Personalization %s", resp.status == PM3_SUCCESS ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AMfList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return CmdTraceList("mf");
|
||||
|
@ -4845,7 +4934,7 @@ static command_t CommandTable[] = {
|
|||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
||||
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
|
||||
{"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"},
|
||||
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
|
|
@ -1505,7 +1505,7 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// error during nested_hard
|
||||
if (resp.oldarg[0]) {
|
||||
if (nonce_file_write) {
|
||||
|
@ -2034,7 +2034,7 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
|
|||
// create mutexes for accessing the statelist cache and our "book of work"
|
||||
pthread_mutex_init(&statelist_cache_mutex, NULL);
|
||||
pthread_mutex_init(&book_of_work_mutex, NULL);
|
||||
|
||||
|
||||
init_statelist_cache();
|
||||
init_book_of_work();
|
||||
|
||||
|
|
|
@ -457,6 +457,24 @@ int CmdFlexdemod(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int lf_getconfig(sample_config *config) {
|
||||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
if (config == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
memcpy(config, resp.data.asBytes, sizeof(sample_config));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int lf_config(sample_config *config) {
|
||||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
|
@ -464,7 +482,7 @@ int lf_config(sample_config *config) {
|
|||
if (config != NULL)
|
||||
SendCommandNG(CMD_LF_SAMPLING_SET_CONFIG, (uint8_t *)config, sizeof(sample_config));
|
||||
else
|
||||
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
|
||||
SendCommandNG(CMD_LF_SAMPLING_PRINT_CONFIG, NULL, 0);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1333,7 +1351,7 @@ static command_t CommandTable[] = {
|
|||
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
||||
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
|
||||
{"hid", CmdLFHID, AlwaysAvailable, "{ HID RFIDs... }"},
|
||||
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},
|
||||
{"hitag", CmdLFHitag, AlwaysAvailable, "{ Hitag CHIPs... }"},
|
||||
{"indala", CmdLFINDALA, AlwaysAvailable, "{ Indala RFIDs... }"},
|
||||
{"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"},
|
||||
|
|
|
@ -34,5 +34,6 @@ int CmdLFfind(const char *Cmd);
|
|||
|
||||
int lf_read(bool verbose, uint32_t samples);
|
||||
int lf_config(sample_config *config);
|
||||
int lf_getconfig(sample_config *config);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1039,9 +1039,9 @@ static int CmdEM4x50Write(const char *Cmd) {
|
|||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x50_write();
|
||||
PrintAndLogEx(NORMAL, "no implemented yet");
|
||||
//
|
||||
//
|
||||
// PrintAndLogEx(SUCCESS, "Done");
|
||||
// PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify");
|
||||
// PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1440,7 +1440,7 @@ static int CmdEM4x05Write(const char *Cmd) {
|
|||
int status = demodEM4x05resp(&dummy);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify");
|
||||
return status;
|
||||
|
|
|
@ -187,7 +187,10 @@ static int CmdGuardClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf gprox read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdGuardSim(const char *Cmd) {
|
||||
|
|
|
@ -346,7 +346,7 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf hid read`") "to verify");
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf hid read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -450,7 +450,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel);
|
||||
PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode);
|
||||
PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber);
|
||||
switch( direction) {
|
||||
switch (direction) {
|
||||
case 0:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH"));
|
||||
break;
|
||||
|
@ -460,7 +460,8 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
case 2:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN"));
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(INFO, "Brute-forcing HID reader");
|
||||
|
@ -495,7 +496,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
fin_hi = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// do one down
|
||||
if (direction != 1) {
|
||||
if (cn_low.CardNumber > 0) {
|
||||
|
@ -507,7 +508,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
}
|
||||
|
||||
switch (direction) {
|
||||
case 0:
|
||||
case 0:
|
||||
if (fin_hi && fin_low) {
|
||||
exitloop = true;
|
||||
}
|
||||
|
@ -518,7 +519,8 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
case 2:
|
||||
exitloop = fin_low;
|
||||
break;
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while (exitloop == false);
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "protocols.h" // t55 defines
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
|
||||
#define INDALA_ARR_LEN 64
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
//large 224 bit indala formats (different preamble too...)
|
||||
|
@ -140,7 +142,7 @@ static void decodeHeden2L(uint8_t *bits) {
|
|||
if (bits[offset + 7]) cardnumber += 16384;
|
||||
if (bits[offset + 23]) cardnumber += 32768;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\tHeden-2L | %u", cardnumber);
|
||||
PrintAndLogEx(SUCCESS, "\tHeden-2L | " _YELLOW_("%u"), cardnumber);
|
||||
}
|
||||
|
||||
// Indala 26 bit decode
|
||||
|
@ -192,7 +194,7 @@ static int CmdIndalaDemod(const char *Cmd) {
|
|||
if (DemodBufferLen == 64) {
|
||||
PrintAndLogEx(
|
||||
SUCCESS
|
||||
, "Indala Found - bitlength %zu, Raw %x%08x"
|
||||
, "Indala Found - bitlength %zu, Raw " _YELLOW_("%x%08x")
|
||||
, DemodBufferLen
|
||||
, uid1
|
||||
, uid2
|
||||
|
@ -244,14 +246,18 @@ static int CmdIndalaDemod(const char *Cmd) {
|
|||
checksum |= DemodBuffer[63] << 0; // b1
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC " _YELLOW_("%u") ", CN " _YELLOW_("%u") ", checksum %1d%1d"
|
||||
, fc
|
||||
, csn
|
||||
, checksum >> 1 & 0x01
|
||||
, checksum & 0x01
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
|
||||
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo);
|
||||
decodeHeden2L(DemodBuffer);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01);
|
||||
|
||||
|
||||
} else {
|
||||
uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
||||
uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32);
|
||||
|
@ -542,49 +548,62 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
|
||||
static int CmdIndalaClone(const char *Cmd) {
|
||||
|
||||
bool is_long_uid = false, got_cn = false;
|
||||
bool is_long_uid = false, got_cn = false, got_26 = false;
|
||||
bool is_t5555 = false;
|
||||
int32_t cardnumber;
|
||||
uint32_t blocks[8] = {0};
|
||||
uint8_t max = 0;
|
||||
uint8_t data[7 * 4];
|
||||
int datalen = 0;
|
||||
uint8_t fc = 0;
|
||||
uint16_t cn = 0;
|
||||
|
||||
CLIParserInit("lf indala clone",
|
||||
"clone INDALA tag to T55x7 (or to q5/T5555)",
|
||||
"Examples:\n"
|
||||
"\tlf indala clone -c 888\n"
|
||||
"\tlf indala clone --heden 888\n"
|
||||
"\tlf indala clone --fc 123 --cn 1337\n"
|
||||
"\tlf indala clone -r a0000000a0002021\n"
|
||||
"\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("lL", "long", "optional - long UID 224 bits"),
|
||||
arg_int0("cC", "cn", "<decimal>", "Cardnumber for Heden 2L format"),
|
||||
arg_strx0("rR", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"),
|
||||
arg_lit0("lL", "long", "optional - long UID 224 bits"),
|
||||
arg_int0("cC", "heden", "<decimal>", "Cardnumber for Heden 2L format"),
|
||||
arg_strx0("rR", "raw", "<hex>", "raw bytes"),
|
||||
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"),
|
||||
arg_int0("", "fc", "<decimal>", "Facility Code (26 bit format)"),
|
||||
arg_int0("", "cn", "<decimal>", "Cardnumber (26 bit format)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(Cmd, argtable, false);
|
||||
|
||||
is_long_uid = arg_get_lit(1);
|
||||
if (is_long_uid == false) {
|
||||
cardnumber = arg_get_int_def(2, -1);
|
||||
got_cn = (cardnumber != -1);
|
||||
}
|
||||
|
||||
if (got_cn == false) {
|
||||
CLIGetHexWithReturn(3, data, &datalen);
|
||||
}
|
||||
// raw param
|
||||
CLIGetHexWithReturn(3, data, &datalen);
|
||||
|
||||
is_t5555 = arg_get_lit(4);
|
||||
|
||||
if (is_long_uid == false) {
|
||||
|
||||
// Heden param
|
||||
cardnumber = arg_get_int_def(2, -1);
|
||||
got_cn = (cardnumber != -1);
|
||||
|
||||
// 26b FC/CN param
|
||||
fc = arg_get_int_def(5, 0);
|
||||
cn = arg_get_int_def(6, 0);
|
||||
got_26 = (fc != 0 && cn != 0);
|
||||
}
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
if (is_long_uid) {
|
||||
// 224 BIT UID
|
||||
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with RawID %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag");
|
||||
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
|
||||
|
@ -602,12 +621,41 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
} else {
|
||||
// 64 BIT UID
|
||||
if (got_cn) {
|
||||
PrintAndLogEx(INFO, "Using Indala HEDEN cardnumber %u", cardnumber);
|
||||
encodeHeden2L(data, cardnumber);
|
||||
datalen = 8;
|
||||
} else if (got_26) {
|
||||
|
||||
PrintAndLogEx(INFO, "Using Indala 26b FC %u CN %u", fc, cn);
|
||||
|
||||
// Used with the 26bit FC/CSN
|
||||
uint8_t *bits = calloc(INDALA_ARR_LEN, sizeof(uint8_t));
|
||||
if (bits == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
data[0] = bytebits_to_byte(bits, 8);
|
||||
data[1] = bytebits_to_byte(bits + 8, 8);
|
||||
data[2] = bytebits_to_byte(bits + 16, 8);
|
||||
data[3] = bytebits_to_byte(bits + 24, 8);
|
||||
data[4] = bytebits_to_byte(bits + 32, 8);
|
||||
data[5] = bytebits_to_byte(bits + 40, 8);
|
||||
data[6] = bytebits_to_byte(bits + 48, 8);
|
||||
data[7] = bytebits_to_byte(bits + 56, 8);
|
||||
datalen = 8;
|
||||
|
||||
free(bits);
|
||||
}
|
||||
|
||||
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with RawID %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag");
|
||||
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);
|
||||
|
@ -647,6 +695,66 @@ int CmdLFINDALA(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits) {
|
||||
// preamble
|
||||
// is there a preamble?
|
||||
bits[0] = 1;
|
||||
bits[2] = 1;
|
||||
bits[32] = 1;
|
||||
|
||||
// add fc
|
||||
bits[57] = ((fc >> 7) & 1); // b8
|
||||
bits[49] = ((fc >> 6) & 1); // b7
|
||||
bits[44] = ((fc >> 5) & 1); // b6
|
||||
bits[47] = ((fc >> 4) & 1); // b5
|
||||
bits[48] = ((fc >> 3) & 1); // b4
|
||||
bits[53] = ((fc >> 2) & 1); // b3
|
||||
bits[39] = ((fc >> 1) & 1); // b2
|
||||
bits[58] = (fc & 1); // b1
|
||||
|
||||
// add cn
|
||||
bits[42] = ((cn >> 15) & 1); // b16
|
||||
bits[45] = ((cn >> 14) & 1); // b15 - c
|
||||
bits[43] = ((cn >> 13) & 1); // b14
|
||||
bits[40] = ((cn >> 12) & 1); // b13 - c
|
||||
bits[52] = ((cn >> 11) & 1); // b12
|
||||
bits[36] = ((cn >> 10) & 1); // b11
|
||||
bits[35] = ((cn >> 9) & 1); // b10 - c
|
||||
bits[51] = ((cn >> 8) & 1); // b9 - c
|
||||
bits[46] = ((cn >> 7) & 1); // b8
|
||||
bits[33] = ((cn >> 6) & 1); // b7 - c
|
||||
bits[37] = ((cn >> 5) & 1); // b6 - c
|
||||
bits[54] = ((cn >> 4) & 1); // b5
|
||||
bits[56] = ((cn >> 3) & 1); // b4
|
||||
bits[59] = ((cn >> 2) & 1); // b3 - c
|
||||
bits[50] = ((cn >> 1) & 1); // b2
|
||||
bits[41] = (cn & 1); // b1 - c
|
||||
|
||||
// checksum
|
||||
uint8_t chk = 0;
|
||||
//sum(y2, y4, y7, y8, y10, y11, y14, y16
|
||||
chk += ((cn >> 14) & 1); //y2 == 75 - 30 = 45
|
||||
chk += ((cn >> 12) & 1); //y4 == 70 - 30 = 40
|
||||
chk += ((cn >> 9) & 1); //y7 == 65 - 30 = 35
|
||||
chk += ((cn >> 8) & 1); //y8 == 81 - 30 = 51
|
||||
chk += ((cn >> 6) & 1); //y10 == 63 - 30 = 33
|
||||
chk += ((cn >> 5) & 1); //y11 == 67 - 30 = 37
|
||||
chk += ((cn >> 2) & 1); //y14 == 89 - 30 = 59
|
||||
chk += (cn & 1); //y16 == 71 - 30 = 41
|
||||
|
||||
if ((chk & 1) == 0) {
|
||||
bits[62] = 0;
|
||||
bits[63] = 1;
|
||||
} else {
|
||||
bits[62] = 1;
|
||||
bits[63] = 0;
|
||||
}
|
||||
// 92 = 62
|
||||
// 93 = 63
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// redesigned by marshmellow adjusted from existing decode functions
|
||||
// indala id decoding
|
||||
int detectIndala(uint8_t *dest, size_t *size, uint8_t *invert) {
|
||||
|
|
|
@ -19,5 +19,6 @@ int detectIndala26(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
|||
int detectIndala64(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
||||
int detectIndala224(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
||||
int demodIndala(void);
|
||||
int getIndalaBits(uint8_t fc, uint16_t csn, uint8_t *bits);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1083,3 +1083,4 @@ fc9839273862
|
|||
4D8B8B95FDEE
|
||||
354A787087F1
|
||||
4a306e62e9b6
|
||||
B9C874AE63D0
|
||||
|
|
|
@ -529,7 +529,7 @@ const char ice[] =
|
|||
" !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n"
|
||||
_RED_(" . .. .. . . .. ... . . . . . .. . ")
|
||||
"\n...................................................................\n"
|
||||
;
|
||||
;
|
||||
|
||||
// Write a file's segments to Flash
|
||||
int flash_write(flash_file_t *ctx) {
|
||||
|
@ -566,8 +566,8 @@ int flash_write(flash_file_t *ctx) {
|
|||
baddr += block_size;
|
||||
length -= block_size;
|
||||
block++;
|
||||
if ( len < strlen(ice) ) {
|
||||
if (filter_ansi && !isalpha(ice[len]) ) {
|
||||
if (len < strlen(ice)) {
|
||||
if (filter_ansi && !isalpha(ice[len])) {
|
||||
len++;
|
||||
} else {
|
||||
fprintf(stdout, "%c", ice[len++]);
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
-- Run me like this: proxmark3 /dev/rfcomm0 -l ./hf_bruteforce.lua
|
||||
-- Run me like this (connected via USB): ./pm3 -l hf_bruteforce.lua
|
||||
-- Run me like this (connected via Blueshark addon): ./client/proxmark3 /dev/rfcomm0 -l ./hf_bruteforce.lua
|
||||
|
||||
local getopt = require('getopt')
|
||||
|
||||
copyright = ''
|
||||
author = 'Keld Norman'
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
|
||||
]]
|
||||
example = [[
|
||||
-- (the above example would bruteforce card number, starting at 1, ending at 10, and waiting 1 second between each card)
|
||||
|
||||
script run hf_bruteforce -s 1 -e 10 -t 1000
|
||||
]]
|
||||
author = 'Daniel Underhay (updated), Keld Norman(original)'
|
||||
version = 'v2.0.0'
|
||||
usage = [[
|
||||
|
||||
script run hf_bruteforce -s start_id -e end_id -t timeout -d direction
|
||||
pm3 --> script run hf_bruteforce -s start_id -e end_id -t timeout -x mifare_card_type
|
||||
|
||||
Arguments:
|
||||
-h this help
|
||||
-s 0-0xFFFFFFFF start id
|
||||
-e 0-0xFFFFFFFF end id
|
||||
-t 0-99999, pause timeout (ms) between cards (use the word 'pause' to wait for user input)
|
||||
-t 0-99999, pause timeout (ms) between cards (use the word 'pause' to wait for user input)
|
||||
-x mfc, mfu mifare type: mfc for Mifare Classic (default) or mfu for Mifare Ultralight EV1
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
pm3 --> script run hf_bruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc
|
||||
|
||||
Bruteforce a 4 byte UID Mifare classic card number, starting at 11223344, ending at 11223346.
|
||||
|
||||
|
||||
pm3 --> script run hf_bruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu
|
||||
|
||||
Bruteforce a 7 byte UID Mifare Ultralight card number, starting at 11223344556677, ending at 11223344556679.
|
||||
|
||||
]]
|
||||
|
||||
|
||||
|
@ -60,41 +67,49 @@ local function help()
|
|||
print(usage)
|
||||
end
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
--- Print user message
|
||||
local function msg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print('')
|
||||
print(msg)
|
||||
print('')
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
end
|
||||
---
|
||||
-- Start
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
local timeout = 0
|
||||
local start_id = 0
|
||||
local end_id = 0xFFFFFFFF
|
||||
local end_id = 0xFFFFFFFFFFFFFF
|
||||
local mftype = 'mfc'
|
||||
|
||||
for o, a in getopt.getopt(args, 'e:s:t:h') do
|
||||
for o, a in getopt.getopt(args, 'e:s:t:x:h') do
|
||||
if o == 's' then start_id = a end
|
||||
if o == 'e' then end_id = a end
|
||||
if o == 't' then timeout = a end
|
||||
if o == 'x' then mftype = a end
|
||||
if o == 'h' then return print(usage) end
|
||||
end
|
||||
|
||||
-- template
|
||||
local command = 'hf 14a sim t 1 u %08X'
|
||||
local command = ''
|
||||
|
||||
print(' Bruteforcing MFC card numbers from 00000000 to FFFFFFFF using delay: '..timeout)
|
||||
print('')
|
||||
print( string.rep('--',20) )
|
||||
if mftype == 'mfc' then
|
||||
command = 'hf 14a sim t 1 u %14X'
|
||||
msg('Bruteforcing Mifare Classic card numbers')
|
||||
elseif mftype == 'mfu' then
|
||||
command = 'hf 14a sim t 2 u %14X'
|
||||
msg('Bruteforcing Mifare Ultralight card numbers')
|
||||
else
|
||||
return print(usage)
|
||||
end
|
||||
|
||||
if command == '' then return print(usage) end
|
||||
|
||||
for n = start_id, end_id do
|
||||
local c = string.format( command, n )
|
||||
print(' Running: "'..c..'"')
|
||||
print('Running: "'..c..'"')
|
||||
core.console(c)
|
||||
core.console('msleep '..timeout);
|
||||
core.console('hw ping')
|
||||
|
@ -102,4 +117,3 @@ local function main(args)
|
|||
|
||||
end
|
||||
main(args)
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
|||
if (*key != UINT64_C(-1)) {
|
||||
break;
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "all candidate keys failed. Restarting darkside attack");
|
||||
PrintAndLogEx(FAILED, "all key candidates failed. Restarting darkside attack");
|
||||
free(last_keylist);
|
||||
last_keylist = keylist;
|
||||
first_run = true;
|
||||
|
@ -345,7 +345,7 @@ int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultk
|
|||
// copy candidatekeys to test key block
|
||||
memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE);
|
||||
|
||||
// check a block of generated candidate keys.
|
||||
// check a block of generated key candidates.
|
||||
if (mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64) == PM3_SUCCESS) {
|
||||
*resultkey = key64;
|
||||
found = true;
|
||||
|
@ -510,7 +510,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
|||
uint32_t keycnt = statelists[0].len;
|
||||
if (keycnt == 0) goto out;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt);
|
||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "key candidates", keycnt);
|
||||
|
||||
memset(resultKey, 0, 6);
|
||||
uint64_t key64 = -1;
|
||||
|
@ -544,10 +544,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
|||
return -5;
|
||||
}
|
||||
|
||||
float bruteforce_per_second = (float)KEYS_IN_BLOCK / (msclock() - start_time) * 1000.0;
|
||||
|
||||
if ( i + 1 % 10 == 0)
|
||||
PrintAndLogEx(INFO, " %6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt , bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||
// if (i + 1 % 10 == 0) {
|
||||
float bruteforce_per_second = (float)(i + max_keys) / ((msclock() - start_time) / 1000.0);
|
||||
PrintAndLogEx(INFO, "%6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
@ -644,7 +644,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
uint32_t keycnt = statelists[0].len;
|
||||
if (keycnt == 0) goto out;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt);
|
||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "key candidates", keycnt);
|
||||
|
||||
memset(resultKey, 0, 6);
|
||||
uint64_t key64 = -1;
|
||||
|
@ -653,7 +653,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
uint32_t maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK;
|
||||
uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt;
|
||||
|
||||
uint8_t *mem = calloc( (maxkeysinblock * 6) + 5, sizeof(uint8_t));
|
||||
uint8_t *mem = calloc((maxkeysinblock * 6) + 5, sizeof(uint8_t));
|
||||
if (mem == NULL) {
|
||||
free(statelists[0].head.slhead);
|
||||
return PM3_EMALLOC;
|
||||
|
@ -667,7 +667,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
mem[4] = (max_keys_chunk & 0xFF);
|
||||
|
||||
uint8_t destfn[32];
|
||||
strncpy((char*)destfn, "static_nested_000.bin", sizeof(destfn) - 1);
|
||||
strncpy((char *)destfn, "static_nested_000.bin", sizeof(destfn) - 1);
|
||||
|
||||
uint64_t start_time = msclock();
|
||||
for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) {
|
||||
|
@ -689,10 +689,10 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
num_to_bytes(key64, 6, p_keyblock + j * 6);
|
||||
}
|
||||
|
||||
// check a block of generated candidate keys.
|
||||
// check a block of generated key candidates.
|
||||
if (IfPm3Flash()) {
|
||||
// upload to flash.
|
||||
res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6) );
|
||||
// upload to flash.
|
||||
res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6));
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "SPIFFS upload failed");
|
||||
free(mem);
|
||||
|
@ -705,13 +705,13 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
}
|
||||
|
||||
if (res == PM3_SUCCESS) {
|
||||
p_keyblock = NULL;
|
||||
free(statelists[0].head.slhead);
|
||||
free(mem);
|
||||
p_keyblock = NULL;
|
||||
free(statelists[0].head.slhead);
|
||||
free(mem);
|
||||
|
||||
num_to_bytes(key64, 6, resultKey);
|
||||
num_to_bytes(key64, 6, resultKey);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||
package->block,
|
||||
package->keytype ? 'B' : 'A',
|
||||
sprint_hex_inrow(resultKey, 6)
|
||||
|
@ -723,8 +723,8 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
}
|
||||
|
||||
// if (i%10 == 0) {
|
||||
float bruteforce_per_second = (float)i + max_keys_chunk / (msclock() - start_time) * 1000.0;
|
||||
PrintAndLogEx(INFO, "Chunk %6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||
float bruteforce_per_second = (float)(i + max_keys_chunk) / ((msclock() - start_time) / 1000.0);
|
||||
PrintAndLogEx(INFO, "%6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second);
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
|
|||
setLayout(layout);
|
||||
|
||||
// plot window title
|
||||
QString pt = QString("[*]Plot [ %1 ]").arg((char*)gui_serial_port_name);
|
||||
QString pt = QString("[*]Plot [ %1 ]").arg((char *)gui_serial_port_name);
|
||||
setWindowTitle(pt);
|
||||
|
||||
// shows plot window on the screen.
|
||||
|
@ -210,7 +210,7 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
|
|||
controlWidget->resize(size().width(), 200);
|
||||
|
||||
// Olverlays / slider window title
|
||||
QString ct = QString("[*]Slider [ %1 ]").arg((char*)gui_serial_port_name);
|
||||
QString ct = QString("[*]Slider [ %1 ]").arg((char *)gui_serial_port_name);
|
||||
controlWidget->setWindowTitle(ct);
|
||||
|
||||
controlWidget->show();
|
||||
|
|
|
@ -29,7 +29,7 @@ bool IsCryptoHelperPresent(void) {
|
|||
uint8_t resp[20] = {0};
|
||||
ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len);
|
||||
|
||||
if (strstr("CryptoHelper", (char*)resp) == 0) {
|
||||
if (strstr("CryptoHelper", (char *)resp) == 0) {
|
||||
PrintAndLogEx(INFO, "Found smart card helper");
|
||||
return true;
|
||||
} else {
|
||||
|
@ -56,11 +56,11 @@ static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Decrypt(uint8_t *src, uint8_t *dest){
|
||||
bool Decrypt(uint8_t *src, uint8_t *dest) {
|
||||
return executeCrypto(CARD_INS_DECRYPT, src, dest);
|
||||
}
|
||||
|
||||
bool Encrypt(uint8_t *src, uint8_t *dest){
|
||||
bool Encrypt(uint8_t *src, uint8_t *dest) {
|
||||
return executeCrypto(CARD_INS_ENCRYPT, src, dest);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ void getHiLo(int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo) {
|
|||
*low = signalprop.low;
|
||||
}
|
||||
|
||||
// prnt("getHiLo fuzzed: High %d | Low %d", *high, *low);
|
||||
// prnt("getHiLo fuzzed: High %d | Low %d", *high, *low);
|
||||
}
|
||||
|
||||
// by marshmellow
|
||||
|
|
|
@ -277,6 +277,29 @@ pm3 --> hf mf dump
|
|||
pm3 --> hf mf restore 1 u 4A6CE843 k hf-mf-A29558E4-key.bin f hf-mf-A29558E4-data.bin
|
||||
```
|
||||
|
||||
Read Mifare Ultralight EV1
|
||||
```
|
||||
pm3 --> hf mfu info
|
||||
```
|
||||
|
||||
Clone Mifare Ultralight EV1 Sequence
|
||||
```
|
||||
pm3 --> hf mfu dump k FFFFFFFF
|
||||
pm3 --> script run dumptoemul-mfu -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml
|
||||
pm3 --> hf mfu eload u hf-mfu-XXXX-dump.eml
|
||||
pm3 --> hf mfu sim t 7 u hf-mfu-XXXX-dump.eml
|
||||
```
|
||||
|
||||
Bruteforce Mifare Classic card numbers from 11223344 to 11223346
|
||||
```
|
||||
pm3 --> script run hf_bruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc
|
||||
```
|
||||
|
||||
Bruteforce Mifare Ultralight EV1 card numbers from 11223344556677 to 11223344556679
|
||||
```
|
||||
pm3 --> script run hf_bruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu
|
||||
```
|
||||
|
||||
## Wiegand manipulation
|
||||
^[Top](#top)
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ brew upgrade --fetch-HEAD proxmark3
|
|||
|
||||
## Flash the BOOTROM & FULLIMAGE
|
||||
|
||||
With your Proxmark3 unplugged from your machine, press and hold the button on your Proxmark3 as you plug it into a USB port. You can release the button, two of the four LEDs should stay on. You're un bootloader mode, ready for the next step. In case the two LEDs don't stay on when you're releasing the button, you've an old bootloader, start over and keep the button pressed during the whole flashing procedure.
|
||||
With your Proxmark3 unplugged from your machine, press and hold the button on your Proxmark3 as you plug it into a USB port. You can release the button, two of the four LEDs should stay on. You're in bootloader mode, ready for the next step. In case the two LEDs don't stay on when you're releasing the button, you've an old bootloader, start over and keep the button pressed during the whole flashing procedure.
|
||||
|
||||
In principle, the helper script `pm3-flash-all` should auto-detect your port, so you can just try:
|
||||
|
||||
|
|
|
@ -392,7 +392,8 @@ typedef struct {
|
|||
#define CMD_LF_T55XX_WAKEUP 0x0224
|
||||
#define CMD_LF_COTAG_READ 0x0225
|
||||
#define CMD_LF_T55XX_SET_CONFIG 0x0226
|
||||
#define CMD_LF_SAMPLING_GET_CONFIG 0x0227
|
||||
#define CMD_LF_SAMPLING_PRINT_CONFIG 0x0227
|
||||
#define CMD_LF_SAMPLING_GET_CONFIG 0x0228
|
||||
|
||||
#define CMD_LF_T55XX_CHK_PWDS 0x0230
|
||||
#define CMD_LF_T55XX_DANGERRAW 0x0231
|
||||
|
@ -504,6 +505,8 @@ typedef struct {
|
|||
|
||||
#define CMD_HF_MIFARE_SNIFF 0x0630
|
||||
#define CMD_HF_MIFARE_MFKEY 0x0631
|
||||
#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632
|
||||
|
||||
//ultralightC
|
||||
#define CMD_HF_MIFAREUC_AUTH 0x0724
|
||||
//0x0725 and 0x0726 no longer used
|
||||
|
|
|
@ -163,6 +163,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
|
||||
#define MIFARE_EV1_PERSONAL_UID 0x40
|
||||
#define MIFARE_EV1_SETMODE 0x43
|
||||
#define MIFARE_EV1_UIDF0 0x00
|
||||
#define MIFARE_EV1_UIDF1 0x40
|
||||
#define MIFARE_EV1_UIDF2 0x20
|
||||
#define MIFARE_EV1_UIDF3 0x60
|
||||
|
||||
#define MIFARE_ULC_WRITE 0xA2
|
||||
#define MIFARE_ULC_COMP_WRITE 0xA0
|
||||
|
@ -308,7 +312,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define PROTO_HITAG1 10
|
||||
#define THINFILM 11
|
||||
#define LTO 12
|
||||
#define PROTO_HITAG2 13
|
||||
#define PROTO_HITAG2 13
|
||||
#define PROTO_HITAGS 14
|
||||
|
||||
//-- Picopass fuses
|
||||
|
@ -595,7 +599,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
|
||||
#define HITAG2_READ_PAGE 0x3 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_READ_PAGE_INVERTED 0x1 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_WRITE_PAGE 0x2 // page number in bits 5 to 3, page number
|
||||
#define HITAG2_WRITE_PAGE 0x2 // page number in bits 5 to 3, page number
|
||||
|
||||
|
||||
// HITAG S commands
|
||||
|
|
|
@ -22,4 +22,4 @@ $(OBJDIR)/libz.a:
|
|||
|
||||
tarbin: $(BINS)
|
||||
$(info [=] TAR ../proxmark3-$(platform)-bin.tar)
|
||||
$(Q)$(TAR) $(TARFLAGS) ../../proxmark3-$(platform)-bin.tar $(BINS:%=fpga_compress/%) $(WINBINS:%=fpga_compress/%)
|
||||
$(Q)$(TAR) $(TARFLAGS) ../../proxmark3-$(platform)-bin.tar $(BINS:%=fpga_compress/%) $(WINBINS:%=fpga_compress/%)
|
||||
|
|
|
@ -142,11 +142,11 @@ typedef int rtccDate;
|
|||
|
||||
|
||||
#ifndef __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#endif
|
||||
|
||||
|
||||
#define GetSystemClock() (80000000ul)
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetInstructionClock() (GetSystemClock())
|
||||
|
||||
//#define USE_SELF_POWER_SENSE_IO
|
||||
|
@ -322,7 +322,7 @@ typedef int rtccDate;
|
|||
// spi for SD card
|
||||
#define SD_CARD_DET LATFbits.LATF0
|
||||
#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
#define SPI_SD SPI_CHANNEL1
|
||||
#define SPI_SD_BUFF SPI1BUF
|
||||
#define SPI_SD_STAT SPI1STATbits
|
||||
|
|
|
@ -229,17 +229,16 @@ static uint32_t hitag2_crypt(uint64_t x);
|
|||
((S >> (C - 3)) & 8) )
|
||||
|
||||
|
||||
static uint32_t hitag2_crypt(uint64_t s)
|
||||
{
|
||||
static uint32_t hitag2_crypt(uint64_t s) {
|
||||
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
|
||||
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
|
||||
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
uint32_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
|
||||
|
||||
DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex);
|
||||
|
@ -253,13 +252,12 @@ static uint32_t hitag2_crypt(uint64_t s)
|
|||
* uint32_t serialnum - 32 bit tag serial number
|
||||
* uint32_t initvector - 32 bit random IV from reader, part of tag authentication
|
||||
*/
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector)
|
||||
{
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) {
|
||||
// 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
|
||||
initvector ^= (uint32_t) (sharedkey >> 16);
|
||||
initvector ^= (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
|
||||
|
@ -320,9 +318,9 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
// optimise with one 64-bit intermediate
|
||||
uint64_t temp = state ^ (state >> 1);
|
||||
pstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,8 +336,7 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
* Hitag_State* pstate - in/out, internal cipher state after initialisation
|
||||
* uint32_t steps - number of bits requested, (capped at 32)
|
||||
*/
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps)
|
||||
{
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps) {
|
||||
uint64_t state = pstate->shiftreg;
|
||||
uint32_t result = 0;
|
||||
uint64_t lfsr = pstate->lfsr;
|
||||
|
@ -448,7 +445,7 @@ unsigned hitag2_verifytest()
|
|||
const uint64_t key = rev64 (0x524B494D4E4FUL);
|
||||
const uint32_t serial = rev32 (0x69574349);
|
||||
const uint32_t initvec = rev32 (0x72456E65);
|
||||
|
||||
|
||||
uint32_t i;
|
||||
Hitag_State state;
|
||||
|
||||
|
@ -471,11 +468,10 @@ unsigned hitag2_verifytest()
|
|||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned pass = hitag2_verifytest();
|
||||
|
||||
printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
printf("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
|
||||
if (pass) {
|
||||
hitag2_benchtest(10000);
|
||||
|
|
|
@ -159,9 +159,9 @@ typedef struct {
|
|||
uint64_t lfsr; // fast lfsr, used to make software faster
|
||||
} Hitag_State;
|
||||
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps);
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps);
|
||||
|
||||
unsigned int hitag2_benchtest_gen32();
|
||||
unsigned int hitag2_benchtest(uint32_t count);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
//
|
||||
// If sorting fails with a 'bus error' then that is likely because your disk I/O can't keep up with
|
||||
// the read/write demands of the multi-threaded sorting. In this case, reduce the number of sorting
|
||||
// threads. This will most likely only be a problem with network disks; SATA should be okay;
|
||||
// threads. This will most likely only be a problem with network disks; SATA should be okay;
|
||||
// USB2/3 should keep up.
|
||||
//
|
||||
// These MUST be a power of 2 for the maths to work - you have been warned!
|
||||
|
@ -53,8 +53,7 @@ uint64_t d2[48];
|
|||
int nsteps2;
|
||||
|
||||
// create table entry
|
||||
void create_table(struct table *t, int d1, int d2)
|
||||
{
|
||||
void create_table(struct table *t, int d1, int d2) {
|
||||
if (!t) {
|
||||
printf("create_table: t is NULL\n");
|
||||
exit(1);
|
||||
|
@ -83,8 +82,7 @@ void create_table(struct table *t, int d1, int d2)
|
|||
|
||||
|
||||
// create all table entries
|
||||
void create_tables(struct table *t)
|
||||
{
|
||||
void create_tables(struct table *t) {
|
||||
int i, j;
|
||||
|
||||
if (!t) {
|
||||
|
@ -92,8 +90,8 @@ void create_tables(struct table *t)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<0x100; i++) {
|
||||
for (j=0; j<0x100; j++) {
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
for (j = 0; j < 0x100; j++) {
|
||||
create_table(t + ((i * 0x100) + j), i, j);
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +99,7 @@ void create_tables(struct table *t)
|
|||
|
||||
|
||||
// free the table memory
|
||||
void free_tables(struct table *t)
|
||||
{
|
||||
void free_tables(struct table *t) {
|
||||
int i;
|
||||
struct table *ttmp;
|
||||
|
||||
|
@ -111,7 +108,7 @@ void free_tables(struct table *t)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<0x10000; i++) {
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
ttmp = t + i;
|
||||
free(ttmp->data);
|
||||
}
|
||||
|
@ -120,8 +117,7 @@ void free_tables(struct table *t)
|
|||
|
||||
|
||||
// write (partial) table to file
|
||||
void writetable(struct table *t1)
|
||||
{
|
||||
void writetable(struct table *t1) {
|
||||
int fd;
|
||||
|
||||
if (debug) printf("writetable %s\n", t1->path);
|
||||
|
@ -146,8 +142,7 @@ void writetable(struct table *t1)
|
|||
|
||||
|
||||
// store value in table
|
||||
void store(unsigned char *data)
|
||||
{
|
||||
void store(unsigned char *data) {
|
||||
unsigned char d1, d2;
|
||||
int offset;
|
||||
struct table *t1;
|
||||
|
@ -171,7 +166,7 @@ void store(unsigned char *data)
|
|||
if (debug) printf("store, offset = %d, got lock\n", offset);
|
||||
|
||||
// store the entry
|
||||
memcpy(t1->ptr, data+2, 10);
|
||||
memcpy(t1->ptr, data + 2, 10);
|
||||
|
||||
if (debug) printf("store, offset = %d, copied data\n", offset);
|
||||
|
||||
|
@ -199,14 +194,13 @@ void store(unsigned char *data)
|
|||
}
|
||||
|
||||
// writes the ks (keystream) and s (state)
|
||||
void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg)
|
||||
{
|
||||
void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) {
|
||||
unsigned char buf[16];
|
||||
|
||||
// create buffer
|
||||
writebuf(buf, ks1, 3);
|
||||
writebuf(buf+3, ks2, 3);
|
||||
writebuf(buf+6, shiftreg, 6);
|
||||
writebuf(buf + 3, ks2, 3);
|
||||
writebuf(buf + 6, shiftreg, 6);
|
||||
|
||||
// store buffer
|
||||
store(buf);
|
||||
|
@ -215,8 +209,7 @@ void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg)
|
|||
|
||||
|
||||
// builds the di table for jumping
|
||||
void builddi(int steps, int table)
|
||||
{
|
||||
void builddi(int steps, int table) {
|
||||
uint64_t statemask;
|
||||
int i;
|
||||
Hitag_State mystate;
|
||||
|
@ -237,7 +230,7 @@ void builddi(int steps, int table)
|
|||
}
|
||||
|
||||
// build di states
|
||||
for (i=0; i<48; i++) {
|
||||
for (i = 0; i < 48; i++) {
|
||||
mystate.shiftreg = statemask;
|
||||
buildlfsr(&mystate);
|
||||
hitag2_nstep(&mystate, steps);
|
||||
|
@ -248,8 +241,7 @@ void builddi(int steps, int table)
|
|||
}
|
||||
|
||||
// jump function - quickly jumps a load of steps
|
||||
void jumpnsteps(Hitag_State *hstate, int table)
|
||||
{
|
||||
void jumpnsteps(Hitag_State *hstate, int table) {
|
||||
uint64_t output = 0;
|
||||
uint64_t bitmask;
|
||||
int i;
|
||||
|
@ -271,7 +263,7 @@ void jumpnsteps(Hitag_State *hstate, int table)
|
|||
// if si is 1, di.si = di; if si is 0, di.si = 0
|
||||
|
||||
bitmask = 1;
|
||||
for (i=0; i<48; i++) {
|
||||
for (i = 0; i < 48; i++) {
|
||||
if (hstate->shiftreg & bitmask) {
|
||||
output = output ^ thisd[i];
|
||||
}
|
||||
|
@ -281,12 +273,11 @@ void jumpnsteps(Hitag_State *hstate, int table)
|
|||
|
||||
hstate->shiftreg = output;
|
||||
buildlfsr(hstate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// thread to build a part of the table
|
||||
void *buildtable(void *d)
|
||||
{
|
||||
void *buildtable(void *d) {
|
||||
Hitag_State hstate;
|
||||
Hitag_State hstate2;
|
||||
unsigned long i;
|
||||
|
@ -301,7 +292,7 @@ void *buildtable(void *d)
|
|||
buildlfsr(&hstate);
|
||||
|
||||
/* jump to offset using jump table 2 (2048) */
|
||||
for (i=0; i<index; i++) {
|
||||
for (i = 0; i < index; i++) {
|
||||
jumpnsteps(&hstate, 2);
|
||||
}
|
||||
|
||||
|
@ -319,7 +310,7 @@ void *buildtable(void *d)
|
|||
}
|
||||
|
||||
/* make the entries */
|
||||
for (i=0; i<maxentries; i++) {
|
||||
for (i = 0; i < maxentries; i++) {
|
||||
|
||||
// copy the current state
|
||||
hstate2.shiftreg = hstate.shiftreg;
|
||||
|
@ -343,8 +334,7 @@ void *buildtable(void *d)
|
|||
|
||||
|
||||
// make 'table/' (unsorted) and 'sorted/' dir structures
|
||||
void makedirs()
|
||||
{
|
||||
void makedirs() {
|
||||
char path[32];
|
||||
int i;
|
||||
|
||||
|
@ -357,7 +347,7 @@ void makedirs()
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<0x100; i++) {
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
sprintf(path, "table/%02x", i);
|
||||
if (mkdir(path, 0755)) {
|
||||
printf("cannot make dir %s\n", path);
|
||||
|
@ -371,16 +361,14 @@ void makedirs()
|
|||
}
|
||||
}
|
||||
|
||||
static int datacmp(const void *p1, const void *p2, void *dummy)
|
||||
{
|
||||
static int datacmp(const void *p1, const void *p2, void *dummy) {
|
||||
unsigned char *d1 = (unsigned char *)p1;
|
||||
unsigned char *d2 = (unsigned char *)p2;
|
||||
|
||||
return memcmp(d1, d2, DATASIZE);
|
||||
}
|
||||
|
||||
void *sorttable(void *d)
|
||||
{
|
||||
void *sorttable(void *d) {
|
||||
int i, j;
|
||||
int fdin;
|
||||
int fdout;
|
||||
|
@ -401,9 +389,9 @@ void *sorttable(void *d)
|
|||
}
|
||||
|
||||
// loop over our first byte values
|
||||
for (i=(index * space); i<((index + 1) * space); i++) {
|
||||
for (i = (index * space); i < ((index + 1) * space); i++) {
|
||||
// loop over all second byte values
|
||||
for (j=0; j<0x100; j++) {
|
||||
for (j = 0; j < 0x100; j++) {
|
||||
|
||||
printf("sorttable: processing bytes 0x%02x/0x%02x\n", i, j);
|
||||
|
||||
|
@ -464,8 +452,7 @@ void *sorttable(void *d)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
pthread_t threads[NUM_BUILD_THREADS];
|
||||
void *status;
|
||||
long i;
|
||||
|
@ -493,7 +480,7 @@ int main(int argc, char *argv[])
|
|||
builddi(2048, 2);
|
||||
|
||||
// start the threads
|
||||
for (i=0; i<NUM_BUILD_THREADS; i++) {
|
||||
for (i = 0; i < NUM_BUILD_THREADS; i++) {
|
||||
ret = pthread_create(&(threads[i]), NULL, buildtable, (void *)(i));
|
||||
if (ret) {
|
||||
printf("cannot start buildtable thread %ld\n", i);
|
||||
|
@ -504,7 +491,7 @@ int main(int argc, char *argv[])
|
|||
if (debug) printf("main, started buildtable threads\n");
|
||||
|
||||
// wait for threads to finish
|
||||
for (i=0; i<NUM_BUILD_THREADS; i++) {
|
||||
for (i = 0; i < NUM_BUILD_THREADS; i++) {
|
||||
ret = pthread_join(threads[i], &status);
|
||||
if (ret) {
|
||||
printf("cannot join buildtable thread %ld\n", i);
|
||||
|
@ -514,7 +501,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
// write all remaining files
|
||||
for (i=0; i<0x10000; i++) {
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
t1 = t + i;
|
||||
if (t1->ptr > t1->data) {
|
||||
writetable(t1);
|
||||
|
@ -531,7 +518,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
|
||||
// start the threads
|
||||
for (i=0; i<NUM_SORT_THREADS; i++) {
|
||||
for (i = 0; i < NUM_SORT_THREADS; i++) {
|
||||
ret = pthread_create(&(threads[i]), NULL, sorttable, (void *)(i));
|
||||
if (ret) {
|
||||
printf("cannot start sorttable thread %ld\n", i);
|
||||
|
@ -542,7 +529,7 @@ int main(int argc, char *argv[])
|
|||
if (debug) printf("main, started sorttable threads\n");
|
||||
|
||||
// wait for threads to finish
|
||||
for (i=0; i<NUM_SORT_THREADS; i++) {
|
||||
for (i = 0; i < NUM_SORT_THREADS; i++) {
|
||||
ret = pthread_join(threads[i], &status);
|
||||
if (ret) {
|
||||
printf("cannot join sorttable thread %ld\n", i);
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#include "ht2crack2utils.h"
|
||||
|
||||
|
||||
int makerandom(char *hex, unsigned int len, int fd)
|
||||
{
|
||||
int makerandom(char *hex, unsigned int len, int fd) {
|
||||
unsigned char raw[32];
|
||||
int i;
|
||||
|
||||
|
@ -26,7 +25,7 @@ int makerandom(char *hex, unsigned int len, int fd)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
sprintf(hex + (2 * i), "%02X", raw[i]);
|
||||
}
|
||||
|
||||
|
@ -34,8 +33,7 @@ int makerandom(char *hex, unsigned int len, int fd)
|
|||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
Hitag_State hstate;
|
||||
char key[32];
|
||||
char uid[32];
|
||||
|
@ -64,7 +62,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
|
||||
for (i=0; i<numtests; i++) {
|
||||
for (i = 0; i < numtests; i++) {
|
||||
|
||||
makerandom(key, 6, urandomfd);
|
||||
makerandom(uid, 4, urandomfd);
|
||||
|
@ -84,7 +82,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
hitag2_nstep(&hstate, 64);
|
||||
|
||||
for (j=0; j<64; j++) {
|
||||
for (j = 0; j < 64; j++) {
|
||||
fprintf(fp, "%08X\n", hitag2_nstep(&hstate, 32));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,16 +17,14 @@ struct rngdata {
|
|||
|
||||
|
||||
|
||||
static int datacmp(const void *p1, const void *p2)
|
||||
{
|
||||
static int datacmp(const void *p1, const void *p2) {
|
||||
unsigned char *d1 = (unsigned char *)p1;
|
||||
unsigned char *d2 = (unsigned char *)p2;
|
||||
|
||||
return memcmp(d1, d2, DATASIZE - 6);
|
||||
}
|
||||
|
||||
int loadrngdata(struct rngdata *r, char *file)
|
||||
{
|
||||
int loadrngdata(struct rngdata *r, char *file) {
|
||||
int fd;
|
||||
int i, j;
|
||||
int nibble;
|
||||
|
@ -72,7 +70,7 @@ int loadrngdata(struct rngdata *r, char *file)
|
|||
|
||||
j = 0;
|
||||
nibble = 0;
|
||||
for (i=0; (i<filestat.st_size) && (j < r->len); i++) {
|
||||
for (i = 0; (i < filestat.st_size) && (j < r->len); i++) {
|
||||
if ((data[i] != 0x0a) && (data[i] != 0x0d) && (data[i] != 0x20)) {
|
||||
if (!nibble) {
|
||||
r->data[j] = hex2bin(data[i]) << 4;
|
||||
|
@ -93,8 +91,7 @@ int loadrngdata(struct rngdata *r, char *file)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int makecand(unsigned char *c, struct rngdata *r, int bitoffset)
|
||||
{
|
||||
int makecand(unsigned char *c, struct rngdata *r, int bitoffset) {
|
||||
int bytenum;
|
||||
int bitnum;
|
||||
int i;
|
||||
|
@ -107,7 +104,7 @@ int makecand(unsigned char *c, struct rngdata *r, int bitoffset)
|
|||
bytenum = bitoffset / 8;
|
||||
bitnum = bitoffset % 8;
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (!bitnum) {
|
||||
c[i] = r->data[bytenum + i];
|
||||
} else {
|
||||
|
@ -120,8 +117,7 @@ int makecand(unsigned char *c, struct rngdata *r, int bitoffset)
|
|||
|
||||
|
||||
// test the candidate against the next or previous rng data
|
||||
int testcand(unsigned char *f, unsigned char *rt, int fwd)
|
||||
{
|
||||
int testcand(unsigned char *f, unsigned char *rt, int fwd) {
|
||||
Hitag_State hstate;
|
||||
int i;
|
||||
uint32_t ks1;
|
||||
|
@ -130,8 +126,8 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd)
|
|||
|
||||
// build the prng state at the candidate
|
||||
hstate.shiftreg = 0;
|
||||
for (i=0; i<6; i++) {
|
||||
hstate.shiftreg = (hstate.shiftreg << 8) | f[i+4];
|
||||
for (i = 0; i < 6; i++) {
|
||||
hstate.shiftreg = (hstate.shiftreg << 8) | f[i + 4];
|
||||
}
|
||||
buildlfsr(&hstate);
|
||||
|
||||
|
@ -149,7 +145,7 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd)
|
|||
ks2 = hitag2_nstep(&hstate, 24);
|
||||
|
||||
writebuf(buf, ks1, 3);
|
||||
writebuf(buf+3, ks2, 3);
|
||||
writebuf(buf + 3, ks2, 3);
|
||||
|
||||
// compare them
|
||||
if (!memcmp(buf, rt, 6)) {
|
||||
|
@ -159,8 +155,7 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd)
|
|||
}
|
||||
}
|
||||
|
||||
int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s)
|
||||
{
|
||||
int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s) {
|
||||
int fd;
|
||||
struct stat filestat;
|
||||
char file[64];
|
||||
|
@ -193,7 +188,7 @@ int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, u
|
|||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(item, c+2, 4);
|
||||
memcpy(item, c + 2, 4);
|
||||
|
||||
found = (unsigned char *)bsearch(item, data, filestat.st_size / DATASIZE, DATASIZE, datacmp);
|
||||
|
||||
|
@ -209,13 +204,13 @@ int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, u
|
|||
while (((found - data) <= (filestat.st_size - DATASIZE)) && (!memcmp(found, item, 4))) {
|
||||
if (testcand(found, rt, fwd)) {
|
||||
memcpy(m, c, 2);
|
||||
memcpy(m+2, found, 4);
|
||||
memcpy(s, found+4, 6);
|
||||
memcpy(m + 2, found, 4);
|
||||
memcpy(s, found + 4, 6);
|
||||
|
||||
munmap(data, filestat.st_size);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
found = found + DATASIZE;
|
||||
}
|
||||
|
@ -228,8 +223,7 @@ int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, u
|
|||
|
||||
}
|
||||
|
||||
int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset)
|
||||
{
|
||||
int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset) {
|
||||
int i;
|
||||
int bitlen;
|
||||
unsigned char cand[6];
|
||||
|
@ -243,7 +237,7 @@ int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstat
|
|||
|
||||
bitlen = r->len * 8;
|
||||
|
||||
for (i=0; i<=bitlen - 48; i++) {
|
||||
for (i = 0; i <= bitlen - 48; i++) {
|
||||
// print progress
|
||||
if ((i % 100) == 0) {
|
||||
printf("searching on bit %d\n", i);
|
||||
|
@ -283,8 +277,7 @@ int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstat
|
|||
|
||||
|
||||
|
||||
void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset)
|
||||
{
|
||||
void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) {
|
||||
int i;
|
||||
|
||||
if (!s) {
|
||||
|
@ -294,7 +287,7 @@ void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset)
|
|||
|
||||
// build prng at recovered offset
|
||||
hstate->shiftreg = 0;
|
||||
for (i=0; i<6; i++) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
hstate->shiftreg = (hstate->shiftreg << 8) | s[i];
|
||||
}
|
||||
|
||||
|
@ -313,8 +306,7 @@ void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset)
|
|||
|
||||
}
|
||||
|
||||
uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr)
|
||||
{
|
||||
uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr) {
|
||||
uint64_t key;
|
||||
uint64_t keyupper;
|
||||
uint32_t uid;
|
||||
|
@ -333,7 +325,7 @@ uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr)
|
|||
|
||||
uidtmp = uid;
|
||||
// rollback and extract bits b
|
||||
for (i=0; i<32; i++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uidtmp >> 31) & 0x1);
|
||||
uidtmp = uidtmp << 1;
|
||||
b = (b << 1) | fnf(hstate->shiftreg);
|
||||
|
@ -364,8 +356,7 @@ uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr)
|
|||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
Hitag_State hstate;
|
||||
struct rngdata rng;
|
||||
int bitoffset = 0;
|
||||
|
@ -420,7 +411,7 @@ int main(int argc, char *argv[])
|
|||
printf("\n");
|
||||
|
||||
printf("KEY:\t\t");
|
||||
for (i=0; i<6; i++) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
printf("%02X", (int)(key & 0xff));
|
||||
key = key >> 8;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#include "ht2crack2utils.h"
|
||||
|
||||
// writes a value into a buffer as a series of bytes
|
||||
void writebuf(unsigned char *buf, uint64_t val, unsigned int len)
|
||||
{
|
||||
void writebuf(unsigned char *buf, uint64_t val, unsigned int len) {
|
||||
int i;
|
||||
char c;
|
||||
|
||||
for (i=len-1; i>=0; i--)
|
||||
{
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
c = val & 0xff;
|
||||
buf[i] = c;
|
||||
val = val >> 8;
|
||||
|
@ -17,18 +15,17 @@ void writebuf(unsigned char *buf, uint64_t val, unsigned int len)
|
|||
|
||||
|
||||
/* simple hexdump for testing purposes */
|
||||
void shexdump(unsigned char *data, int data_len)
|
||||
{
|
||||
void shexdump(unsigned char *data, int data_len) {
|
||||
int i;
|
||||
|
||||
if (!data || (data_len <= 0)) {
|
||||
printf("shexdump: invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
printf("Hexdump from %p:\n", data);
|
||||
|
||||
for (i=0; i<data_len; i++) {
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if ((i % HEX_PER_ROW) == 0) {
|
||||
printf("\n0x%04x: ", i);
|
||||
}
|
||||
|
@ -39,8 +36,7 @@ void shexdump(unsigned char *data, int data_len)
|
|||
|
||||
|
||||
|
||||
void printbin(unsigned char *c)
|
||||
{
|
||||
void printbin(unsigned char *c) {
|
||||
int i, j;
|
||||
unsigned char x;
|
||||
|
||||
|
@ -49,9 +45,9 @@ void printbin(unsigned char *c)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
x = c[i];
|
||||
for (j=0; j<8; j++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
printf("%d", (x & 0x80) >> 7);
|
||||
x = x << 1;
|
||||
}
|
||||
|
@ -60,14 +56,13 @@ void printbin(unsigned char *c)
|
|||
}
|
||||
|
||||
|
||||
void printbin2(uint64_t val, unsigned int size)
|
||||
{
|
||||
void printbin2(uint64_t val, unsigned int size) {
|
||||
int i;
|
||||
uint64_t mask = 1;
|
||||
|
||||
mask = mask << (size - 1);
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
if (val & mask) {
|
||||
printf("1");
|
||||
} else {
|
||||
|
@ -78,8 +73,7 @@ void printbin2(uint64_t val, unsigned int size)
|
|||
}
|
||||
|
||||
|
||||
void printstate(Hitag_State *hstate)
|
||||
{
|
||||
void printstate(Hitag_State *hstate) {
|
||||
printf("shiftreg =\t");
|
||||
printbin2(hstate->shiftreg, 48);
|
||||
printf("\n");
|
||||
|
@ -89,8 +83,7 @@ void printstate(Hitag_State *hstate)
|
|||
|
||||
|
||||
// convert hex char to binary
|
||||
unsigned char hex2bin(unsigned char c)
|
||||
{
|
||||
unsigned char hex2bin(unsigned char c) {
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
return (c - '0');
|
||||
} else if ((c >= 'a') && (c <= 'f')) {
|
||||
|
@ -103,8 +96,7 @@ unsigned char hex2bin(unsigned char c)
|
|||
}
|
||||
|
||||
// return a single bit from a value
|
||||
int bitn(uint64_t x, int bit)
|
||||
{
|
||||
int bitn(uint64_t x, int bit) {
|
||||
uint64_t bitmask = 1;
|
||||
|
||||
bitmask = bitmask << bit;
|
||||
|
@ -118,20 +110,18 @@ int bitn(uint64_t x, int bit)
|
|||
|
||||
|
||||
// the sub-function R that rollback depends upon
|
||||
int fnR(uint64_t x)
|
||||
{
|
||||
int fnR(uint64_t x) {
|
||||
// renumbered bits because my state is 0-47, not 1-48
|
||||
return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^
|
||||
bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^
|
||||
bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^
|
||||
bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
}
|
||||
|
||||
// the rollback function that lets us go backwards in time
|
||||
void rollback(Hitag_State *hstate, unsigned int steps)
|
||||
{
|
||||
void rollback(Hitag_State *hstate, unsigned int steps) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<steps; i++) {
|
||||
for (i = 0; i < steps; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | fnR(hstate->shiftreg);
|
||||
}
|
||||
|
||||
|
@ -139,24 +129,20 @@ void rollback(Hitag_State *hstate, unsigned int steps)
|
|||
|
||||
|
||||
// the three filter sub-functions that feed fnf
|
||||
int fa(unsigned int i)
|
||||
{
|
||||
int fa(unsigned int i) {
|
||||
return bitn(0x2C79, i);
|
||||
}
|
||||
|
||||
int fb(unsigned int i)
|
||||
{
|
||||
int fb(unsigned int i) {
|
||||
return bitn(0x6671, i);
|
||||
}
|
||||
|
||||
int fc(unsigned int i)
|
||||
{
|
||||
int fc(unsigned int i) {
|
||||
return bitn(0x7907287B, i);
|
||||
}
|
||||
|
||||
// the filter function that generates a bit of output from the prng state
|
||||
int fnf(uint64_t s)
|
||||
{
|
||||
int fnf(uint64_t s) {
|
||||
unsigned int x1, x2, x3, x4, x5, x6;
|
||||
|
||||
x1 = (bitn(s, 2) << 0) | (bitn(s, 3) << 1) | (bitn(s, 5) << 2) | (bitn(s, 6) << 3);
|
||||
|
@ -171,16 +157,15 @@ int fnf(uint64_t s)
|
|||
}
|
||||
|
||||
// builds the lfsr for the prng (quick calcs for hitag2_nstep())
|
||||
void buildlfsr(Hitag_State *hstate)
|
||||
{
|
||||
void buildlfsr(Hitag_State *hstate) {
|
||||
uint64_t state = hstate->shiftreg;
|
||||
uint64_t temp;
|
||||
|
||||
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);
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ extern rtccDate RTC_date; // date structure
|
|||
#define TAG_TYPE_AWID_26 17
|
||||
#define TAG_TYPE_EM4X05 18
|
||||
#define TAG_TYPE_TAMAGOTCHI 19
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
|
||||
// various
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ unsigned char getbit(unsigned char byte, unsigned char bit);
|
|||
void bytestohex(unsigned char *target, unsigned char *source, unsigned int length);
|
||||
unsigned int manchester_encode(unsigned char *target, unsigned char *source, unsigned int length);
|
||||
unsigned int manchester_decode(unsigned char *target, unsigned char *source, unsigned int length);
|
||||
char * strip_newline(char *buff);
|
||||
char *strip_newline(char *buff);
|
||||
BOOL command_ack(BOOL data);
|
||||
BOOL command_nack(BYTE *reason);
|
||||
BOOL command_unknown(void);
|
||||
|
|
|
@ -142,19 +142,17 @@ rtccTime RTC_time; // time structure
|
|||
rtccDate RTC_date; // date structure
|
||||
|
||||
// convert byte-reversed 8 digit hex to unsigned long
|
||||
unsigned long hexreversetoulong(BYTE *hex)
|
||||
{
|
||||
unsigned long ret= 0L;
|
||||
unsigned long hexreversetoulong(BYTE *hex) {
|
||||
unsigned long ret = 0L;
|
||||
unsigned int x;
|
||||
BYTE i;
|
||||
|
||||
if(strlen(hex) != 8)
|
||||
if (strlen(hex) != 8)
|
||||
return 0L;
|
||||
|
||||
for(i= 0 ; i < 4 ; ++i)
|
||||
{
|
||||
if(sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
for (i = 0 ; i < 4 ; ++i) {
|
||||
if (sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
ret += ((unsigned long) x) << i * 8;
|
||||
hex += 2;
|
||||
}
|
||||
|
@ -162,18 +160,17 @@ unsigned long hexreversetoulong(BYTE *hex)
|
|||
}
|
||||
|
||||
// convert byte-reversed 12 digit hex to unsigned long
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex)
|
||||
{
|
||||
unsigned long long ret= 0LL;
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex) {
|
||||
unsigned long long ret = 0LL;
|
||||
BYTE tmp[9];
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
// breaking direct conversion!
|
||||
|
||||
tmp[8]= '\0';
|
||||
|
||||
tmp[8] = '\0';
|
||||
memset(tmp + 4, '0', 4);
|
||||
memcpy(tmp, hex + 8, 4);
|
||||
ret= hexreversetoulong(tmp);
|
||||
ret = hexreversetoulong(tmp);
|
||||
ret <<= 32;
|
||||
memcpy(tmp, hex, 8);
|
||||
ret += hexreversetoulong(tmp);
|
||||
|
|
|
@ -142,11 +142,11 @@ typedef int rtccDate;
|
|||
|
||||
|
||||
#ifndef __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#endif
|
||||
|
||||
|
||||
#define GetSystemClock() (80000000ul)
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetInstructionClock() (GetSystemClock())
|
||||
|
||||
//#define USE_SELF_POWER_SENSE_IO
|
||||
|
@ -322,7 +322,7 @@ typedef int rtccDate;
|
|||
// spi for SD card
|
||||
#define SD_CARD_DET LATFbits.LATF0
|
||||
#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
#define SPI_SD SPI_CHANNEL1
|
||||
#define SPI_SD_BUFF SPI1BUF
|
||||
#define SPI_SD_STAT SPI1STATbits
|
||||
|
|
|
@ -229,17 +229,16 @@ static uint32_t hitag2_crypt(uint64_t x);
|
|||
((S >> (C - 3)) & 8) )
|
||||
|
||||
|
||||
static uint32_t hitag2_crypt(uint64_t s)
|
||||
{
|
||||
static uint32_t hitag2_crypt(uint64_t s) {
|
||||
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
|
||||
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
|
||||
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
uint32_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
|
||||
|
||||
DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex);
|
||||
|
@ -253,13 +252,12 @@ static uint32_t hitag2_crypt(uint64_t s)
|
|||
* uint32_t serialnum - 32 bit tag serial number
|
||||
* uint32_t initvector - 32 bit random IV from reader, part of tag authentication
|
||||
*/
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector)
|
||||
{
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) {
|
||||
// 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
|
||||
initvector ^= (uint32_t) (sharedkey >> 16);
|
||||
initvector ^= (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
|
||||
|
@ -320,9 +318,9 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
// optimise with one 64-bit intermediate
|
||||
uint64_t temp = state ^ (state >> 1);
|
||||
pstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,8 +336,7 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
* Hitag_State* pstate - in/out, internal cipher state after initialisation
|
||||
* uint32_t steps - number of bits requested, (capped at 32)
|
||||
*/
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps)
|
||||
{
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps) {
|
||||
uint64_t state = pstate->shiftreg;
|
||||
uint32_t result = 0;
|
||||
uint64_t lfsr = pstate->lfsr;
|
||||
|
@ -446,7 +443,7 @@ unsigned hitag2_verifytest()
|
|||
const uint64_t key = rev64 (0x524B494D4E4FUL);
|
||||
const uint32_t serial = rev32 (0x69574349);
|
||||
const uint32_t initvec = rev32 (0x72456E65);
|
||||
|
||||
|
||||
uint32_t i;
|
||||
Hitag_State state;
|
||||
|
||||
|
@ -469,11 +466,10 @@ unsigned hitag2_verifytest()
|
|||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned pass = hitag2_verifytest();
|
||||
|
||||
printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
printf("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
|
||||
if (pass) {
|
||||
hitag2_benchtest(10000);
|
||||
|
|
|
@ -159,9 +159,9 @@ typedef struct {
|
|||
uint64_t lfsr; // fast lfsr, used to make software faster
|
||||
} Hitag_State;
|
||||
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps);
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps);
|
||||
|
||||
unsigned int hitag2_benchtest_gen32();
|
||||
unsigned int hitag2_benchtest(uint32_t count);
|
||||
|
|
|
@ -34,11 +34,10 @@ struct threaddata {
|
|||
uint64_t klowerrange;
|
||||
};
|
||||
|
||||
void printbin(uint64_t val)
|
||||
{
|
||||
void printbin(uint64_t val) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<64; i++) {
|
||||
for (i = 0; i < 64; i++) {
|
||||
if (val & 0x8000000000000000) {
|
||||
printf("1");
|
||||
} else {
|
||||
|
@ -48,8 +47,7 @@ void printbin(uint64_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void printstate(Hitag_State *hstate)
|
||||
{
|
||||
void printstate(Hitag_State *hstate) {
|
||||
printf("shiftreg =\t");
|
||||
printbin(hstate->shiftreg);
|
||||
printf("\n");
|
||||
|
@ -70,17 +68,16 @@ void printstate(Hitag_State *hstate)
|
|||
((S >> (C - 3)) & 8) )
|
||||
|
||||
|
||||
static uint32_t hitag2_crypt(uint64_t s)
|
||||
{
|
||||
static uint32_t hitag2_crypt(uint64_t s) {
|
||||
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
|
||||
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
|
||||
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
uint32_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
|
||||
|
||||
return (ht2_function5c >> bitindex) & 1;
|
||||
|
@ -89,17 +86,16 @@ static uint32_t hitag2_crypt(uint64_t s)
|
|||
|
||||
// this function is a modification of the filter function f, based heavily
|
||||
// on the hitag2_crypt function in Rfidler
|
||||
int fnP(uint64_t klowery)
|
||||
{
|
||||
int fnP(uint64_t klowery) {
|
||||
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
|
||||
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
|
||||
const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011
|
||||
uint32_t i;
|
||||
|
||||
i = (ht2_function4a >> pickbits2_2 (klowery, 2, 5)) & 1;
|
||||
i |= ((ht2_function4b << 1) >> pickbits1_1_2 (klowery, 8, 12, 14)) & 0x02;
|
||||
i |= ((ht2_function4b << 2) >> pickbits1x4 (klowery, 17, 21, 23, 26)) & 0x04;
|
||||
i |= ((ht2_function4b << 3) >> pickbits2_1_1 (klowery, 28, 31, 33)) & 0x08;
|
||||
i = (ht2_function4a >> pickbits2_2(klowery, 2, 5)) & 1;
|
||||
i |= ((ht2_function4b << 1) >> pickbits1_1_2(klowery, 8, 12, 14)) & 0x02;
|
||||
i |= ((ht2_function4b << 2) >> pickbits1x4(klowery, 17, 21, 23, 26)) & 0x04;
|
||||
i |= ((ht2_function4b << 3) >> pickbits2_1_1(klowery, 28, 31, 33)) & 0x08;
|
||||
|
||||
// modified to use reference implementation approach
|
||||
// orig fc table is 0x7907287B = 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
|
@ -109,8 +105,7 @@ int fnP(uint64_t klowery)
|
|||
}
|
||||
|
||||
// comparison function for sorting/searching Tklower entries
|
||||
int Tk_cmp(const void *v1, const void *v2)
|
||||
{
|
||||
int Tk_cmp(const void *v1, const void *v2) {
|
||||
const struct Tklower *Tk1 = (struct Tklower *)v1;
|
||||
const struct Tklower *Tk2 = (struct Tklower *)v2;
|
||||
|
||||
|
@ -148,8 +143,7 @@ int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) {
|
|||
}
|
||||
|
||||
// function to test if a partial key is valid
|
||||
int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR)
|
||||
{
|
||||
int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR) {
|
||||
uint64_t kupper;
|
||||
uint64_t key;
|
||||
Hitag_State hstate;
|
||||
|
@ -162,7 +156,7 @@ int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR
|
|||
normaR = ((revaR >> 24) | ((revaR >> 8) & 0xff00) | ((revaR << 8) & 0xff0000) | (revaR << 24));
|
||||
|
||||
// search for remaining 14 bits
|
||||
for (kupper=0; kupper < 0x3fff; kupper++) {
|
||||
for (kupper = 0; kupper < 0x3fff; kupper++) {
|
||||
key = (kupper << 34) | pkey;
|
||||
hitag2_init(&hstate, key, uid, nR);
|
||||
b = hitag2_nstep(&hstate, 32);
|
||||
|
@ -170,7 +164,7 @@ int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR
|
|||
*out = key;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -205,8 +199,7 @@ int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR
|
|||
// effectively work out candidates for the lower 34 bits of the key.
|
||||
|
||||
|
||||
void *crack(void *d)
|
||||
{
|
||||
void *crack(void *d) {
|
||||
struct threaddata *data = (struct threaddata *)d;
|
||||
uint64_t uid;
|
||||
struct nRaR *TnRaR;
|
||||
|
@ -249,11 +242,11 @@ void *crack(void *d)
|
|||
}
|
||||
|
||||
// find keys
|
||||
for (klower=data->klowerstart; klower < (data->klowerstart + data->klowerrange); klower++) {
|
||||
for (klower = data->klowerstart; klower < (data->klowerstart + data->klowerrange); klower++) {
|
||||
printf("trying klower = 0x%05lx\n", klower);
|
||||
// build table
|
||||
count = 0;
|
||||
for (y=0; y<0x40000; y++) {
|
||||
for (y = 0; y < 0x40000; y++) {
|
||||
// create klowery
|
||||
klowery = (y << 16) | klower;
|
||||
// check for cases where right most bit of fc doesn't matter
|
||||
|
@ -268,9 +261,9 @@ void *crack(void *d)
|
|||
// insert y into shiftreg and extract keystream, reversed order
|
||||
b = 0;
|
||||
ytmp = y;
|
||||
for (j=0; j<2; j++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
hstate.shiftreg = hstate.shiftreg | ((ytmp & 0xffff) << 48);
|
||||
for (i=0; i<16; i++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
hstate.shiftreg = hstate.shiftreg >> 1;
|
||||
bit = hitag2_crypt(hstate.shiftreg);
|
||||
b = (b >> 1) | (bit << 31);
|
||||
|
@ -295,11 +288,11 @@ void *crack(void *d)
|
|||
qsort(Tk, count, sizeof(struct Tklower), Tk_cmp);
|
||||
|
||||
// look for matches
|
||||
for (kmiddle=0; kmiddle<0x40000; kmiddle++) {
|
||||
for (kmiddle = 0; kmiddle < 0x40000; kmiddle++) {
|
||||
// loop over nRaR pairs
|
||||
badguess = 0;
|
||||
found = 0;
|
||||
for (i=0; (i<numnrar) && (!badguess); i++) {
|
||||
for (i = 0; (i < numnrar) && (!badguess); i++) {
|
||||
z = kmiddle ^ (TnRaR[i].nR & 0x3ffff);
|
||||
ret = is_kmiddle_badguess(z, Tk, count, TnRaR[i].aR & 0x1);
|
||||
if (ret == 1) {
|
||||
|
@ -314,7 +307,7 @@ void *crack(void *d)
|
|||
printf("possible partial key found: 0x%012lx\n", ((uint64_t)kmiddle << 16) | klower);
|
||||
|
||||
if (testkey(&foundkey, uid, (kmiddle << 16 | klower), TnRaR[0].nR, TnRaR[0].aR) &&
|
||||
testkey(&foundkey, uid, (kmiddle << 16 | klower), TnRaR[1].nR, TnRaR[1].aR)) {
|
||||
testkey(&foundkey, uid, (kmiddle << 16 | klower), TnRaR[1].nR, TnRaR[1].aR)) {
|
||||
// normalise foundkey
|
||||
revkey = rev64(foundkey);
|
||||
foundkey = ((revkey >> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000);
|
||||
|
@ -331,8 +324,7 @@ void *crack(void *d)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *fp;
|
||||
int i;
|
||||
pthread_t threads[NUM_THREADS];
|
||||
|
@ -401,8 +393,8 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
*buft2 = 0x00;
|
||||
if (!strncmp(buf, "0x", 2)) {
|
||||
TnRaR[numnrar].nR = rev32(hexreversetoulong(buf+2));
|
||||
TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1+2));
|
||||
TnRaR[numnrar].nR = rev32(hexreversetoulong(buf + 2));
|
||||
TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1 + 2));
|
||||
} else {
|
||||
TnRaR[numnrar].nR = rev32(hexreversetoulong(buf));
|
||||
TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1));
|
||||
|
@ -423,7 +415,7 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
tdata[i].uid = uid;
|
||||
tdata[i].TnRaR = TnRaR;
|
||||
tdata[i].numnrar = numnrar;
|
||||
|
@ -437,7 +429,7 @@ int main(int argc, char *argv[])
|
|||
crack(tdata);
|
||||
} else {
|
||||
// run full threaded mode
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
if (pthread_create(&(threads[i]), NULL, crack, (void *)(tdata + i))) {
|
||||
printf("cannot start thread %d\n", i);
|
||||
exit(1);
|
||||
|
@ -446,7 +438,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
// wait for threads to finish
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
if (pthread_join(threads[i], &status)) {
|
||||
printf("cannot join thread %d\n", i);
|
||||
exit(1);
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
Hitag_State hstate;
|
||||
FILE *fp;
|
||||
char *line = NULL;
|
||||
|
@ -51,7 +50,7 @@ int main(int argc, char *argv[])
|
|||
ar = strchr(line, ' ');
|
||||
*ar = 0x00;
|
||||
ar++;
|
||||
ar[strlen(ar)-1] = 0x00;
|
||||
ar[strlen(ar) - 1] = 0x00;
|
||||
if (!strncmp(line, "0x", 2)) {
|
||||
nr = line + 2;
|
||||
} else {
|
||||
|
|
|
@ -336,7 +336,7 @@ extern rtccDate RTC_date; // date structure
|
|||
#define TAG_TYPE_AWID_26 17
|
||||
#define TAG_TYPE_EM4X05 18
|
||||
#define TAG_TYPE_TAMAGOTCHI 19
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
|
||||
// various
|
||||
|
||||
|
|
|
@ -142,19 +142,17 @@ rtccTime RTC_time; // time structure
|
|||
rtccDate RTC_date; // date structure
|
||||
|
||||
// convert byte-reversed 8 digit hex to unsigned long
|
||||
unsigned long hexreversetoulong(BYTE *hex)
|
||||
{
|
||||
unsigned long ret= 0L;
|
||||
unsigned long hexreversetoulong(BYTE *hex) {
|
||||
unsigned long ret = 0L;
|
||||
unsigned int x;
|
||||
BYTE i;
|
||||
|
||||
if(strlen(hex) != 8)
|
||||
if (strlen(hex) != 8)
|
||||
return 0L;
|
||||
|
||||
for(i= 0 ; i < 4 ; ++i)
|
||||
{
|
||||
if(sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
for (i = 0 ; i < 4 ; ++i) {
|
||||
if (sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
ret += ((unsigned long) x) << i * 8;
|
||||
hex += 2;
|
||||
}
|
||||
|
@ -162,18 +160,17 @@ unsigned long hexreversetoulong(BYTE *hex)
|
|||
}
|
||||
|
||||
// convert byte-reversed 12 digit hex to unsigned long
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex)
|
||||
{
|
||||
unsigned long long ret= 0LL;
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex) {
|
||||
unsigned long long ret = 0LL;
|
||||
BYTE tmp[9];
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
// breaking direct conversion!
|
||||
|
||||
tmp[8]= '\0';
|
||||
|
||||
tmp[8] = '\0';
|
||||
memset(tmp + 4, '0', 4);
|
||||
memcpy(tmp, hex + 8, 4);
|
||||
ret= hexreversetoulong(tmp);
|
||||
ret = hexreversetoulong(tmp);
|
||||
ret <<= 32;
|
||||
memcpy(tmp, hex, 8);
|
||||
ret += hexreversetoulong(tmp);
|
||||
|
|
|
@ -142,11 +142,11 @@ typedef int rtccDate;
|
|||
|
||||
|
||||
#ifndef __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#define __PIC32MX__
|
||||
#endif
|
||||
|
||||
|
||||
#define GetSystemClock() (80000000ul)
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetPeripheralClock() (GetSystemClock())
|
||||
#define GetInstructionClock() (GetSystemClock())
|
||||
|
||||
//#define USE_SELF_POWER_SENSE_IO
|
||||
|
@ -322,7 +322,7 @@ typedef int rtccDate;
|
|||
// spi for SD card
|
||||
#define SD_CARD_DET LATFbits.LATF0
|
||||
#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
// (held LOW by default - cut solder bridge to GND to free pin if required)
|
||||
#define SPI_SD SPI_CHANNEL1
|
||||
#define SPI_SD_BUFF SPI1BUF
|
||||
#define SPI_SD_STAT SPI1STATbits
|
||||
|
|
|
@ -229,17 +229,16 @@ static uint32_t hitag2_crypt(uint64_t x);
|
|||
((S >> (C - 3)) & 8) )
|
||||
|
||||
|
||||
static uint32_t hitag2_crypt(uint64_t s)
|
||||
{
|
||||
static uint32_t hitag2_crypt(uint64_t s) {
|
||||
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
|
||||
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
|
||||
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
|
||||
uint32_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
|
||||
|
||||
DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex);
|
||||
|
@ -253,13 +252,12 @@ static uint32_t hitag2_crypt(uint64_t s)
|
|||
* uint32_t serialnum - 32 bit tag serial number
|
||||
* uint32_t initvector - 32 bit random IV from reader, part of tag authentication
|
||||
*/
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector)
|
||||
{
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) {
|
||||
// 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
|
||||
initvector ^= (uint32_t) (sharedkey >> 16);
|
||||
initvector ^= (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
|
||||
|
@ -320,9 +318,9 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
// optimise with one 64-bit intermediate
|
||||
uint64_t temp = state ^ (state >> 1);
|
||||
pstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,8 +336,7 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
|
|||
* Hitag_State* pstate - in/out, internal cipher state after initialisation
|
||||
* uint32_t steps - number of bits requested, (capped at 32)
|
||||
*/
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps)
|
||||
{
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps) {
|
||||
uint64_t state = pstate->shiftreg;
|
||||
uint32_t result = 0;
|
||||
uint64_t lfsr = pstate->lfsr;
|
||||
|
@ -446,7 +443,7 @@ unsigned hitag2_verifytest()
|
|||
const uint64_t key = rev64 (0x524B494D4E4FUL);
|
||||
const uint32_t serial = rev32 (0x69574349);
|
||||
const uint32_t initvec = rev32 (0x72456E65);
|
||||
|
||||
|
||||
uint32_t i;
|
||||
Hitag_State state;
|
||||
|
||||
|
@ -469,11 +466,10 @@ unsigned hitag2_verifytest()
|
|||
|
||||
#ifdef UNIT_TEST
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned pass = hitag2_verifytest();
|
||||
|
||||
printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
printf("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL");
|
||||
|
||||
if (pass) {
|
||||
hitag2_benchtest(10000);
|
||||
|
|
|
@ -159,9 +159,9 @@ typedef struct {
|
|||
uint64_t lfsr; // fast lfsr, used to make software faster
|
||||
} Hitag_State;
|
||||
|
||||
void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
void hitag2_init(Hitag_State *pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector);
|
||||
|
||||
uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps);
|
||||
uint32_t hitag2_nstep(Hitag_State *pstate, uint32_t steps);
|
||||
|
||||
unsigned int hitag2_benchtest_gen32();
|
||||
unsigned int hitag2_benchtest(uint32_t count);
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#include "ht2crack2utils.h"
|
||||
|
||||
// writes a value into a buffer as a series of bytes
|
||||
void writebuf(unsigned char *buf, uint64_t val, unsigned int len)
|
||||
{
|
||||
void writebuf(unsigned char *buf, uint64_t val, unsigned int len) {
|
||||
int i;
|
||||
char c;
|
||||
|
||||
for (i=len-1; i>=0; i--)
|
||||
{
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
c = val & 0xff;
|
||||
buf[i] = c;
|
||||
val = val >> 8;
|
||||
|
@ -17,18 +15,17 @@ void writebuf(unsigned char *buf, uint64_t val, unsigned int len)
|
|||
|
||||
|
||||
/* simple hexdump for testing purposes */
|
||||
void shexdump(unsigned char *data, int data_len)
|
||||
{
|
||||
void shexdump(unsigned char *data, int data_len) {
|
||||
int i;
|
||||
|
||||
if (!data || (data_len <= 0)) {
|
||||
printf("shexdump: invalid parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
printf("Hexdump from %p:\n", data);
|
||||
|
||||
for (i=0; i<data_len; i++) {
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if ((i % HEX_PER_ROW) == 0) {
|
||||
printf("\n0x%04x: ", i);
|
||||
}
|
||||
|
@ -39,8 +36,7 @@ void shexdump(unsigned char *data, int data_len)
|
|||
|
||||
|
||||
|
||||
void printbin(unsigned char *c)
|
||||
{
|
||||
void printbin(unsigned char *c) {
|
||||
int i, j;
|
||||
unsigned char x;
|
||||
|
||||
|
@ -49,9 +45,9 @@ void printbin(unsigned char *c)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
for (i = 0; i < 6; i++) {
|
||||
x = c[i];
|
||||
for (j=0; j<8; j++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
printf("%d", (x & 0x80) >> 7);
|
||||
x = x << 1;
|
||||
}
|
||||
|
@ -60,14 +56,13 @@ void printbin(unsigned char *c)
|
|||
}
|
||||
|
||||
|
||||
void printbin2(uint64_t val, unsigned int size)
|
||||
{
|
||||
void printbin2(uint64_t val, unsigned int size) {
|
||||
int i;
|
||||
uint64_t mask = 1;
|
||||
|
||||
mask = mask << (size - 1);
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
if (val & mask) {
|
||||
printf("1");
|
||||
} else {
|
||||
|
@ -78,8 +73,7 @@ void printbin2(uint64_t val, unsigned int size)
|
|||
}
|
||||
|
||||
|
||||
void printstate(Hitag_State *hstate)
|
||||
{
|
||||
void printstate(Hitag_State *hstate) {
|
||||
printf("shiftreg =\t");
|
||||
printbin2(hstate->shiftreg, 48);
|
||||
printf("\n");
|
||||
|
@ -89,8 +83,7 @@ void printstate(Hitag_State *hstate)
|
|||
|
||||
|
||||
// convert hex char to binary
|
||||
unsigned char hex2bin(unsigned char c)
|
||||
{
|
||||
unsigned char hex2bin(unsigned char c) {
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
return (c - '0');
|
||||
} else if ((c >= 'a') && (c <= 'f')) {
|
||||
|
@ -103,8 +96,7 @@ unsigned char hex2bin(unsigned char c)
|
|||
}
|
||||
|
||||
// return a single bit from a value
|
||||
int bitn(uint64_t x, int bit)
|
||||
{
|
||||
int bitn(uint64_t x, int bit) {
|
||||
uint64_t bitmask = 1;
|
||||
|
||||
bitmask = bitmask << bit;
|
||||
|
@ -118,20 +110,18 @@ int bitn(uint64_t x, int bit)
|
|||
|
||||
|
||||
// the sub-function R that rollback depends upon
|
||||
int fnR(uint64_t x)
|
||||
{
|
||||
int fnR(uint64_t x) {
|
||||
// renumbered bits because my state is 0-47, not 1-48
|
||||
return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^
|
||||
bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^
|
||||
bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^
|
||||
bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
}
|
||||
|
||||
// the rollback function that lets us go backwards in time
|
||||
void rollback(Hitag_State *hstate, unsigned int steps)
|
||||
{
|
||||
void rollback(Hitag_State *hstate, unsigned int steps) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<steps; i++) {
|
||||
for (i = 0; i < steps; i++) {
|
||||
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | fnR(hstate->shiftreg);
|
||||
}
|
||||
|
||||
|
@ -139,24 +129,20 @@ void rollback(Hitag_State *hstate, unsigned int steps)
|
|||
|
||||
|
||||
// the three filter sub-functions that feed fnf
|
||||
int fa(unsigned int i)
|
||||
{
|
||||
int fa(unsigned int i) {
|
||||
return bitn(0x2C79, i);
|
||||
}
|
||||
|
||||
int fb(unsigned int i)
|
||||
{
|
||||
int fb(unsigned int i) {
|
||||
return bitn(0x6671, i);
|
||||
}
|
||||
|
||||
int fc(unsigned int i)
|
||||
{
|
||||
int fc(unsigned int i) {
|
||||
return bitn(0x7907287B, i);
|
||||
}
|
||||
|
||||
// the filter function that generates a bit of output from the prng state
|
||||
int fnf(uint64_t s)
|
||||
{
|
||||
int fnf(uint64_t s) {
|
||||
unsigned int x1, x2, x3, x4, x5, x6;
|
||||
|
||||
x1 = (bitn(s, 2) << 0) | (bitn(s, 3) << 1) | (bitn(s, 5) << 2) | (bitn(s, 6) << 3);
|
||||
|
@ -171,16 +157,15 @@ int fnf(uint64_t s)
|
|||
}
|
||||
|
||||
// builds the lfsr for the prng (quick calcs for hitag2_nstep())
|
||||
void buildlfsr(Hitag_State *hstate)
|
||||
{
|
||||
void buildlfsr(Hitag_State *hstate) {
|
||||
uint64_t state = hstate->shiftreg;
|
||||
uint64_t temp;
|
||||
|
||||
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);
|
||||
^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
|
||||
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
|
||||
^ (temp >> 42) ^ (temp >> 46);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -93,8 +93,7 @@ uint64_t uid;
|
|||
int maxtablesize = 800000;
|
||||
uint64_t supplied_testkey = 0;
|
||||
|
||||
void usage()
|
||||
{
|
||||
void usage() {
|
||||
printf("ht2crack4 - K Sheldrake, based on the work of Garcia et al\n\n");
|
||||
printf("Cracks a HiTag2 key using a small number (4 to 16) of encrypted\n");
|
||||
printf("nonce and challenge response pairs, using a fast correlation\n");
|
||||
|
@ -130,46 +129,44 @@ const uint64_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 011
|
|||
* a known least-sig pattern. first index is num bits in known part, second is the
|
||||
* bit pattern of the known part. */
|
||||
double pfna[][8] = {
|
||||
{0.50000, 0.50000, },
|
||||
{0.50000, 0.50000, 0.50000, 0.50000, },
|
||||
{0.50000, 0.00000, 0.50000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, },
|
||||
{0.50000, 0.50000, },
|
||||
{0.50000, 0.50000, 0.50000, 0.50000, },
|
||||
{0.50000, 0.00000, 0.50000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, },
|
||||
};
|
||||
double pfnb[][8] = {
|
||||
{0.62500, 0.37500, },
|
||||
{0.50000, 0.75000, 0.75000, 0.00000, },
|
||||
{0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 1.00000, 1.00000, 0.00000, },
|
||||
{0.62500, 0.37500, },
|
||||
{0.50000, 0.75000, 0.75000, 0.00000, },
|
||||
{0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 1.00000, 1.00000, 0.00000, },
|
||||
};
|
||||
double pfnc[][16] = {
|
||||
{0.50000, 0.50000, },
|
||||
{0.62500, 0.62500, 0.37500, 0.37500, },
|
||||
{0.75000, 0.50000, 0.25000, 0.75000, 0.50000, 0.75000, 0.50000, 0.00000, },
|
||||
{1.00000, 1.00000, 0.50000, 0.50000, 0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, },
|
||||
{0.50000, 0.50000, },
|
||||
{0.62500, 0.62500, 0.37500, 0.37500, },
|
||||
{0.75000, 0.50000, 0.25000, 0.75000, 0.50000, 0.75000, 0.50000, 0.00000, },
|
||||
{1.00000, 1.00000, 0.50000, 0.50000, 0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, },
|
||||
};
|
||||
|
||||
|
||||
/* hitag2_crypt works on the post-shifted form of the lfsr; this is the ref in rfidler code */
|
||||
static uint32_t hitag2_crypt(uint64_t s)
|
||||
{
|
||||
static uint32_t hitag2_crypt(uint64_t s) {
|
||||
uint32_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 7, 11, 13)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
|
||||
|
||||
return (ht2_function5c >> bitindex) & 1;
|
||||
}
|
||||
|
||||
/* ht2crypt works on the pre-shifted form of the lfsr; this is the ref in the paper */
|
||||
uint64_t ht2crypt(uint64_t s)
|
||||
{
|
||||
uint64_t ht2crypt(uint64_t s) {
|
||||
uint64_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> pickbits2_2 (s, 2, 5)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 8, 12, 14)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 17, 21, 23, 26)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 28, 31, 33)) & 0x08;
|
||||
bitindex = (ht2_function4a >> pickbits2_2(s, 2, 5)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(s, 8, 12, 14)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> pickbits1x4(s, 17, 21, 23, 26)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 28, 31, 33)) & 0x08;
|
||||
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 34, 43, 46)) & 0x10;
|
||||
|
||||
return (ht2_function5c >> bitindex) & 1;
|
||||
|
@ -177,11 +174,10 @@ uint64_t ht2crypt(uint64_t s)
|
|||
|
||||
|
||||
/* fnL is the feedback function for the reference code */
|
||||
uint64_t fnL(uint64_t x)
|
||||
{
|
||||
uint64_t fnL(uint64_t x) {
|
||||
return (bitn(x, 0) ^ bitn(x, 2) ^ bitn(x, 3) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 8) ^
|
||||
bitn(x, 16) ^ bitn(x, 22) ^ bitn(x, 23) ^ bitn(x, 26) ^ bitn(x, 30) ^ bitn(x, 41) ^
|
||||
bitn(x, 42) ^ bitn(x, 43) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
bitn(x, 16) ^ bitn(x, 22) ^ bitn(x, 23) ^ bitn(x, 26) ^ bitn(x, 30) ^ bitn(x, 41) ^
|
||||
bitn(x, 42) ^ bitn(x, 43) ^ bitn(x, 46) ^ bitn(x, 47));
|
||||
}
|
||||
|
||||
|
||||
|
@ -189,18 +185,18 @@ uint64_t fnL(uint64_t x)
|
|||
* the number of relevant bits.
|
||||
* e.g. if there are 16 confirmed bits in a state, then packed_size[16] = 8 relevant bits.
|
||||
* this is for pre-shifted lfsr */
|
||||
unsigned int packed_size[] = { 0, 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
|
||||
unsigned int packed_size[] = { 0, 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8,
|
||||
8, 9, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 14, 14, 15,
|
||||
15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 20, 20 };
|
||||
15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 20, 20
|
||||
};
|
||||
|
||||
|
||||
/* f20 is the same as hitag2_crypt except it works on the packed version
|
||||
* of the state where all 20 relevant bits are squashed together */
|
||||
uint64_t f20(uint64_t y)
|
||||
{
|
||||
uint64_t f20(uint64_t y) {
|
||||
uint64_t bitindex;
|
||||
|
||||
bitindex = (ht2_function4a >> (y & 0xf)) & 1;
|
||||
bitindex = (ht2_function4a >> (y & 0xf)) & 1;
|
||||
bitindex |= ((ht2_function4b << 1) >> ((y >> 4) & 0xf)) & 0x02;
|
||||
bitindex |= ((ht2_function4b << 2) >> ((y >> 8) & 0xf)) & 0x04;
|
||||
bitindex |= ((ht2_function4b << 3) >> ((y >> 12) & 0xf)) & 0x08;
|
||||
|
@ -211,14 +207,13 @@ uint64_t f20(uint64_t y)
|
|||
|
||||
|
||||
/* packstate packs the relevant bits from LFSR state into 20 bits for pre-shifted lfsr */
|
||||
uint64_t packstate(uint64_t s)
|
||||
{
|
||||
uint64_t packstate(uint64_t s) {
|
||||
uint64_t packed;
|
||||
|
||||
packed = pickbits2_2 (s, 2, 5);
|
||||
packed |= (pickbits1_1_2 (s, 8, 12, 14) << 4);
|
||||
packed |= (pickbits1x4 (s, 17, 21, 23, 26) << 8);
|
||||
packed |= (pickbits2_1_1 (s, 28, 31, 33) << 12);
|
||||
packed = pickbits2_2(s, 2, 5);
|
||||
packed |= (pickbits1_1_2(s, 8, 12, 14) << 4);
|
||||
packed |= (pickbits1x4(s, 17, 21, 23, 26) << 8);
|
||||
packed |= (pickbits2_1_1(s, 28, 31, 33) << 12);
|
||||
packed |= (pickbits1_2_1(s, 34, 43, 46) << 16);
|
||||
|
||||
return packed;
|
||||
|
@ -226,8 +221,7 @@ uint64_t packstate(uint64_t s)
|
|||
|
||||
|
||||
/* create_guess_table mallocs the tables */
|
||||
void create_guess_table()
|
||||
{
|
||||
void create_guess_table() {
|
||||
guesses = (struct guess *)malloc(sizeof(struct guess) * maxtablesize);
|
||||
if (!guesses) {
|
||||
printf("cannot malloc guess table\n");
|
||||
|
@ -238,8 +232,7 @@ void create_guess_table()
|
|||
|
||||
/* init the guess table by reading in the encrypted nR,aR values and
|
||||
* setting the first 2^16 key guesses */
|
||||
void init_guess_table(char *filename, char *uidstr)
|
||||
{
|
||||
void init_guess_table(char *filename, char *uidstr) {
|
||||
unsigned int i, j;
|
||||
FILE *fp;
|
||||
char *buf = NULL;
|
||||
|
@ -289,8 +282,8 @@ void init_guess_table(char *filename, char *uidstr)
|
|||
}
|
||||
*buft2 = 0x00;
|
||||
if (!strncmp(buf, "0x", 2)) {
|
||||
nonces[num_nRaR].enc_nR = rev32(hexreversetoulong(buf+2));
|
||||
nonces[num_nRaR].ks = rev32(hexreversetoulong(buft1+2)) ^ 0xffffffff;
|
||||
nonces[num_nRaR].enc_nR = rev32(hexreversetoulong(buf + 2));
|
||||
nonces[num_nRaR].ks = rev32(hexreversetoulong(buft1 + 2)) ^ 0xffffffff;
|
||||
} else {
|
||||
nonces[num_nRaR].enc_nR = rev32(hexreversetoulong(buf));
|
||||
nonces[num_nRaR].ks = rev32(hexreversetoulong(buft1)) ^ 0xffffffff;
|
||||
|
@ -303,12 +296,12 @@ void init_guess_table(char *filename, char *uidstr)
|
|||
|
||||
fprintf(stderr, "Loaded %d nRaR pairs\n", num_nRaR);
|
||||
|
||||
// set key and copy in enc_nR and ks values
|
||||
// set key and copy in enc_nR and ks values
|
||||
// set score to -1.0 to distinguish them from 0 scores
|
||||
for (i=0; i<65536; i++) {
|
||||
for (i = 0; i < 65536; i++) {
|
||||
guesses[i].key = i;
|
||||
guesses[i].score = -1.0;
|
||||
for (j=0; j<num_nRaR; j++) {
|
||||
for (j = 0; j < num_nRaR; j++) {
|
||||
guesses[i].b0to31[j] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -320,8 +313,7 @@ void init_guess_table(char *filename, char *uidstr)
|
|||
/* bit_score calculates the ratio of partial states that could generate
|
||||
* the resulting bit b to all possible states
|
||||
* size is the number of confirmed bits in the state */
|
||||
double bit_score(uint64_t s, uint64_t size, uint64_t b)
|
||||
{
|
||||
double bit_score(uint64_t s, uint64_t size, uint64_t b) {
|
||||
uint64_t packed;
|
||||
uint64_t chopped;
|
||||
unsigned int n;
|
||||
|
@ -353,14 +345,14 @@ double bit_score(uint64_t s, uint64_t size, uint64_t b)
|
|||
// incomplete first nibble
|
||||
// get probability of getting a 1 from first nibble
|
||||
// and by subtraction from 1, prob of getting a 0
|
||||
nibprob1 = pfna[n-1][packed];
|
||||
nibprob1 = pfna[n - 1][packed];
|
||||
nibprob0 = 1.0 - nibprob1;
|
||||
|
||||
// calc fnc prob as sum of probs of nib 1 producing a 1 and 0
|
||||
prob = (nibprob0 * pfnc[0][0]) + (nibprob1 * pfnc[0][1]);
|
||||
} else if (n < 20) {
|
||||
// calculate the fnc input first, then we'll fix it
|
||||
fncinput = (ht2_function4a >> (packed & 0xf)) & 1;
|
||||
fncinput = (ht2_function4a >> (packed & 0xf)) & 1;
|
||||
fncinput |= ((ht2_function4b << 1) >> ((packed >> 4) & 0xf)) & 0x02;
|
||||
fncinput |= ((ht2_function4b << 2) >> ((packed >> 8) & 0xf)) & 0x04;
|
||||
fncinput |= ((ht2_function4b << 3) >> ((packed >> 12) & 0xf)) & 0x08;
|
||||
|
@ -404,8 +396,7 @@ double bit_score(uint64_t s, uint64_t size, uint64_t b)
|
|||
* bit_scores together until no bits remain. bit_scores are
|
||||
* multiplied by the number of relevant bits in the scored state
|
||||
* to give weight to more complete states. */
|
||||
double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize)
|
||||
{
|
||||
double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize) {
|
||||
double sc, sc2;
|
||||
|
||||
if ((size == 1) || (kssize == 1)) {
|
||||
|
@ -436,8 +427,7 @@ double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize)
|
|||
|
||||
|
||||
/* score_traces runs score for each encrypted nonce */
|
||||
void score_traces(struct guess *g, unsigned int size)
|
||||
{
|
||||
void score_traces(struct guess *g, unsigned int size) {
|
||||
uint64_t lfsr;
|
||||
unsigned int i;
|
||||
double sc;
|
||||
|
@ -448,13 +438,13 @@ void score_traces(struct guess *g, unsigned int size)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<num_nRaR; i++) {
|
||||
for (i = 0; i < num_nRaR; i++) {
|
||||
// calc next b
|
||||
// create lfsr - lower 32 bits is uid, upper 16 bits are lower 16 bits of key
|
||||
// then shift by size - 16, insert upper key XOR enc_nonce XOR bitstream,
|
||||
// and calc new bit b
|
||||
lfsr = (uid >> (size - 16)) | ((g->key << (48 - size)) ^
|
||||
((nonces[i].enc_nR ^ g->b0to31[i]) << (64 - size)));
|
||||
((nonces[i].enc_nR ^ g->b0to31[i]) << (64 - size)));
|
||||
g->b0to31[i] = g->b0to31[i] | (ht2crypt(lfsr) << (size - 16));
|
||||
|
||||
// create lfsr - lower 16 bits are lower 16 bits of key
|
||||
|
@ -491,12 +481,11 @@ void score_all_traces(unsigned int size)
|
|||
*/
|
||||
|
||||
/* score_some_traces runs score_traces for every key guess in a section of the table */
|
||||
void *score_some_traces(void *data)
|
||||
{
|
||||
void *score_some_traces(void *data) {
|
||||
unsigned int i;
|
||||
struct thread_data *tdata = (struct thread_data *)data;
|
||||
|
||||
for (i=tdata->start; i<tdata->end; i++) {
|
||||
for (i = tdata->start; i < tdata->end; i++) {
|
||||
score_traces(&(guesses[i]), tdata->size);
|
||||
}
|
||||
|
||||
|
@ -505,8 +494,7 @@ void *score_some_traces(void *data)
|
|||
|
||||
|
||||
/* score_all_traces runs score_traces for every key guess in the table */
|
||||
void score_all_traces(unsigned int size)
|
||||
{
|
||||
void score_all_traces(unsigned int size) {
|
||||
pthread_t threads[NUM_THREADS];
|
||||
void *status;
|
||||
struct thread_data tdata[NUM_THREADS];
|
||||
|
@ -516,9 +504,9 @@ void score_all_traces(unsigned int size)
|
|||
chunk_size = num_guesses / NUM_THREADS;
|
||||
|
||||
// create thread data
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
tdata[i].start = i * chunk_size;
|
||||
tdata[i].end = (i+1) * chunk_size;
|
||||
tdata[i].end = (i + 1) * chunk_size;
|
||||
tdata[i].size = size;
|
||||
}
|
||||
|
||||
|
@ -526,7 +514,7 @@ void score_all_traces(unsigned int size)
|
|||
tdata[NUM_THREADS - 1].end = num_guesses;
|
||||
|
||||
// start the threads
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
if (pthread_create(&(threads[i]), NULL, score_some_traces, (void *)(tdata + i))) {
|
||||
printf("cannot start thread %d\n", i);
|
||||
exit(1);
|
||||
|
@ -534,7 +522,7 @@ void score_all_traces(unsigned int size)
|
|||
}
|
||||
|
||||
// wait for threads to end
|
||||
for (i=0; i<NUM_THREADS; i++) {
|
||||
for (i = 0; i < NUM_THREADS; i++) {
|
||||
if (pthread_join(threads[i], &status)) {
|
||||
printf("cannot join thread %d\n", i);
|
||||
exit(1);
|
||||
|
@ -547,8 +535,7 @@ void score_all_traces(unsigned int size)
|
|||
|
||||
|
||||
/* cmp_guess is the comparison function for qsorting the guess table */
|
||||
int cmp_guess(const void *a, const void *b)
|
||||
{
|
||||
int cmp_guess(const void *a, const void *b) {
|
||||
struct guess *a1 = (struct guess *)a;
|
||||
struct guess *b1 = (struct guess *)b;
|
||||
|
||||
|
@ -565,15 +552,14 @@ int cmp_guess(const void *a, const void *b)
|
|||
/* expand all guesses in first half of (sorted) table by
|
||||
* copying them into the second half and extending the copied
|
||||
* ones with an extra 1, leaving the first half with an extra 0 */
|
||||
void expand_guesses(unsigned int halfsize, unsigned int size)
|
||||
{
|
||||
void expand_guesses(unsigned int halfsize, unsigned int size) {
|
||||
unsigned int i, j;
|
||||
|
||||
for (i=0; i<halfsize; i++) {
|
||||
guesses[i+halfsize].key = guesses[i].key | (1l << size);
|
||||
guesses[i+halfsize].score = guesses[i].score;
|
||||
for (j=0; j<num_nRaR; j++) {
|
||||
guesses[i+halfsize].b0to31[j] = guesses[i].b0to31[j];
|
||||
for (i = 0; i < halfsize; i++) {
|
||||
guesses[i + halfsize].key = guesses[i].key | (1l << size);
|
||||
guesses[i + halfsize].score = guesses[i].score;
|
||||
for (j = 0; j < num_nRaR; j++) {
|
||||
guesses[i + halfsize].b0to31[j] = guesses[i].b0to31[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -581,14 +567,13 @@ void expand_guesses(unsigned int halfsize, unsigned int size)
|
|||
|
||||
/* checks if the supplied test key is still in the table, which
|
||||
* is useful when testing different scoring methods */
|
||||
void check_supplied_testkey(unsigned int size)
|
||||
{
|
||||
void check_supplied_testkey(unsigned int size) {
|
||||
uint64_t partkey;
|
||||
unsigned int i;
|
||||
|
||||
partkey = supplied_testkey & ((1l << size) - 1);
|
||||
|
||||
for (i=0; i<num_guesses; i++) {
|
||||
for (i = 0; i < num_guesses; i++) {
|
||||
if (guesses[i].key == partkey) {
|
||||
fprintf(stderr, " supplied test key score = %1.10f, position = %d\n", guesses[i].score, i);
|
||||
return;
|
||||
|
@ -601,8 +586,7 @@ void check_supplied_testkey(unsigned int size)
|
|||
|
||||
|
||||
/* execute_round scores the guesses, sorts them and expands the good half */
|
||||
void execute_round(unsigned int size)
|
||||
{
|
||||
void execute_round(unsigned int size) {
|
||||
unsigned int halfsize;
|
||||
|
||||
// score all the current guesses
|
||||
|
@ -630,14 +614,13 @@ void execute_round(unsigned int size)
|
|||
|
||||
|
||||
/* crack is the main cracking algo; it executes the rounds */
|
||||
void crack()
|
||||
{
|
||||
void crack() {
|
||||
unsigned int i;
|
||||
uint64_t revkey;
|
||||
uint64_t foundkey;
|
||||
|
||||
for (i=16; i<=48; i++) {
|
||||
fprintf(stderr, "round %2d, size=%2d\n", i-16, i);
|
||||
for (i = 16; i <= 48; i++) {
|
||||
fprintf(stderr, "round %2d, size=%2d\n", i - 16, i);
|
||||
execute_round(i);
|
||||
|
||||
// print some metrics
|
||||
|
@ -649,8 +632,7 @@ void crack()
|
|||
|
||||
|
||||
/* test function to make sure I know how the LFSR works */
|
||||
void testkey(uint64_t key)
|
||||
{
|
||||
void testkey(uint64_t key) {
|
||||
uint64_t i;
|
||||
uint64_t b0to31 = 0;
|
||||
uint64_t ks = 0;
|
||||
|
@ -663,7 +645,7 @@ void testkey(uint64_t key)
|
|||
printf("after init with key, uid, nR:\n");
|
||||
printstate(&hstate);
|
||||
b0to31 = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
b0to31 = (b0to31 >> 1) | (hitag2_nstep(&hstate, 1) << 31);
|
||||
}
|
||||
printf("ks = 0x%08" PRIx64 ", enc_aR = 0x%08" PRIx64 ", aR = 0x%08" PRIx64 "\n", b0to31, nonces[0].ks ^ 0xffffffff, nonces[0].ks ^ 0xffffffff ^ b0to31);
|
||||
|
@ -679,7 +661,7 @@ void testkey(uint64_t key)
|
|||
// xor upper part of key with encrypted nonce
|
||||
nRxorkey = nonces[0].enc_nR ^ (key >> 16);
|
||||
// insert keyupper xor encrypted nonce xor ks
|
||||
for (i=0; i<32; i++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
b0to31 = (b0to31 >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
|
@ -693,7 +675,7 @@ void testkey(uint64_t key)
|
|||
printf("\n");
|
||||
|
||||
// iterate lfsr with fnL, extracting ks
|
||||
for (i=0; i<32; i++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
ks = (ks >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
|
@ -710,38 +692,37 @@ void testkey(uint64_t key)
|
|||
|
||||
|
||||
/* test function to generate test data */
|
||||
void gen_bitstreams_testks(struct guess *g, uint64_t key)
|
||||
{
|
||||
unsigned int i, j;
|
||||
uint64_t nRxorkey, lfsr, ks;
|
||||
void gen_bitstreams_testks(struct guess *g, uint64_t key) {
|
||||
unsigned int i, j;
|
||||
uint64_t nRxorkey, lfsr, ks;
|
||||
|
||||
for (j=0; j<num_nRaR; j++) {
|
||||
for (j = 0; j < num_nRaR; j++) {
|
||||
|
||||
// build initial lfsr
|
||||
lfsr = uid | ((key & 0xffff) << 32);
|
||||
g->b0to31[j] = 0;
|
||||
// xor upper part of key with encrypted nonce
|
||||
nRxorkey = nonces[j].enc_nR ^ (key >> 16);
|
||||
// insert keyupper xor encrypted nonce xor ks
|
||||
for (i=0; i<32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
g->b0to31[j] = (g->b0to31[j] >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
lfsr = lfsr | ((((nRxorkey >> i) & 0x1) ^ ((g->b0to31[j] >> 31) & 0x1)) << 48);
|
||||
// shift lfsr
|
||||
lfsr = lfsr >> 1;
|
||||
}
|
||||
// build initial lfsr
|
||||
lfsr = uid | ((key & 0xffff) << 32);
|
||||
g->b0to31[j] = 0;
|
||||
// xor upper part of key with encrypted nonce
|
||||
nRxorkey = nonces[j].enc_nR ^ (key >> 16);
|
||||
// insert keyupper xor encrypted nonce xor ks
|
||||
for (i = 0; i < 32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
g->b0to31[j] = (g->b0to31[j] >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
lfsr = lfsr | ((((nRxorkey >> i) & 0x1) ^ ((g->b0to31[j] >> 31) & 0x1)) << 48);
|
||||
// shift lfsr
|
||||
lfsr = lfsr >> 1;
|
||||
}
|
||||
|
||||
ks = 0;
|
||||
// iterate lfsr with fnL, extracting ks
|
||||
for (i=0; i<32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
ks = (ks >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
lfsr = lfsr | (fnL(lfsr) << 48);
|
||||
// shift lfsr
|
||||
lfsr = lfsr >> 1;
|
||||
}
|
||||
// iterate lfsr with fnL, extracting ks
|
||||
for (i = 0; i < 32; i++) {
|
||||
// store ks - when done, the first ks bit will be bit 0 and the last will be bit 31
|
||||
ks = (ks >> 1) | (ht2crypt(lfsr) << 31);
|
||||
// insert new bit
|
||||
lfsr = lfsr | (fnL(lfsr) << 48);
|
||||
// shift lfsr
|
||||
lfsr = lfsr >> 1;
|
||||
}
|
||||
|
||||
printf("orig ks = 0x%08" PRIx64 ", gen ks = 0x%08" PRIx64 ", b0to31 = 0x%08" PRIx64 "\n", nonces[j].ks, ks, g->b0to31[j]);
|
||||
if (nonces[j].ks != ks) {
|
||||
|
@ -752,15 +733,14 @@ void gen_bitstreams_testks(struct guess *g, uint64_t key)
|
|||
|
||||
|
||||
/* test function */
|
||||
void test()
|
||||
{
|
||||
void test() {
|
||||
uint64_t lfsr;
|
||||
uint64_t packed;
|
||||
|
||||
uint64_t i;
|
||||
|
||||
|
||||
for (i=0; i<1000; i++) {
|
||||
for (i = 0; i < 1000; i++) {
|
||||
lfsr = ((uint64_t)rand() << 32) | rand();
|
||||
packed = packstate(lfsr);
|
||||
|
||||
|
@ -774,15 +754,14 @@ void test()
|
|||
|
||||
|
||||
/* check_key tests the potential key against an encrypted nonce, ks pair */
|
||||
int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks)
|
||||
{
|
||||
int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks) {
|
||||
Hitag_State hstate;
|
||||
uint64_t bits;
|
||||
int i;
|
||||
|
||||
hitag2_init(&hstate, key, uid, enc_nR);
|
||||
bits = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
bits = (bits >> 1) | (hitag2_nstep(&hstate, 1) << 31);
|
||||
}
|
||||
if (ks == bits) {
|
||||
|
@ -794,8 +773,7 @@ int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks)
|
|||
|
||||
|
||||
/* start up */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned int i;
|
||||
uint64_t revkey;
|
||||
uint64_t foundkey;
|
||||
|
@ -808,7 +786,7 @@ int main(int argc, char *argv[])
|
|||
// exit(0);
|
||||
|
||||
while ((c = getopt(argc, argv, "u:n:N:t:T:h")) != -1) {
|
||||
switch(c) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
uidstr = optarg;
|
||||
break;
|
||||
|
@ -848,7 +826,7 @@ int main(int argc, char *argv[])
|
|||
crack();
|
||||
|
||||
// test all key guesses and stop if one works
|
||||
for (i=0; i<num_guesses; i++) {
|
||||
for (i = 0; i < num_guesses; i++) {
|
||||
if (check_key(guesses[i].key, nonces[0].enc_nR, nonces[0].ks) &&
|
||||
check_key(guesses[i].key, nonces[1].enc_nR, nonces[1].ks)) {
|
||||
printf("WIN!!! :)\n");
|
||||
|
|
|
@ -336,7 +336,7 @@ extern rtccDate RTC_date; // date structure
|
|||
#define TAG_TYPE_AWID_26 17
|
||||
#define TAG_TYPE_EM4X05 18
|
||||
#define TAG_TYPE_TAMAGOTCHI 19
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram
|
||||
|
||||
// various
|
||||
|
||||
|
|
|
@ -142,19 +142,17 @@ rtccTime RTC_time; // time structure
|
|||
rtccDate RTC_date; // date structure
|
||||
|
||||
// convert byte-reversed 8 digit hex to unsigned long
|
||||
unsigned long hexreversetoulong(BYTE *hex)
|
||||
{
|
||||
unsigned long ret= 0L;
|
||||
unsigned long hexreversetoulong(BYTE *hex) {
|
||||
unsigned long ret = 0L;
|
||||
unsigned int x;
|
||||
BYTE i;
|
||||
|
||||
if(strlen(hex) != 8)
|
||||
if (strlen(hex) != 8)
|
||||
return 0L;
|
||||
|
||||
for(i= 0 ; i < 4 ; ++i)
|
||||
{
|
||||
if(sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
for (i = 0 ; i < 4 ; ++i) {
|
||||
if (sscanf(hex, "%2X", &x) != 1)
|
||||
return 0L;
|
||||
ret += ((unsigned long) x) << i * 8;
|
||||
hex += 2;
|
||||
}
|
||||
|
@ -162,18 +160,17 @@ unsigned long hexreversetoulong(BYTE *hex)
|
|||
}
|
||||
|
||||
// convert byte-reversed 12 digit hex to unsigned long
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex)
|
||||
{
|
||||
unsigned long long ret= 0LL;
|
||||
unsigned long long hexreversetoulonglong(BYTE *hex) {
|
||||
unsigned long long ret = 0LL;
|
||||
BYTE tmp[9];
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
|
||||
// this may seem an odd way to do it, but weird compiler issues were
|
||||
// breaking direct conversion!
|
||||
|
||||
tmp[8]= '\0';
|
||||
|
||||
tmp[8] = '\0';
|
||||
memset(tmp + 4, '0', 4);
|
||||
memcpy(tmp, hex + 8, 4);
|
||||
ret= hexreversetoulong(tmp);
|
||||
ret = hexreversetoulong(tmp);
|
||||
ret <<= 32;
|
||||
memcpy(tmp, hex, 8);
|
||||
ret += hexreversetoulong(tmp);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue