Merge branch 'master' into lf_emul

This commit is contained in:
Artem Gnatyuk 2020-03-21 23:47:09 +07:00
commit 3fb4045c16
107 changed files with 4902 additions and 2157 deletions

View file

@ -3,6 +3,18 @@ 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... 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] ## [unreleased][unreleased]
- Fix 'hf mfdes enum' - now actually manages to enumerate files under all AID's. :smiley: (@iceman1001)
- Fix 'hf mfdes info' - now detects DESFire light and work properly Wrapped commands :+1: (@iceman1001)
- :smiling_imp: support (@doegox)
- Additional colour changes as recommended by @iceman (@dunderhay)
- Change type colour for `hf 14a` card types (@dunderhay)
- Add colour to `hf mfdes` command (@dunderhay)
- Add 'HINTS' command. Will turn off / on hint messages. Default mode is OFF. (@iceman1001)
- Add colour to `hf 14a` and `hf mfu` commands (@dunderhay)
- Add colour to `lf hid` commands (@dunderhay)
- 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 - hint texts added to all lf clone commands (@iceman1001)
- Change `lf keri demod` - adjusted the internal id. (@mwalker33) - Change `lf keri demod` - adjusted the internal id. (@mwalker33)
- Added seamless integration with cryptohelper (@iceman1001) - Added seamless integration with cryptohelper (@iceman1001)
@ -35,7 +47,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) - 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 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 `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) - Fix `hf mf nested` - now writes the correct blockno (@iceman1001)
- Change `lf t55xx dump` - now supports saving to JSON (@iceman1001) - Change `lf t55xx dump` - now supports saving to JSON (@iceman1001)
- Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi) - Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi)
@ -431,6 +443,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk) - Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
- Added `script run luxeodump` (@0xdrrb) - Added `script run luxeodump` (@0xdrrb)
- Fix `lf hitag reader 02` - print all bytes (@bosb) - Fix `lf hitag reader 02` - print all bytes (@bosb)
- Fix hitag S simulation (still not working), write, add example HITAG S 256 (@bosb)
### Fixed ### Fixed
@ -605,8 +618,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) - 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 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 - 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 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 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) 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 script `legic.lua` for display and edit Data of Legic-Prime Tags (@icsom)
- Added the experimental HITAG_S support (@spenneb) - Added the experimental HITAG_S support (@spenneb)

View file

@ -24,7 +24,7 @@ init:
Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename" Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename"
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) # iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
clone_script: clone_script:
- ps: >- - ps: >-
Write-Host "Removing ProxSpace..." -NoNewLine Write-Host "Removing ProxSpace..." -NoNewLine
@ -409,4 +409,4 @@ on_success:
on_failure: on_failure:
- ps: Write-Host "Build error." -ForegroundColor Red - ps: Write-Host "Build error." -ForegroundColor Red
on_finish: on_finish:
- ps: $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - ps: # $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View file

@ -45,7 +45,7 @@
* This module emits debug strings during normal operation -- so try it out in * 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. * 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: * Caveats / notes:
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash * - Trace buffer will be cleared on starting stand-alone mode. Data in flash
@ -97,7 +97,7 @@ void RunMod() {
if (trace_len > 0) { if (trace_len > 0) {
Dbprintf("[!] Trace length (bytes) = %u", trace_len); 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)) { if (!exists_in_spiffs(HF_14ASNIFF_LOGFILE)) {
rdv40_spiffs_write( rdv40_spiffs_write(
HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE); HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
@ -117,7 +117,7 @@ void RunMod() {
SpinErr(LED_A, 200, 5); SpinErr(LED_A, 200, 5);
SpinDelay(100); SpinDelay(100);
LEDsoff(); LEDsoff();
SpinDelay(300); SpinDelay(300);
DownloadTraceInstructions(); DownloadTraceInstructions();

View file

@ -7,6 +7,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// main code for HID collector aka IceHID by Iceman // main code for HID collector aka IceHID by Iceman
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <inttypes.h>
#include "standalone.h" // standalone definitions #include "standalone.h" // standalone definitions
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#include "appmain.h" #include "appmain.h"
@ -63,7 +64,7 @@ void DownloadLogInstructions() {
bool log_exists; bool log_exists;
void append(uint8_t* entry, size_t entry_len) { void append(uint8_t *entry, size_t entry_len) {
LED_B_ON(); LED_B_ON();
if (log_exists == false) { if (log_exists == false) {
@ -105,23 +106,23 @@ uint32_t IceEM410xdemod() {
memset(entry, 0, sizeof(entry)); memset(entry, 0, sizeof(entry));
if (size == 128) { if (size == 128) {
sprintf((char *)entry, "EM XL TAG ID: %06lx%08lx%08lx - (%05ld_%03ld_%08ld)\n", sprintf((char *)entry, "EM XL TAG ID: %06"PRIx32"%08"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n",
hi, hi,
(uint32_t)(lo >> 32), (uint32_t)(lo >> 32),
(uint32_t)lo, (uint32_t)lo,
(uint32_t)(lo & 0xFFFF), (uint32_t)(lo & 0xFFFF),
(uint32_t)((lo >> 16LL) & 0xFF), (uint32_t)((lo >> 16LL) & 0xFF),
(uint32_t)(lo & 0xFFFFFF)); (uint32_t)(lo & 0xFFFFFF));
} else { } else {
sprintf((char *)entry, "EM TAG ID: %02lx%08lx - (%05ld_%03ld_%08ld)\n", sprintf((char *)entry, "EM TAG ID: %02"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n",
(uint32_t)(lo >> 32), (uint32_t)(lo >> 32),
(uint32_t)lo, (uint32_t)lo,
(uint32_t)(lo & 0xFFFF), (uint32_t)(lo & 0xFFFF),
(uint32_t)((lo >> 16LL) & 0xFF), (uint32_t)((lo >> 16LL) & 0xFF),
(uint32_t)(lo & 0xFFFFFF)); (uint32_t)(lo & 0xFFFFFF));
} }
append(entry, strlen((char*)entry)); append(entry, strlen((char *)entry));
Dbprintf("%s", entry); Dbprintf("%s", entry);
BigBuf_free(); BigBuf_free();
return PM3_SUCCESS; return PM3_SUCCESS;
@ -160,20 +161,20 @@ uint32_t IceAWIDdemod() {
uint8_t fac = bytebits_to_byte(dest + 9, 8); uint8_t fac = bytebits_to_byte(dest + 9, 8);
uint32_t cardnum = bytebits_to_byte(dest + 17, 16); uint32_t cardnum = bytebits_to_byte(dest + 17, 16);
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen);
sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo); sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo);
} else { } else {
uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16); uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16);
if (fmtLen > 32) { if (fmtLen > 32) {
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32); uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32);
uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32); uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32);
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx%08lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32"%08"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
} else { } else {
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen);
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
} }
} }
append(entry, strlen((char*)entry)); append(entry, strlen((char *)entry));
Dbprintf("%s", entry); Dbprintf("%s", entry);
BigBuf_free(); BigBuf_free();
return PM3_SUCCESS; return PM3_SUCCESS;
@ -209,15 +210,15 @@ uint32_t IceIOdemod() {
uint8_t entry[64]; uint8_t entry[64];
memset(entry, 0, sizeof(entry)); memset(entry, 0, sizeof(entry));
sprintf((char *)entry, "IO Prox XSF(%02d)%02x:%05d (%08lx%08lx)\n" sprintf((char *)entry, "IO Prox XSF(%02u)%02x:%05u (%08"PRIx32"%08"PRIx32")\n"
, version , version
, facilitycode , facilitycode
, number , number
, hi , hi
, lo , lo
); );
append(entry, strlen((char*)entry)); append(entry, strlen((char *)entry));
Dbprintf("%s", entry); Dbprintf("%s", entry);
BigBuf_free(); BigBuf_free();
return PM3_SUCCESS; return PM3_SUCCESS;
@ -249,14 +250,14 @@ uint32_t IceHIDDemod() {
// go over previously decoded manchester data and decode into usable tag ID // go over previously decoded manchester data and decode into usable tag ID
if (hi2 != 0) { //extra large HID tags 88/192 bits if (hi2 != 0) { //extra large HID tags 88/192 bits
sprintf((char *)entry, "HID large: %lx%08lx%08lx (%ld)\n", sprintf((char *)entry, "HID large: %"PRIx32"%08"PRIx32"%08"PRIx32" (%"PRIu32")\n",
hi2, hi2,
hi, hi,
lo, lo,
(lo >> 1) & 0xFFFF (lo >> 1) & 0xFFFF
); );
append(entry, strlen((char*)entry)); append(entry, strlen((char *)entry));
} else { //standard HID tags 44/96 bits } else { //standard HID tags 44/96 bits
uint8_t bitlen = 0; uint8_t bitlen = 0;
@ -296,16 +297,16 @@ uint32_t IceHIDDemod() {
fac = ((hi & 0xF) << 12) | (lo >> 20); fac = ((hi & 0xF) << 12) | (lo >> 20);
} }
sprintf((char *)entry, "HID: %lx%08lx (%ld) Format: %d bit FC: %ld Card: %ld\n", sprintf((char *)entry, "HID: %"PRIx32"%08"PRIx32" (%"PRIu32") Format: %d bit FC: %"PRIu32" Card: %"PRIu32"\n",
hi, hi,
lo, lo,
(lo >> 1) & 0xFFFF, (lo >> 1) & 0xFFFF,
bitlen, bitlen,
fac, fac,
cardnum cardnum
); );
append(entry, strlen((char*)entry)); append(entry, strlen((char *)entry));
} }
Dbprintf("%s", entry); Dbprintf("%s", entry);
@ -349,7 +350,7 @@ void RunMod() {
uint32_t res; 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); DoAcquisition_config(false, 28000);
res = IceHIDDemod(); res = IceHIDDemod();
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {

View file

@ -42,6 +42,7 @@
#include "Standalone/standalone.h" #include "Standalone/standalone.h"
#include "util.h" #include "util.h"
#include "ticks.h" #include "ticks.h"
#include "commonutil.h"
#ifdef WITH_LCD #ifdef WITH_LCD
#include "LCD.h" #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. // 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); hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40);
#else #else
hf_av = hf_max = AvgAdc(ADC_CHAN_HF); hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
#endif #endif
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10); Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
hf_baseline = hf_av; hf_baseline = hf_av;
@ -1247,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) {
// SniffMifare(packet->oldarg[0]); // SniffMifare(packet->oldarg[0]);
// break; // 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: { case CMD_HF_MIFARE_SETMOD: {
MifareSetMod(packet->data.asBytes); MifareSetMod(packet->data.asBytes);
break; break;

View file

@ -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? // 0 = collision?
// 32 = good response // 32 = good response
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) { bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
@ -544,7 +544,7 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t
// will receive 32-bit configuration page // will receive 32-bit configuration page
} else if (bSelecting) { } else if (bSelecting) {
// Initiate auth // Initiate auth
tx[0] = 0xa0 | key_no >> 4; // WRCPAGE tx[0] = 0xa0 | (key_no); // WRCPAGE
tx[1] = blocknr << 4; tx[1] = blocknr << 4;
crc = hitag_crc(tx, 12); crc = hitag_crc(tx, 12);
tx[1] |= crc >> 4; tx[1] |= crc >> 4;
@ -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); Dbhexdump(4, logdata_1, false);
bSuccessful = true; bSuccessful = true;
return false; return false;
/* /*
// read next page of card until done // read next page of card until done
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
tx[1] = blocknr << 4; tx[1] = blocknr << 4;
crc = hitag_crc(tx, 12); crc = hitag_crc(tx, 12);
tx[1] |= crc >> 4; tx[1] |= crc >> 4;
tx[2] = crc << 4; tx[2] = crc << 4;
*txlen = 20; *txlen = 20;
*/ */
} }
} }
break; break;
@ -1091,7 +1091,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
uint32_t block = 0; uint32_t block = 0;
for (size_t i = 0; i < 12; i++) { for (size_t i = 0; i < 12; i++) {
// num2bytes? // num2bytes?
for (size_t j = 0; j < 4; j++) { for (size_t j = 0; j < 4; j++) {
block <<= 8; block <<= 8;
block |= tag.sectors[i][j]; block |= tag.sectors[i][j];
@ -1105,30 +1105,30 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
size_t nrzs = 0, periods = 0; size_t nrzs = 0, periods = 0;
// uint32_t command_start = 0, command_duration = 0; // uint32_t command_start = 0, command_duration = 0;
// int16_t checked = 0; // int16_t checked = 0;
// SIMULATE // SIMULATE
while (!BUTTON_PRESS()) { while (!BUTTON_PRESS()) {
LED_D_ON(); LED_D_ON();
// lf_reset_counter(); // lf_reset_counter();
LED_A_OFF(); LED_A_OFF();
WDT_HIT(); WDT_HIT();
/* /*
// only every 1000th times, in order to save time when collecting samples. // only every 1000th times, in order to save time when collecting samples.
if (checked == 100) { if (checked == 100) {
if (data_available()) { if (data_available()) {
checked = -1; checked = -1;
break; break;
} else { } else {
checked = 0; checked = 0;
} }
} }
++checked; ++checked;
*/ */
rxlen = 0; rxlen = 0;
@ -1220,8 +1220,8 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
if (nrzs < 5) { if (nrzs < 5) {
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
continue; continue;
} else { } else {
for (size_t i = 0; i < 5; i++){ for (size_t i = 0; i < 5; i++) {
if (nrz_samples[i] != 1) { if (nrz_samples[i] != 1) {
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one", i); 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 // 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]; uint8_t bit = nrz_samples[i];
rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
rxlen++; rxlen++;
@ -1401,7 +1401,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
// hitagS settings // hitagS settings
t_wait_1 = 204; t_wait_1 = 204;
t_wait_2 = 128; t_wait_2 = 128;
/*tag_size = 256;*/
flipped_bit = 0; flipped_bit = 0;
tag_size = 8; tag_size = 8;
DBG DbpString("Configured for hitagS reader"); 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_start = 0;
uint32_t command_duration = 0; uint32_t command_duration = 0;
uint32_t response_start = 0; uint32_t response_start = 0;
uint32_t response_duration = 0; uint32_t response_duration = 0;
uint8_t rx[HITAG_FRAME_LEN]; uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0; size_t rxlen = 0;
uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t txbuf[HITAG_FRAME_LEN];
@ -1731,14 +1730,14 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
tag_size = 8; tag_size = 8;
DbpString("Configured for hitagS writer"); DbpString("Configured for hitagS writer");
} else if (htf < 20) { } else if (htf < 20) {
// hitag1 settings // hitag1 settings
t_wait_1 = 204; t_wait_1 = 204;
t_wait_2 = 128; t_wait_2 = 128;
tag_size = 256; tag_size = 256;
flipped_bit = 0; flipped_bit = 0;
DbpString("Configured for hitag1 writer"); DbpString("Configured for hitag1 writer");
} else if (htf < 30) { } else if (htf < 30) {
// hitag2 settings // hitag2 settings
t_wait_1 = HITAG_T_WAIT_1_MIN; t_wait_1 = HITAG_T_WAIT_1_MIN;
t_wait_2 = HITAG_T_WAIT_2_MIN; t_wait_2 = HITAG_T_WAIT_2_MIN;
tag_size = 48; 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); lf_wait_periods(t_wait_2);
command_start += t_wait_2; command_start += t_wait_2;

View file

@ -38,70 +38,60 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
uint8_t temp[20]; uint8_t temp[20];
int i; int i;
uint8_t *spaceptr = NULL; uint8_t *spaceptr = NULL;
// get uid as hexstring // get uid as hexstring
if(!hitag2_get_uid(uidhex)) if (!hitag2_get_uid(uidhex)) {
{
UserMessage("Cannot get UID\r\n"); UserMessage("Cannot get UID\r\n");
return false; return false;
} }
// convert uid hexstring to binarray // convert uid hexstring to binarray
hextobinarray(uid, uidhex); hextobinarray(uid, uidhex);
// convert nR and aR hexstrings to binarray // convert nR and aR hexstrings to binarray
spaceptr = strchr(nrarhex, ' '); spaceptr = strchr(nrarhex, ' ');
if (!spaceptr) if (!spaceptr) {
{
UserMessage("Please supply a valid nR aR pair\r\n"); UserMessage("Please supply a valid nR aR pair\r\n");
return false; return false;
} }
*spaceptr = 0x00; *spaceptr = 0x00;
if (hextobinarray(nrar, nrarhex) != 32) if (hextobinarray(nrar, nrarhex) != 32) {
{
UserMessage("nR is not 32 bits long\r\n"); UserMessage("nR is not 32 bits long\r\n");
return false; 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"); UserMessage("aR is not 32 bits long\r\n");
return false; return false;
} }
// find a valid encrypted command // 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"); UserMessage("Cannot find a valid encrypted command\r\n");
return false; return false;
} }
// find the 'read page 0' command and recover key stream // 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"); UserMessage("Cannot find encrypted 'read page0' command\r\n");
return false; return false;
} }
// empty the response string // empty the response string
response[0] = 0x00; response[0] = 0x00;
// read all pages using key stream // read all pages using key stream
for (i=0; i<8; i++) for (i = 0; i < 8; i++) {
{ if (hitag2crack_read_page(pagehex, i, nrar, keybits)) {
if (hitag2crack_read_page(pagehex, i, nrar, keybits))
{
sprintf(temp, "%1d: %s\r\n", i, pagehex); sprintf(temp, "%1d: %s\r\n", i, pagehex);
} } else {
else
{
sprintf(temp, "%1d:\r\n", i); sprintf(temp, "%1d:\r\n", i);
} }
// add page string to response // add page string to response
strcat(response, temp); strcat(response, temp);
} }
return true; 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[]) { bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]) {
uint8_t guess[10]; uint8_t guess[10];
uint8_t responsestr[9]; uint8_t responsestr[9];
// UserMessage("Finding valid encrypted command:"); // UserMessage("Finding valid encrypted command:");
// we're going to hold bits 5, 7, 8 and 9 and brute force the rest // 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 // e.g. x x x x x 0 x 0 0 0
for (uint8_t a=0; a<2; a++) { for (uint8_t a = 0; a < 2; a++) {
for (uint8_t b=0; b<2; b++) { for (uint8_t b = 0; b < 2; b++) {
for (uint8_t c=0; c<2; c++) { for (uint8_t c = 0; c < 2; c++) {
for (uint8_t d=0; d<2; d++) { for (uint8_t d = 0; d < 2; d++) {
for (uint8_t e=0; e<2; e++) { for (uint8_t e = 0; e < 2; e++) {
for (uint8_t g=0; g<2; g++) { for (uint8_t g = 0; g < 2; g++) {
// build binarray // build binarray
guess[0] = a; guess[0] = a;
guess[1] = b; 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:"); UserMessage("Finding 'read page 0' command:");
// we're going to brute the missing 4 bits of the valid encrypted command // we're going to brute the missing 4 bits of the valid encrypted command
for (a=0; a<2; a++) for (a = 0; a < 2; a++) {
{ for (b = 0; b < 2; b++) {
for (b=0; b<2; b++) for (c = 0; c < 2; c++) {
{ for (d = 0; d < 2; d++) {
for (c=0; c<2; c++)
{
for (d=0; d<2; d++)
{
// create our guess by bit flipping the pattern of bits // create our guess by bit flipping the pattern of bits
// representing the inverted bit and the 3 page bits // representing the inverted bit and the 3 page bits
// in both the non-inverted and inverted parts of the // in both the non-inverted and inverted parts of the
// encrypted command. // encrypted command.
memcpy(guess, e_firstcmd, 10); memcpy(guess, e_firstcmd, 10);
if (a) if (a) {
{
guess[5] = !guess[5]; guess[5] = !guess[5];
guess[0] = !guess[0]; guess[0] = !guess[0];
} }
if (b) if (b) {
{
guess[7] = !guess[7]; guess[7] = !guess[7];
guess[2] = !guess[2]; guess[2] = !guess[2];
} }
if (c) if (c) {
{
guess[8] = !guess[8]; guess[8] = !guess[8];
guess[3] = !guess[3]; guess[3] = !guess[3];
} }
if (d) if (d) {
{
guess[9] = !guess[9]; guess[9] = !guess[9];
guess[4] = !guess[4]; guess[4] = !guess[4];
} }
// try the guess // 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 // check if it was valid
if (strcmp(responsestr, ERROR_RESPONSE) != 0) if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
{
// convert response to binarray // convert response to binarray
hextobinarray(e_uid, responsestr); hextobinarray(e_uid, responsestr);
// test if the guess was 'read page 0' command // 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; return true;
} }
} } else {
else
{
#ifdef RFIDLER_DEBUG #ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n"); UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
#endif #endif
} }
} } else {
else #ifdef RFIDLER_DEBUG
{
#ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
#endif #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 e_ext_cmd[40];
uint8_t responsestr[9]; uint8_t responsestr[9];
int i; int i;
// copy encrypted cmd to cipherbits // copy encrypted cmd to cipherbits
memcpy(cipherbits, e_cmd, 10); memcpy(cipherbits, e_cmd, 10);
// copy encrypted uid to cipherbits // copy encrypted uid to cipherbits
memcpy(cipherbits + 10, e_uid, 32); memcpy(cipherbits + 10, e_uid, 32);
// copy cmd to plainbits // copy cmd to plainbits
binstringtobinarray(plainbits, READP0CMD); binstringtobinarray(plainbits, READP0CMD);
// copy uid to plainbits // copy uid to plainbits
memcpy(plainbits + 10, uid, 32); memcpy(plainbits + 10, uid, 32);
// xor the plainbits with the cipherbits to get keybits // xor the plainbits with the cipherbits to get keybits
hitag2crack_xor(keybits, plainbits, cipherbits, 42); hitag2crack_xor(keybits, plainbits, cipherbits, 42);
// create extended cmd -> 4 * READP0CMD = 40 bits // 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); binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
} }
// xor extended cmd with keybits // xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40); hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
// send extended encrypted cmd // 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 // test if it was valid
if (strcmp(responsestr, ERROR_RESPONSE) != 0) if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
{
return true; return true;
} }
} } else {
else
{
#ifdef RFIDLER_DEBUG #ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
#endif #endif
} }
return false; return false;
} }
// hitag2crack_xor XORs the source with the pad to produce the target. // hitag2crack_xor XORs the source with the pad to produce the target.
// source, target and pad are binarrays of length len. // source, target and pad are binarrays of length len.
void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int 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]; 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 e_response[32];
uint8_t response[32]; uint8_t response[32];
int i; int i;
if ((pagenum < 0) || (pagenum > 7)) if (pagenum > 7) {
{
UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n"); UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n");
return false; return false;
} }
// create cmd // create cmd
binstringtobinarray(cmd, READP0CMD); binstringtobinarray(cmd, READP0CMD);
if (pagenum & 0x1) if (pagenum & 0x1) {
{
cmd[9] = !cmd[9]; cmd[9] = !cmd[9];
cmd[4] = !cmd[4]; cmd[4] = !cmd[4];
} }
if (pagenum & 0x2) if (pagenum & 0x2) {
{
cmd[8] = !cmd[8]; cmd[8] = !cmd[8];
cmd[3] = !cmd[3]; cmd[3] = !cmd[3];
} }
if (pagenum & 0x4) if (pagenum & 0x4) {
{
cmd[7] = !cmd[7]; cmd[7] = !cmd[7];
cmd[2] = !cmd[2]; cmd[2] = !cmd[2];
} }
// encrypt command // encrypt command
hitag2crack_xor(e_cmd, cmd, keybits, 10); hitag2crack_xor(e_cmd, cmd, keybits, 10);
// send encrypted command // 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 // check if it is valid
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) {
{
// convert to binarray // convert to binarray
hextobinarray(e_response, e_responsestr); hextobinarray(e_response, e_responsestr);
// decrypt response // decrypt response
@ -370,17 +334,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
// convert to hexstring // convert to hexstring
binarraytohex(responsestr, response, 32); binarraytohex(responsestr, response, 32);
return true; return true;
} } else {
else
{
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n"); 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"); UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n");
} }
return false; return false;
} }
@ -391,14 +351,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
// cmd is the binarray of the encrypted command to send; // cmd is the binarray of the encrypted command to send;
// len is the length of the encrypted command. // len is the length of the encrypted command.
bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len) { bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len) {
uint8_t tmp[37]; // uint8_t tmp[37];
uint8_t uid[9]; uint8_t uid[9];
uint8_t e_page3str[9]; uint8_t e_page3str[9];
int ret = 0; int ret = 0;
// get the UID // 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"); UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n");
return false; return false;
} }
@ -407,22 +366,19 @@ bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, i
CryptoActive = false; CryptoActive = false;
// get the UID again // 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"); UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n");
return false; return false;
} }
// send nrar and receive (useless) encrypted page 3 value // 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"); UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n");
return false; return false;
} }
// send encrypted command // 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 #ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n"); UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n");
#endif #endif
@ -442,34 +398,29 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
int ret = 0; int ret = 0;
// START_AUTH kills active crypto session // START_AUTH kills active crypto session
CryptoActive= false; 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)) 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"); UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n");
return false; return false;
} }
// skip 1/2 bit to synchronise manchester // skip 1/2 bit to synchronise manchester
HW_Skip_Bits = 1; HW_Skip_Bits = 1;
ret = read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY); 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) // check if response was a valid length (5 sync bits + 32 bits response)
if (ret == 37) if (ret == 37) {
{
// check sync bits // check sync bits
if (memcmp(tmp, Hitag2Sync, 5) != 0) if (memcmp(tmp, Hitag2Sync, 5) != 0) {
{
UserMessage("hitag2crack_tx_rx: no sync\r\n"); UserMessage("hitag2crack_tx_rx: no sync\r\n");
return false; return false;
} }
// convert response to hexstring // convert response to hexstring
binarraytohex(responsestr, tmp + 5, 32); binarraytohex(responsestr, tmp + 5, 32);
return true; return true;
} } else {
else
{
#ifdef RFIDLER_DEBUG #ifdef RFIDLER_DEBUG
UserMessage("hitag2crack_tx_rx: wrong rx len\r\n"); UserMessage("hitag2crack_tx_rx: wrong rx len\r\n");
#endif #endif
@ -485,58 +436,53 @@ bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) {
uint32_t initvector; uint32_t initvector;
uint8_t *spaceptr; uint8_t *spaceptr;
uint8_t *dataptr; uint8_t *dataptr;
// extract vals from input // extract vals from input
dataptr = input; dataptr = input;
spaceptr = strchr(dataptr, ' '); spaceptr = strchr(dataptr, ' ');
if (!spaceptr) if (!spaceptr) {
{
UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n"); UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n");
return false; return false;
} }
*spaceptr = 0x00; *spaceptr = 0x00;
if (strlen(dataptr) != 12) if (strlen(dataptr) != 12) {
{
UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n"); UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n");
return false; return false;
} }
sharedkey = rev64(hexreversetoulonglong(dataptr)); sharedkey = rev64(hexreversetoulonglong(dataptr));
dataptr = spaceptr+1; dataptr = spaceptr + 1;
spaceptr = strchr(dataptr, ' '); spaceptr = strchr(dataptr, ' ');
if (!spaceptr) if (!spaceptr) {
{
UserMessage("/r/nno UID\r\n"); UserMessage("/r/nno UID\r\n");
return false; return false;
} }
*spaceptr = 0x00; *spaceptr = 0x00;
if (strlen(dataptr) != 8) if (strlen(dataptr) != 8) {
{
UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n"); UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n");
return false; return false;
} }
serialnum = rev32(hexreversetoulong(dataptr)); serialnum = rev32(hexreversetoulong(dataptr));
dataptr = spaceptr+1; dataptr = spaceptr + 1;
if (strlen(dataptr) != 8) if (strlen(dataptr) != 8) {
{
UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n"); UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n");
return false; return false;
} }
initvector = rev32(hexreversetoulong(dataptr)); initvector = rev32(hexreversetoulong(dataptr));
// start up crypto engine // start up crypto engine
hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector); hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector);
strcpy(response, "Success\r\n"); strcpy(response, "Success\r\n");
return true; return true;
} }
@ -545,21 +491,20 @@ bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) {
uint8_t binhex[9]; uint8_t binhex[9];
uint8_t binstr[33]; uint8_t binstr[33];
uint32_t binulong; uint32_t binulong;
if (strlen(hex) != 8) if (strlen(hex) != 8) {
{
UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n"); UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n");
return false; return false;
} }
binulong = hextoulong(hex); binulong = hextoulong(hex);
ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32); ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32);
binarraytobinstring(binstr, bin, 32); binarraytobinstring(binstr, bin, 32);
binarraytohex(binhex, bin, 32); binarraytohex(binhex, bin, 32);
// UserMessage("ar = %s\r\n", binstr); // UserMessage("ar = %s\r\n", binstr);
// UserMessage("arhex = %s\r\n", binhex); // UserMessage("arhex = %s\r\n", binhex);
strcpy(response, binhex); strcpy(response, binhex);
return true; return true;
} }
@ -570,17 +515,16 @@ bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) {
uint8_t binstr[33]; uint8_t binstr[33];
uint32_t binulong; uint32_t binulong;
int len; int len;
len = strlen(e_binstr); len = strlen(e_binstr);
if (len > 32) if (len > 32) {
{
UserMessage("\r\nbinary string must be <= 32 bits\r\n"); UserMessage("\r\nbinary string must be <= 32 bits\r\n");
return false; return false;
} }
binstringtobinarray(e_bin, e_binstr); binstringtobinarray(e_bin, e_binstr);
binulong = binarraytoulong(e_bin, len); binulong = binarraytoulong(e_bin, len);
ulongtobinarray(bin, hitag2_crypt(binulong, len), len); ulongtobinarray(bin, hitag2_crypt(binulong, len), len);
binarraytobinstring(binstr, bin, len); binarraytobinstring(binstr, bin, len);
strcpy(response, binstr); 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) { bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr) {
return hitag2crack_decrypt_bin(response, e_binstr); return hitag2crack_decrypt_bin(response, e_binstr);
} }
// hitag2_keystream uses the first crack algorithm described in the paper, // hitag2_keystream uses the first crack algorithm described in the paper,
// Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits // Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits
// of keystream. // of keystream.
@ -607,113 +551,101 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
uint8_t uid[32]; uint8_t uid[32];
uint8_t nrar[64]; uint8_t nrar[64];
uint8_t e_firstcmd[10]; uint8_t e_firstcmd[10];
uint8_t e_page0cmd[10]; // uint8_t e_page0cmd[10];
// uint8_t keybits[2080]; // uint8_t keybits[2080];
uint8_t *keybits = DataBuff; uint8_t *keybits = DataBuff;
uint8_t keybitshex[67]; uint8_t keybitshex[67];
int kslen; int kslen;
int ksoffset; int ksoffset;
uint8_t pagehex[9]; // uint8_t pagehex[9];
uint8_t temp[20]; // uint8_t temp[20];
int i; int i;
uint8_t *spaceptr = NULL; uint8_t *spaceptr = NULL;
/* /*
keybits = malloc(2080); keybits = malloc(2080);
if (!keybits) { if (!keybits) {
UserMessage("cannot malloc keybits\r\n"); UserMessage("cannot malloc keybits\r\n");
return false; return false;
} }
*/ */
// get uid as hexstring // get uid as hexstring
if(!hitag2_get_uid(uidhex)) if (!hitag2_get_uid(uidhex)) {
{
UserMessage("Cannot get UID\r\n"); UserMessage("Cannot get UID\r\n");
return false; return false;
} }
// convert uid hexstring to binarray // convert uid hexstring to binarray
hextobinarray(uid, uidhex); hextobinarray(uid, uidhex);
// convert nR and aR hexstrings to binarray // convert nR and aR hexstrings to binarray
spaceptr = strchr(nrarhex, ' '); spaceptr = strchr(nrarhex, ' ');
if (!spaceptr) if (!spaceptr) {
{
UserMessage("Please supply a valid nR aR pair\r\n"); UserMessage("Please supply a valid nR aR pair\r\n");
return false; return false;
} }
*spaceptr = 0x00; *spaceptr = 0x00;
if (hextobinarray(nrar, nrarhex) != 32) if (hextobinarray(nrar, nrarhex) != 32) {
{
UserMessage("nR is not 32 bits long\r\n"); UserMessage("nR is not 32 bits long\r\n");
return false; 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"); UserMessage("aR is not 32 bits long\r\n");
return false; return false;
} }
// find a valid encrypted command // 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"); UserMessage("Cannot find a valid encrypted command\r\n");
return false; return false;
} }
// find the 'read page 0' command and recover key stream // 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"); UserMessage("Cannot find encrypted 'read page0' command\r\n");
return false; return false;
} }
// using the 40 bits of keystream in keybits, sending commands with ever // using the 40 bits of keystream in keybits, sending commands with ever
// increasing lengths to acquire 2048 bits of key stream. // increasing lengths to acquire 2048 bits of key stream.
kslen = 40; kslen = 40;
while (kslen < 2048) while (kslen < 2048) {
{
ksoffset = 0; ksoffset = 0;
if (!hitag2crack_send_auth(nrar)) if (!hitag2crack_send_auth(nrar)) {
{
UserMessage("hitag2crack_send_auth failed\r\n"); UserMessage("hitag2crack_send_auth failed\r\n");
return false; return false;
} }
// while we have at least 52 bits of keystream, consume it with // while we have at least 52 bits of keystream, consume it with
// extended read page 0 commands. 52 = 10 (min command len) + // extended read page 0 commands. 52 = 10 (min command len) +
// 32 (response) + 10 (min command len we'll send) // 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 // 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"); UserMessage("hitag2crack_consume_keystream failed\r\n");
return false; return false;
} }
} }
// send an extended command to retrieve more keystream, updating kslen // send an extended command to retrieve more keystream, updating kslen
// as we go // 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"); UserMessage("hitag2crack_extend_keystream failed\r\n");
return false; return false;
} }
UserMessage("Recovered %d bits of keystream\r\n", kslen); 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); binarraytohex(keybitshex, keybits + i, 256);
UserMessage("%s\r\n", keybitshex); UserMessage("%s\r\n", keybitshex);
} }
response[0] = 0x00; response[0] = 0x00;
return true; return true;
} }
@ -724,8 +656,7 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
uint8_t e_page3str[9]; uint8_t e_page3str[9];
// get the UID // get the UID
if(!hitag2_get_uid(uid)) if (!hitag2_get_uid(uid)) {
{
UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n"); UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n");
return false; return false;
} }
@ -734,15 +665,13 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
CryptoActive = false; CryptoActive = false;
// get the UID again // 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"); UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n");
return false; return false;
} }
// send nrar and receive (useless) encrypted page 3 value // 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"); UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n");
return false; 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 // 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. // cannot be longer than 510 bits to fit into the small RWD buffer.
conlen = kslen - *ksoffset - 42; conlen = kslen - *ksoffset - 42;
if (conlen < 10) if (conlen < 10) {
{
UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n"); UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n");
return false; return false;
} }
// sanitise conlen // sanitise conlen
if (conlen > 510) if (conlen > 510) {
{
conlen = 510; conlen = 510;
} }
// calculate how many repeated commands to send in this extended command. // calculate how many repeated commands to send in this extended command.
numcmds = conlen / 10; numcmds = conlen / 10;
// build extended command // build extended command
for (i=0; i<numcmds; i++) for (i = 0; i < numcmds; i++) {
{
binstringtobinarray(ext_cmd + (i * 10), READP0CMD); binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
} }
// xor extended cmd with keybits // xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + *ksoffset, numcmds * 10); hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + *ksoffset, numcmds * 10);
// send encrypted command // 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"); UserMessage("hitag2crack_consume_keystream:\r\n tx/rx cmd failed\r\n");
return false; return false;
} }
// test response // 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"); UserMessage("hitag2crack_consume_keystream:\r\n got error response from card\r\n");
return false; return false;
} }
// dont bother decrypting the response - we already know the keybits // dont bother decrypting the response - we already know the keybits
// update ksoffset with command length and response // update ksoffset with command length and response
*ksoffset += (numcmds * 10) + 32; *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 responsestr[9];
uint8_t e_response[32]; uint8_t e_response[32];
int i; int i;
// calc number of command iterations to send // calc number of command iterations to send
cmdlen = *kslen - ksoffset; cmdlen = *kslen - ksoffset;
if (cmdlen < 10) if (cmdlen < 10) {
{
UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n"); UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n");
return false; return false;
} }
numcmds = cmdlen / 10; numcmds = cmdlen / 10;
// build extended command // build extended command
for (i=0; i<numcmds; i++) for (i = 0; i < numcmds; i++) {
{
binstringtobinarray(ext_cmd + (i * 10), READP0CMD); binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
} }
// xor extended cmd with keybits // xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + ksoffset, numcmds * 10); hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + ksoffset, numcmds * 10);
// send extended encrypted cmd // 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"); UserMessage("hitag2crack_extend_keystream:\r\n tx/rx cmd failed\r\n");
return false; return false;
} }
// test response // 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"); UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
return false; return false;
} }
@ -867,7 +787,7 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
// update kslen // update kslen
*kslen = ksoffset + (numcmds * 10) + 32; *kslen = ksoffset + (numcmds * 10) + 32;
return true; 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) { bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive) {
uint8_t tmp[9]; uint8_t tmp[9];
int i; int i;
response[0] = '\0'; response[0] = '\0';
// auth to tag // auth to tag
if (hitag2_crypto_auth(tmp, key)) if (hitag2_crypto_auth(tmp, key)) {
{
// read tag, one page at a time // read tag, one page at a time
for (i= 0; i <= 7; ++i) for (i = 0; i <= 7; ++i) {
{ if (!read_tag(tmp, i, i)) {
if(!read_tag(tmp, i, i))
{
// if read fails, it could be because of auth, // if read fails, it could be because of auth,
// so try to reauth // 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 // if we can't reauth, it's a real failure
return false; return false;
} }
// temp failure (probably due to page protections) // temp failure (probably due to page protections)
strcpy(tmp, "XXXXXXXX"); strcpy(tmp, "XXXXXXXX");
} }
// page contents are in tmp // page contents are in tmp
strcat(response, tmp); strcat(response, tmp);
} }
if (interactive) if (interactive) {
{ tmp[8] = '\0';
tmp[8]= '\0'; for (i = 0; i <= 7 ; ++i) {
for(i= 0; i <= 7 ; ++i) UserMessageNum("%d: ", i);
{ memcpy(tmp, response + (i * 8), 8);
UserMessageNum("%d: ", i); UserMessage("%s\r\n", tmp);
memcpy(tmp, response + (i * 8), 8);
UserMessage("%s\r\n", tmp);
}
UserMessage("%s", "\r\n");
} }
else UserMessage("%s", "\r\n");
{ } else {
hitag2_nvm_store_tag(response); hitag2_nvm_store_tag(response);
} }
return true; return true;
} } else {
else
{
return false; return false;
} }
} }

View file

@ -19,9 +19,9 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
bool hitag2crack_rng_init(uint8_t *response, uint8_t *input); bool hitag2crack_rng_init(uint8_t *response, uint8_t *input);
bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex); bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex);
bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *hex); bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr);
bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex); bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex);
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *hex); bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr);
bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex); bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex);
bool hitag2crack_send_auth(uint8_t *nrar); bool hitag2crack_send_auth(uint8_t *nrar);

View file

@ -10,6 +10,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Some code was copied from Hitag2.c // Some code was copied from Hitag2.c
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// bosb 2020
#include "hitagS.h" #include "hitagS.h"
@ -23,6 +24,7 @@
#include "string.h" #include "string.h"
#include "commonutil.h" #include "commonutil.h"
#include "hitag2_crypto.h" #include "hitag2_crypto.h"
#include "lfadc.h"
#define CRC_PRESET 0xFF #define CRC_PRESET 0xFF
#define CRC_POLYNOM 0x1D #define CRC_POLYNOM 0x1D
@ -50,6 +52,22 @@ size_t blocknr;
bool end = false; bool end = false;
//#define SENDBIT_TEST //#define SENDBIT_TEST
/* array index 3 2 1 0 // bytes in sim.bin file are 0 1 2 3
// UID is 0 1 2 3 // tag.uid is 3210
// datasheet HitagS_V11.pdf bytes in tables printed 3 2 1 0
#db# UID: 5F C2 11 84
#db# conf0: C9 conf1: 00 conf2: 00
3 2 1 0
#db# Page[ 0]: 84 11 C2 5F uid
#db# Page[ 1]: AA 00 00 C9 conf, HITAG S 256
#db# Page[ 2]: 4E 4F 54 48
#db# Page[ 3]: 52 4B 49 4D
#db# Page[ 4]: 00 00 00 00
#db# Page[ 5]: 00 00 00 00
#db# Page[ 6]: 00 00 00 00
#db# Page[ 7]: 4B 4F 5F 57 */
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) #define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b))
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) #define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b)))
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) #define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c))))
@ -86,7 +104,7 @@ bool end = false;
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_THREE_HALF 41
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
#define DEBUG 0 #define DBGLEVEL 0
/* /*
* Implementation of the crc8 calculation from Hitag S * Implementation of the crc8 calculation from Hitag S
@ -207,6 +225,22 @@ static void hitag_send_bit(int bit) {
} }
static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { static void hitag_send_frame(const uint8_t *frame, size_t frame_len) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("hitag_send_frame: (%i) %02X %02X %02X %02X", frame_len, frame[0], frame[1], frame[2], frame[3]);
// The beginning of the frame is hidden in some high level; pause until our bits will have an effect
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
HIGH(GPIO_SSC_DOUT);
switch (m) {
case AC4K:
case MC8K:
while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; //FADV
break;
case AC2K:
case MC4K:
while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; //STD + ADV
break;
}
// SOF - send start of frame // SOF - send start of frame
for (size_t i = 0; i < sof_bits; i++) { for (size_t i = 0; i < sof_bits; i++) {
hitag_send_bit(1); hitag_send_bit(1);
@ -299,6 +333,25 @@ static int check_select(uint8_t *rx, uint32_t uid) {
return 0; return 0;
} }
void hitagS_set_frame_modulation() {
switch (tag.mode) {
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
}
/* /*
* handles all commands from a reader * handles all commands from a reader
*/ */
@ -318,20 +371,28 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
switch (rxlen) { switch (rxlen) {
case 5: { case 5: {
//UID request with a selected response protocol mode //UID request with a selected response protocol mode
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("UID request: length: %i first byte: %02x", rxlen, rx[0]);
tag.pstate = HT_READY; tag.pstate = HT_READY;
tag.tstate = HT_NO_OP; tag.tstate = HT_NO_OP;
if ((rx[0] & 0xf0) == 0x30) { if ((rx[0] & 0xf0) == 0x30) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_STANDARD");
tag.mode = HT_STANDARD; tag.mode = HT_STANDARD;
sof_bits = 1; sof_bits = 1;
m = AC2K; m = AC2K;
} }
if ((rx[0] & 0xf0) == 0xc0) { if ((rx[0] & 0xf0) == 0xc0) {
tag.mode = HT_ADVANCED; tag.mode = HT_ADVANCED;
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_ADVANCED");
sof_bits = 3; sof_bits = 3;
m = AC2K; m = AC2K;
} }
if ((rx[0] & 0xf0) == 0xd0) { if ((rx[0] & 0xf0) == 0xd0) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_FAST_ADVANCED");
tag.mode = HT_FAST_ADVANCED; tag.mode = HT_FAST_ADVANCED;
sof_bits = 3; sof_bits = 3;
m = AC4K; m = AC4K;
@ -344,29 +405,18 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
break; break;
case 45: { case 45: {
//select command from reader received //select command from reader received
if (DBGLEVEL >= DBG_EXTENDED)
DbpString("SELECT");
if (check_select(rx, tag.uid) == 1) { if (check_select(rx, tag.uid) == 1) {
if (DBGLEVEL >= DBG_EXTENDED)
DbpString("SELECT match");
//if the right tag was selected //if the right tag was selected
*txlen = 32; *txlen = 32;
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
//send configuration //send configuration
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; tx[i] = tag.pages[1][i];
tx[3] = 0xff; tx[3] = 0xff;
if (tag.mode != HT_STANDARD) { if (tag.mode != HT_STANDARD) {
*txlen = 40; *txlen = 40;
@ -390,22 +440,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
_hitag2_byte(&state); _hitag2_byte(&state);
@ -438,7 +473,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
} }
*/ */
} }
break;
case 40: case 40:
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("WRITE");
//data received to be written //data received to be written
if (tag.tstate == HT_WRITING_PAGE_DATA) { if (tag.tstate == HT_WRITING_PAGE_DATA) {
tag.tstate = HT_NO_OP; tag.tstate = HT_NO_OP;
@ -448,44 +486,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
*txlen = 2; *txlen = 2;
tx[0] = 0x40; tx[0] = 0x40;
page_to_be_written = 0; page_to_be_written = 0;
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
} else if (tag.tstate == HT_WRITING_BLOCK_DATA) { } else if (tag.tstate == HT_WRITING_BLOCK_DATA) {
tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0]
<< 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3];
//send ack //send ack
*txlen = 2; *txlen = 2;
tx[0] = 0x40; tx[0] = 0x40;
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
page_to_be_written++; page_to_be_written++;
block_data_left--; block_data_left--;
if (block_data_left == 0) { if (block_data_left == 0) {
@ -500,29 +508,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
//send page data //send page data
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
*txlen = 32; *txlen = 32;
tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; tx[0] = tag.pages[page][0];
tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; tx[1] = tag.pages[page][1];
tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; tx[2] = tag.pages[page][2];
tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; tx[3] = tag.pages[page][3];
if (tag.LKP && page == 1) if (tag.LKP && page == 1)
tx[3] = 0xff; tx[3] = 0xff;
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
if (tag.mode != HT_STANDARD) { if (tag.mode != HT_STANDARD) {
//add crc8 //add crc8
@ -543,29 +536,13 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
*txlen = 32 * 4; *txlen = 32 * 4;
//send page,...,page+3 data //send page,...,page+3 data
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; tx[0 + i * 4] = tag.pages[page + 0 + i * 4][0];
tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; tx[1 + i * 4] = tag.pages[page + 1 + i * 4][1];
tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; tx[2 + i * 4] = tag.pages[page + 2 + i * 4][2];
tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; tx[3 + i * 4] = tag.pages[page + 3 + i * 4][3];
page++;
} }
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
if (tag.mode != HT_STANDARD) { if (tag.mode != HT_STANDARD) {
//add crc8 //add crc8
@ -576,29 +553,12 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[16] = crc; tx[16] = crc;
} }
if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) { if ((page) % 4 != 0 || (tag.LKP && (page) == 0)) {
sof_bits = 0; sof_bits = 0;
*txlen = 0; *txlen = 0;
} }
} else if ((rx[0] & 0xf0) == 0x80) { //write page } else if ((rx[0] & 0xf0) == 0x80) { //write page
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
switch (tag.mode) {
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
if ((tag.LCON && page == 1) if ((tag.LCON && page == 1)
|| (tag.LKP && (page == 2 || page == 3))) { || (tag.LKP && (page == 2 || page == 3))) {
//deny //deny
@ -613,22 +573,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
} else if ((rx[0] & 0xf0) == 0x90) { //write block } else if ((rx[0] & 0xf0) == 0x90) { //write block
uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16);
switch (tag.mode) { hitagS_set_frame_modulation();
case HT_STANDARD:
sof_bits = 1;
m = MC4K;
break;
case HT_ADVANCED:
sof_bits = 6;
m = MC4K;
break;
case HT_FAST_ADVANCED:
sof_bits = 6;
m = MC8K;
break;
default:
break;
}
if (page % 4 != 0 || page == 0) { if (page % 4 != 0 || page == 0) {
//deny //deny
*txlen = 0; *txlen = 0;
@ -644,7 +589,8 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
} }
break; break;
default: default:
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]);
break; break;
} }
} }
@ -722,7 +668,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
| (uid[30] << 1) | (uid[30] << 1)
| uid[31]; | uid[31];
if (DEBUG) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4);
tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1);
@ -816,7 +762,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
tag.LCK1 = response_bit[26]; tag.LCK1 = response_bit[26];
tag.LCK0 = response_bit[27]; tag.LCK0 = response_bit[27];
if (DEBUG) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
if (tag.auth == 1) { if (tag.auth == 1) {
@ -839,7 +785,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
tx[5] = auth_ks[1]; tx[5] = auth_ks[1];
tx[6] = auth_ks[2]; tx[6] = auth_ks[2];
tx[7] = auth_ks[3]; tx[7] = auth_ks[3];
if (DEBUG) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0], Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0],
tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]); tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]);
} else if (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE } else if (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE
@ -864,7 +810,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8);
calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8);
calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8);
if (DEBUG) { if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("UID:::%X", tag.uid); Dbprintf("UID:::%X", tag.uid);
Dbprintf("RND:::%X", rnd); Dbprintf("RND:::%X", rnd);
} }
@ -884,7 +830,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state); pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state);
} }
if (DEBUG) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1);
//Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16));
@ -930,28 +876,30 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
tag.pstate = HT_READY; tag.pstate = HT_READY;
tag.tstate = HT_NO_OP; tag.tstate = HT_NO_OP;
for (i = 0; i < 16; i++)
for (j = 0; j < 4; j++)
tag.pages[i][j] = 0x0;
// read tag data into memory // read tag data into memory
if (tag_mem_supplied) { if (tag_mem_supplied) {
for (i = 0; i < 16; i++)
for (j = 0; j < 4; j++)
tag.pages[i][j] = 0x0;
DbpString("Loading hitagS memory..."); DbpString("Loading hitagS memory...");
memcpy((uint8_t *)tag.pages, data, 4 * 64); memcpy((uint8_t *)tag.pages, data, 4 * 64);
} else {
// use the last read tag
} }
tag.uid = (uint32_t)tag.pages[0]; tag.uid = (tag.pages[0][3] << 24 | tag.pages[0][2] << 16 | tag.pages[0][1] << 8 | tag.pages[0][0]);
tag.key = (intptr_t)tag.pages[3]; tag.key = (tag.pages[3][3] << 24 | tag.pages[3][2] << 16 | tag.pages[3][1] << 8 | tag.pages[3][0]);
tag.key <<= 16; tag.key <<= 16;
tag.key += ((tag.pages[2][0]) << 8) + tag.pages[2][1]; tag.key += ((tag.pages[2][3]) << 8) + tag.pages[2][2];
tag.pwdl0 = tag.pages[2][3]; tag.pwdl0 = tag.pages[2][0];
tag.pwdl1 = tag.pages[2][2]; tag.pwdl1 = tag.pages[2][1];
tag.pwdh0 = tag.pages[1][0]; tag.pwdh0 = tag.pages[1][3];
//con0 //con0
tag.max_page = 64; tag.max_page = 64;
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 1) if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 1)
tag.max_page = 8; tag.max_page = 8;
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 0)
tag.max_page = 0; tag.max_page = 0;
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
for (i = 0; i < tag.max_page; i++) for (i = 0; i < tag.max_page; i++)
@ -962,41 +910,42 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
tag.pages[i][0] & 0xff); tag.pages[i][0] & 0xff);
//con1 //con1
tag.auth = 0; tag.auth = 0;
if ((tag.pages[1][2] & 0x80) == 0x80) if ((tag.pages[1][1] & 0x80) == 0x80)
tag.auth = 1; tag.auth = 1;
tag.LCON = 0; tag.LCON = 0;
if ((tag.pages[1][2] & 0x2) == 0x02) if ((tag.pages[1][1] & 0x2) == 0x02)
tag.LCON = 1; tag.LCON = 1;
tag.LKP = 0; tag.LKP = 0;
if ((tag.pages[1][2] & 0x1) == 0x01) if ((tag.pages[1][1] & 0x1) == 0x01)
tag.LKP = 1; tag.LKP = 1;
//con2 //con2
//0=read write 1=read only //0=read write 1=read only
tag.LCK7 = 0; tag.LCK7 = 0;
if ((tag.pages[1][1] & 0x80) == 0x80) if ((tag.pages[1][2] & 0x80) == 0x80)
tag.LCK7 = 1; tag.LCK7 = 1;
tag.LCK6 = 0; tag.LCK6 = 0;
if ((tag.pages[1][1] & 0x40) == 0x040) if ((tag.pages[1][2] & 0x40) == 0x040)
tag.LCK6 = 1; tag.LCK6 = 1;
tag.LCK5 = 0; tag.LCK5 = 0;
if ((tag.pages[1][1] & 0x20) == 0x20) if ((tag.pages[1][2] & 0x20) == 0x20)
tag.LCK5 = 1; tag.LCK5 = 1;
tag.LCK4 = 0; tag.LCK4 = 0;
if ((tag.pages[1][1] & 0x10) == 0x10) if ((tag.pages[1][2] & 0x10) == 0x10)
tag.LCK4 = 1; tag.LCK4 = 1;
tag.LCK3 = 0; tag.LCK3 = 0;
if ((tag.pages[1][1] & 0x8) == 0x08) if ((tag.pages[1][2] & 0x8) == 0x08)
tag.LCK3 = 1; tag.LCK3 = 1;
tag.LCK2 = 0; tag.LCK2 = 0;
if ((tag.pages[1][1] & 0x4) == 0x04) if ((tag.pages[1][2] & 0x4) == 0x04)
tag.LCK2 = 1; tag.LCK2 = 1;
tag.LCK1 = 0; tag.LCK1 = 0;
if ((tag.pages[1][1] & 0x2) == 0x02) if ((tag.pages[1][2] & 0x2) == 0x02)
tag.LCK1 = 1; tag.LCK1 = 1;
tag.LCK0 = 0; tag.LCK0 = 0;
if ((tag.pages[1][1] & 0x1) == 0x01) if ((tag.pages[1][2] & 0x1) == 0x01)
tag.LCK0 = 1; tag.LCK0 = 1;
// Set up simulator mode, frequency divisor which will drive the FPGA // Set up simulator mode, frequency divisor which will drive the FPGA
// and analog mux selection. // and analog mux selection.
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
@ -1028,7 +977,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
// external trigger rising edge, load RA on rising edge of TIOA. // external trigger rising edge, load RA on rising edge of TIOA.
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
| AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING;
// Enable and reset counter // Enable and reset counter
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
@ -1100,12 +1049,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); LogTrace(tx, nbytes(txlen), 0, 0, NULL, false);
} }
// Enable and reset external trigger in timer for capturing future frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Reset the received frame and response timing info // Reset the received frame and response timing info
memset(rx, 0x00, sizeof(rx)); memset(rx, 0x00, sizeof(rx));
response = 0; response = 0;
// Enable and reset external trigger in timer for capturing future frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
LED_B_OFF(); LED_B_OFF();
} }
// Reset the frame length // Reset the frame length
@ -1114,22 +1064,92 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
overflow += (AT91C_BASE_TC1->TC_CV / T0); overflow += (AT91C_BASE_TC1->TC_CV / T0);
// Reset the timer to restart while-loop that receives frames // Reset the timer to restart while-loop that receives frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
} }
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false); set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; lf_finalize();
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
// release allocated memory from BigBuff. // release allocated memory from BigBuff.
BigBuf_free(); BigBuf_free();
StartTicks();
DbpString("Sim Stopped"); DbpString("Sim Stopped");
} }
void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response) {
// Reset values for receiving frames
memset(rx, 0x00, HITAG_FRAME_LEN * sizeof(uint8_t));
*rxlen = 0;
int lastbit = 1;
bool bSkip = true;
int tag_sof = 1;
*response = 0;
uint32_t errorCount = 0;
// Receive frame, watch for at most T0*EOF periods
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
// Check if falling edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
// Retrieve the new timing values
int ra = (AT91C_BASE_TC1->TC_RA / T0);
// Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
LED_B_ON();
// Capture tag frame (manchester decoding using only falling edges)
if (ra >= HITAG_T_EOF) {
if (*rxlen != 0) {
//DbpString("wierd1?");
}
// Capture the T0 periods that have passed since last communication or field drop (reset)
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
*response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101)
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
(*rxlen)++;
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
(*rxlen)++;
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
// Manchester coding example |_-|...|_-|-_| (0...01)
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
(*rxlen)++;
// We have to skip this half period at start and add the 'one' the second time
if (!bSkip) {
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
(*rxlen)++;
}
lastbit = !lastbit;
bSkip = !bSkip;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
if (tag_sof) {
// Ignore bits that are transmitted during SOF
tag_sof--;
} else {
// bit is same as last bit
rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
(*rxlen)++;
}
} else {
// Ignore wierd value, is to small to mean anything
errorCount++;
}
}
// if we saw over 100 wierd values break it probably isn't hitag...
if (errorCount > 100) break;
// We can break this loop if we received the last bit from a frame
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
if ((*rxlen) > 0)
break;
}
}
}
/* /*
* Authenticates to the Tag with the given key or challenge. * Authenticates to the Tag with the given key or challenge.
* If the key was given the password will be decrypted. * If the key was given the password will be decrypted.
@ -1149,7 +1169,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
uint8_t *tx = txbuf; uint8_t *tx = txbuf;
size_t txlen = 0; size_t txlen = 0;
int lastbit = 1; int lastbit = 1;
int reset_sof = 1;
int t_wait = HITAG_T_WAIT_MAX; int t_wait = HITAG_T_WAIT_MAX;
bool bStop = false; bool bStop = false;
int pageNum = 0; int pageNum = 0;
@ -1164,6 +1183,9 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
uint64_t NrAr = 0; uint64_t NrAr = 0;
uint8_t key_[6]; uint8_t key_[6];
tag.pstate = HT_READY;
tag.tstate = HT_NO_OP;
switch (htf) { switch (htf) {
case RHTSF_CHALLENGE: { case RHTSF_CHALLENGE: {
DbpString("Authenticating using nr,ar pair:"); DbpString("Authenticating using nr,ar pair:");
@ -1238,10 +1260,8 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
// synchronized startup procedure // synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
t_wait = 200; t_wait = 200;
while (!bStop && !BUTTON_PRESS() && !data_available()) { while (!bStop && !BUTTON_PRESS() && !data_available()) {
WDT_HIT(); WDT_HIT();
@ -1381,85 +1401,12 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
} }
// Reset values for receiving frames hitagS_receive_frame(rx, &rxlen, &response);
memset(rx, 0x00, sizeof(rx));
rxlen = 0;
lastbit = 1;
bool bSkip = true;
int tag_sof = reset_sof;
response = 0;
// Receive frame, watch for at most T0*EOF periods
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
// Check if falling edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
// Retrieve the new timing values
int ra = (AT91C_BASE_TC1->TC_RA / T0);
// Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
LED_B_ON();
// Capture tag frame (manchester decoding using only falling edges)
if (ra >= HITAG_T_EOF) {
if (rxlen != 0) {
//DbpString("wierd1?");
}
// Capture the T0 periods that have passed since last communication or field drop (reset)
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
// Manchester coding example |_-|...|_-|-_| (0...01)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
// We have to skip this half period at start and add the 'one' the second time
if (!bSkip) {
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
}
lastbit = !lastbit;
bSkip = !bSkip;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
if (tag_sof) {
// Ignore bits that are transmitted during SOF
tag_sof--;
} else {
// bit is same as last bit
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
rxlen++;
}
} else {
// Ignore wierd value, is to small to mean anything
}
}
// We can break this loop if we received the last bit from a frame
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
if (rxlen > 0)
break;
}
}
} }
end = false; end = false;
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false); set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; lf_finalize();
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
StartTicks();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }
@ -1479,7 +1426,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
uint8_t *tx = txbuf; uint8_t *tx = txbuf;
size_t txlen = 0; size_t txlen = 0;
int lastbit; int lastbit;
int reset_sof;
int t_wait = HITAG_T_WAIT_MAX; int t_wait = HITAG_T_WAIT_MAX;
bool bStop; bool bStop;
unsigned char crc; unsigned char crc;
@ -1555,6 +1501,7 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
// external trigger rising edge, load RA on falling edge of TIOA. // external trigger rising edge, load RA on falling edge of TIOA.
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
| AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ETRGEDG_FALLING
@ -1570,7 +1517,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
lastbit = 1; lastbit = 1;
bStop = false; bStop = false;
reset_sof = 1;
t_wait = 200; t_wait = 200;
while (!bStop && !BUTTON_PRESS() && !data_available()) { while (!bStop && !BUTTON_PRESS() && !data_available()) {
@ -1670,87 +1616,13 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
} }
// Reset values for receiving frames hitagS_receive_frame(rx, &rxlen, &response);
memset(rx, 0x00, sizeof(rx));
rxlen = 0;
lastbit = 1;
bool bSkip = true;
int tag_sof = reset_sof;
response = 0;
uint32_t errorCount = 0;
// Receive frame, watch for at most T0*EOF periods
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
// Check if falling edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
// Retrieve the new timing values
int ra = (AT91C_BASE_TC1->TC_RA / T0);
// Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
LED_B_ON();
// Capture tag frame (manchester decoding using only falling edges)
if (ra >= HITAG_T_EOF) {
if (rxlen != 0) {
//DbpString("wierd1?");
}
// Capture the T0 periods that have passed since last communication or field drop (reset)
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
// Manchester coding example |_-|...|_-|-_| (0...01)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
// We have to skip this half period at start and add the 'one' the second time
if (!bSkip) {
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
}
lastbit = !lastbit;
bSkip = !bSkip;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
if (tag_sof) {
// Ignore bits that are transmitted during SOF
tag_sof--;
} else {
// bit is same as last bit
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
rxlen++;
}
} else {
// Ignore wierd value, is to small to mean anything
errorCount++;
}
}
// if we saw over 100 wierd values break it probably isn't hitag...
if (errorCount > 100) break;
// We can break this loop if we received the last bit from a frame
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
if (rxlen > 0)
break;
}
}
} }
end = false; end = false;
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false); set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; lf_finalize();
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
StartTicks();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }
@ -1773,7 +1645,7 @@ void check_challenges(bool file_given, uint8_t *data) {
size_t rxlen = 0; size_t rxlen = 0;
uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t txbuf[HITAG_FRAME_LEN];
int t_wait = HITAG_T_WAIT_MAX; int t_wait = HITAG_T_WAIT_MAX;
int lastbit, reset_sof, STATE = 0;; int lastbit, STATE = 0;;
bool bStop; bool bStop;
int response_bit[200]; int response_bit[200];
unsigned char mask = 1; unsigned char mask = 1;
@ -1834,7 +1706,6 @@ void check_challenges(bool file_given, uint8_t *data) {
// Reset the received frame, frame count and timing info // Reset the received frame, frame count and timing info
lastbit = 1; lastbit = 1;
bStop = false; bStop = false;
reset_sof = 1;
t_wait = 200; t_wait = 200;
if (file_given) { if (file_given) {
@ -1952,11 +1823,11 @@ void check_challenges(bool file_given, uint8_t *data) {
u1++; u1++;
} else if (STATE == 2 && rxlen >= 44) { } else if (STATE == 2 && rxlen >= 44) {
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X", Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
unlocker[u1 - 1][0], unlocker[u1 - 1][1], unlocker[u1 - 1][0], unlocker[u1 - 1][1],
unlocker[u1 - 1][2], unlocker[u1 - 1][3], unlocker[u1 - 1][2], unlocker[u1 - 1][3],
unlocker[u1 - 1][4], unlocker[u1 - 1][5], unlocker[u1 - 1][4], unlocker[u1 - 1][5],
unlocker[u1 - 1][6], unlocker[u1 - 1][7]); unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
STATE = 0; STATE = 0;
} }
@ -1984,85 +1855,10 @@ void check_challenges(bool file_given, uint8_t *data) {
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
} }
// Reset values for receiving frames hitagS_receive_frame(rx, &rxlen, &response);
memset(rx, 0x00, sizeof(rx));
rxlen = 0;
lastbit = 1;
bool bSkip = true;
int tag_sof = reset_sof;
response = 0;
// Receive frame, watch for at most T0*EOF periods
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
// Check if falling edge in tag modulation is detected
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
// Retrieve the new timing values
int ra = (AT91C_BASE_TC1->TC_RA / T0);
// Reset timer every frame, we have to capture the last edge for timing
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
LED_B_ON();
// Capture tag frame (manchester decoding using only falling edges)
if (ra >= HITAG_T_EOF) {
if (rxlen != 0) {
//DbpString("wierd1?");
}
// Capture the T0 periods that have passed since last communication or field drop (reset)
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
response = ra - HITAG_T_TAG_HALF_PERIOD;
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
// Manchester coding example |-_|_-|-_| (101)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
// Manchester coding example |_-|...|_-|-_| (0...01)
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
rxlen++;
// We have to skip this half period at start and add the 'one' the second time
if (!bSkip) {
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
rxlen++;
}
lastbit = !lastbit;
bSkip = !bSkip;
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
if (tag_sof) {
// Ignore bits that are transmitted during SOF
tag_sof--;
} else {
// bit is same as last bit
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
rxlen++;
}
} else {
// Ignore wierd value, is to small to mean anything
}
}
// We can break this loop if we received the last bit from a frame
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
if (rxlen > 0)
break;
}
}
} }
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false); set_tracing(false);
lf_finalize();
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
StartTicks();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
} }

View file

@ -1817,15 +1817,15 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
++check; ++check;
// test if the field exists // 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)) { if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_RDV40)) {
analogCnt++; analogCnt++;
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40]; analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40];
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
if (analogCnt >= 32) { if (analogCnt >= 32) {
if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { 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 #else
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) {
analogCnt++; analogCnt++;
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF]; analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF];
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
if (analogCnt >= 32) { if (analogCnt >= 32) {
if ((MAX_ADC_HF_VOLTAGE * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { if ((MAX_ADC_HF_VOLTAGE * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {

View file

@ -1291,7 +1291,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol)
cardnum = (lo >> 1) & 0x7FFFF; cardnum = (lo >> 1) & 0x7FFFF;
fac = ((hi & 0xF) << 12) | (lo >> 20); fac = ((hi & 0xF) << 12) | (lo >> 20);
} }
Dbprintf("TAG ID: " _YELLOW_("%x%08x (%d)") "- Format Len: " _YELLOW_("%d") "bit - FC: " _YELLOW_("%d") "- Card: "_YELLOW_("%d"), Dbprintf("TAG ID: " _GREEN_("%x%08x (%d)") "- Format Len: " _GREEN_("%d") "bit - FC: " _GREEN_("%d") "- Card: "_GREEN_("%d"),
hi, hi,
lo, lo,
(lo >> 1) & 0xFFFF, (lo >> 1) & 0xFFFF,
@ -2399,13 +2399,13 @@ void SendForward(uint8_t fwd_bit_count) {
TurnReadLF_off(EM_START_GAP); TurnReadLF_off(EM_START_GAP);
TurnReadLFOn(18 * 8); TurnReadLFOn(18 * 8);
// now start writting with bitbanging the antenna. // now start writting with bitbanging the antenna. (each bit should be 32*8 total length)
while (fwd_bit_sz-- > 0) { //prepare next bit modulation while (fwd_bit_sz-- > 0) { //prepare next bit modulation
if (((*fwd_write_ptr++) & 1) == 1) { if (((*fwd_write_ptr++) & 1) == 1) {
WaitUS(32 * 8); WaitUS(32 * 8);
} else { } else {
TurnReadLF_off(23 * 8); TurnReadLF_off(23 * 8);
TurnReadLFOn(18 * 8); TurnReadLFOn(32-23 * 8);
} }
} }
} }

View file

@ -117,8 +117,8 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
if (use_malloc) { if (use_malloc) {
if (sample_size == NULL || *sample_size == 0 ) { if (sample_size == NULL || *sample_size == 0) {
*sample_size = BigBuf_max_traceLen(); *sample_size = BigBuf_max_traceLen();
data.buffer = BigBuf_get_addr(); data.buffer = BigBuf_get_addr();
} else { } else {
*sample_size = MIN(*sample_size, BigBuf_max_traceLen()); *sample_size = MIN(*sample_size, BigBuf_max_traceLen());
@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
} }
} else { } else {
if (sample_size == NULL || *sample_size == 0 ) { if (sample_size == NULL || *sample_size == 0) {
*sample_size = BigBuf_max_traceLen(); *sample_size = BigBuf_max_traceLen();
} }
data.buffer = BigBuf_get_addr(); data.buffer = BigBuf_get_addr();
@ -221,7 +221,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 50ms for the resonant antenna to settle. // 50ms for the resonant antenna to settle.
if (reader_field) if (reader_field)
SpinDelay(50); SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc();

View file

@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) {
#endif #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 // Work with emulator memory
// //
@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) {
while (true) { while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, 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; break;
} }
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) { 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; break;
} }
int respLen; int respLen;
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { 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; break;
} }
if (mifare_classic_halt(pcs, cuid)) { if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= 1) Dbprintf("Halt error"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
break; break;
} }
@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) {
LED_B_ON(); LED_B_ON();
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0); reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
LED_B_OFF(); LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card?
void MifareHasStaticNonce(); // Has the tag a static nonce? void MifareHasStaticNonce(); // Has the tag a static nonce?
void MifareSetMod(uint8_t *datain); 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 MifareUSetPwd(uint8_t arg0, uint8_t *datain);
void OnSuccessMagic(); void OnSuccessMagic();
void OnErrorMagic(uint8_t reason); void OnErrorMagic(uint8_t reason);

View file

@ -14,6 +14,8 @@
#include "crc16.h" #include "crc16.h"
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include "commonutil.h" #include "commonutil.h"
#include "util.h"
#include "mifare.h"
#define MAX_APPLICATION_COUNT 28 #define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 16 #define MAX_FILE_COUNT 16
@ -31,8 +33,11 @@ static uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4};
/* PCB CID CMD PAYLOAD */ /* PCB CID CMD PAYLOAD */
//static uint8_t __res[MAX_FRAME_SIZE]; //static uint8_t __res[MAX_FRAME_SIZE];
bool InitDesfireCard() { bool InitDesfireCard() {
pcb_blocknum = 0;
iso14a_card_select_t card; iso14a_card_select_t card;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -46,28 +51,14 @@ bool InitDesfireCard() {
return true; return true;
} }
// ARG0 flag enums
enum {
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x08,
} CmdOptions ;
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
/* ARG0 contains flags.
0x01 = init card.
0x02 = Disconnect
0x03
*/
uint8_t flags = arg0; uint8_t flags = arg0;
size_t datalen = arg1; size_t datalen = arg1;
uint8_t resp[RECEIVE_SIZE]; uint8_t resp[RECEIVE_SIZE];
memset(resp, 0, sizeof(resp)); memset(resp, 0, sizeof(resp));
if (DBGLEVEL >= 4) { if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf(" flags : %02X", flags); Dbprintf(" flags : %02X", flags);
Dbprintf(" len : %02X", datalen); Dbprintf(" len : %02X", datalen);
print_result(" RX : ", datain, datalen); print_result(" RX : ", datain, datalen);
@ -77,35 +68,42 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
clear_trace(); clear_trace();
if (flags & INIT) { if (flags & INIT) {
if (!InitDesfireCard()) if (!InitDesfireCard()) {
return; return;
}
} }
int len = DesfireAPDU(datain, datalen, resp); int len = DesfireAPDU(datain, datalen, resp);
if (DBGLEVEL >= 4) if (DBGLEVEL >= DBG_EXTENDED)
print_result("ERR <--: ", resp, len); print_result("RESP <--: ", resp, len);
if (!len) { if (!len) {
OnError(2); OnError(2);
return; return;
} }
// reset the pcb_blocknum,
pcb_blocknum = 0;
if (flags & DISCONNECT) if (flags & DISCONNECT)
OnSuccess(); OnSuccess();
reply_old(CMD_ACK, 1, len, 0, resp, len); reply_mix(CMD_ACK, 1, len, 0, resp, len);
} }
void MifareDesfireGetInformation() { void MifareDesfireGetInformation() {
LEDsoff();
int len = 0; int len = 0;
iso14a_card_select_t card; iso14a_card_select_t card;
uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t dataout[PM3_CMD_DATA_SIZE] = {0x00};
struct p {
uint8_t isOK;
uint8_t uid[7];
uint8_t versionHW[7];
uint8_t versionSW[7];
uint8_t details[14];
} PACKED payload;
/* /*
1 = PCB 1 1 = PCB 1
2 = cid 2 2 = cid 2
@ -122,61 +120,65 @@ void MifareDesfireGetInformation() {
// card select - information // card select - information
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card"); if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card");
OnError(1); payload.isOK = 1; // 2 == can not select
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
switch_off();
return; return;
} }
if (card.uidlen != 7) { if (card.uidlen != 7) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen); if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
OnError(2); payload.isOK = 2; // 2 == WRONG UID
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
switch_off();
return; return;
} }
// add uid.
memcpy(dataout, card.uid, 7); memcpy(payload.uid, card.uid, sizeof(card.uid));
LED_A_ON(); LED_A_ON();
LED_B_OFF(); uint8_t cmd[] = {GET_VERSION, 0x00, 0x00, 0x00};
LED_C_OFF();
uint8_t cmd[] = {GET_VERSION};
size_t cmd_len = sizeof(cmd); size_t cmd_len = sizeof(cmd);
len = DesfireAPDU(cmd, cmd_len, resp); len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) { if (!len) {
print_result("ERROR <--: ", resp, len); print_result("ERROR <--: ", resp, len);
OnError(3); payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
switch_off();
return; return;
} }
LED_A_OFF(); memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW));
LED_B_ON();
memcpy(dataout + 7, resp + 3, 7);
// ADDITION_FRAME 1 // ADDITION_FRAME 1
cmd[0] = ADDITIONAL_FRAME; cmd[0] = ADDITIONAL_FRAME;
len = DesfireAPDU(cmd, cmd_len, resp); len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) { if (!len) {
print_result("ERROR <--: ", resp, len); print_result("ERROR <--: ", resp, len);
OnError(3); payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
switch_off();
return; return;
} }
memcpy(payload.versionSW, resp + 1, sizeof(payload.versionSW));
LED_B_OFF();
LED_C_ON();
memcpy(dataout + 7 + 7, resp + 3, 7);
// ADDITION_FRAME 2 // ADDITION_FRAME 2
len = DesfireAPDU(cmd, cmd_len, resp); len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) { if (!len) {
print_result("ERROR <--: ", resp, len); print_result("ERROR <--: ", resp, len);
OnError(3); payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
switch_off();
return; return;
} }
memcpy(dataout + 7 + 7 + 7, resp + 3, 14); memcpy(payload.details, resp + 1, sizeof(payload.details));
reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout));
LED_B_ON();
reply_ng(CMD_HF_DESFIRE_INFO, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
LED_B_OFF();
// reset the pcb_blocknum, // reset the pcb_blocknum,
pcb_blocknum = 0; pcb_blocknum = 0;
OnSuccess(); OnSuccess();
@ -467,7 +469,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// dekryptera tagnonce. // dekryptera tagnonce.
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
if (DBGLEVEL >= 4) { if (DBGLEVEL >= DBG_EXTENDED) {
DbpString("mbedtls_aes_setkey_dec failed"); DbpString("mbedtls_aes_setkey_dec failed");
} }
OnError(7); OnError(7);
@ -480,7 +482,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
memcpy(both + 16, decRndB, 16); memcpy(both + 16, decRndB, 16);
uint8_t encBoth[32] = {0x00}; uint8_t encBoth[32] = {0x00};
if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) { if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) {
if (DBGLEVEL >= 4) { if (DBGLEVEL >= DBG_EXTENDED) {
DbpString("mbedtls_aes_setkey_enc failed"); DbpString("mbedtls_aes_setkey_enc failed");
} }
OnError(7); OnError(7);
@ -517,7 +519,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
} }
OnSuccess(); OnSuccess();
reply_old(CMD_ACK, 1, len, 0, resp, len); reply_mix(CMD_ACK, 1, len, 0, resp, len);
} }
// 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO) // 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO)
@ -534,23 +536,23 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) {
wrappedLen = CreateAPDU(cmd, cmd_len, wCmd); wrappedLen = CreateAPDU(cmd, cmd_len, wCmd);
if (DBGLEVEL >= 4) if (DBGLEVEL >= DBG_EXTENDED)
print_result("WCMD <--: ", wCmd, wrappedLen); print_result("WCMD <--: ", wCmd, wrappedLen);
ReaderTransmit(wCmd, wrappedLen, NULL); ReaderTransmit(wCmd, wrappedLen, NULL);
len = ReaderReceive(resp, par); len = ReaderReceive(resp, par);
if (!len) { if (!len) {
if (DBGLEVEL >= 4) Dbprintf("fukked"); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("fukked");
return false; //DATA LINK ERROR return false; //DATA LINK ERROR
} }
// if we received an I- or R(ACK)-Block with a block number equal to the // if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number // current block number, toggle the current block number
else if (len >= 4 // PCB+CID+CRC = 4 bytes if (len >= 4 // PCB+CID+CRC = 4 bytes
&& ((resp[0] & 0xC0) == 0 // I-Block && ((resp[0] & 0xC0) == 0 // I-Block
|| (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 || (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
&& (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers && (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers
pcb_blocknum ^= 1; //toggle next block pcb_blocknum ^= 1; //toggle next block
} }
memcpy(dataout, resp, len); memcpy(dataout, resp, len);
@ -565,15 +567,22 @@ size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
uint8_t cmd[cmdlen]; uint8_t cmd[cmdlen];
memset(cmd, 0, cmdlen); memset(cmd, 0, cmdlen);
cmd[0] = 0x0A; // 0x0A = send cid, 0x02 = no cid. cmd[0] = 0x02; // 0x0A = send cid, 0x02 = no cid.
cmd[0] |= pcb_blocknum; // OR the block number into the PCB cmd[0] |= pcb_blocknum; // OR the block number into the PCB
cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("pcb_blocknum %d == %d ", pcb_blocknum, cmd[0] );
cmd[1] = 0x90; // CID: 0x00 //TODO: allow multiple selected cards
memcpy(cmd + 2, datain, len); memcpy(cmd + 2, datain, len);
AddCrc14A(cmd, len + 2); AddCrc14A(cmd, len + 2);
/*
hf 14a apdu -sk 90 60 00 00 00
hf 14a apdu -k 90 AF 00 00 00
hf 14a apdu 90AF000000
*/
memcpy(dataout, cmd, cmdlen); memcpy(dataout, cmd, cmdlen);
return cmdlen; return cmdlen;
} }

View file

@ -537,13 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
// find reader field // find reader field
if (cardSTATE == MFEMUL_NOFIELD) { if (cardSTATE == MFEMUL_NOFIELD) {
#if defined RDV4 #if defined RDV4
vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
#else #else
vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
#endif #endif
if (vHf > MF_MINFIELDV) { if (vHf > MF_MINFIELDV) {
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
LED_A_ON(); LED_A_ON();

View file

@ -13,6 +13,11 @@
#include "common.h" #include "common.h"
// PRIx64 definition missing with gcc-arm-none-eabi v8?
#ifndef PRIx64
#define PRIx64 "llx"
#endif
// Basic macros // Basic macros
#ifndef SHORT_COIL #ifndef SHORT_COIL

View file

@ -130,7 +130,7 @@ CORESRCS = uart_posix.c \
util_posix.c \ util_posix.c \
scandir.c \ scandir.c \
crc16.c \ crc16.c \
comms.c comms.c
CMDSRCS = crapto1/crapto1.c \ CMDSRCS = crapto1/crapto1.c \
crapto1/crypto1.c \ crapto1/crypto1.c \

View file

@ -315,7 +315,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
} }
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) { int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
int ret_val = PM3_SUCCESS; int ret_val = PM3_SUCCESS;
// We want to mount before multiple operation so the lazy writes/append will not // 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; bytes_sent += bytes_in_packet;
PacketResponseNG resp; PacketResponseNG resp;
uint8_t retry = 3; uint8_t retry = 3;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); 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 // 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 // unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0); SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return ret_val; return ret_val;
} }
@ -400,8 +400,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
cmdp += 2; cmdp += 2;
break; break;
case 'o': case 'o':
param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32); param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32);
if (strlen((char*)destfilename) == 0) { if (strlen((char *)destfilename) == 0) {
PrintAndLogEx(FAILED, "Destination Filename missing or invalid"); PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
errors = true; errors = true;
} }
@ -429,12 +429,12 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
} }
res = flashmem_spiffs_load(destfilename, data, datalen); res = flashmem_spiffs_load(destfilename, data, datalen);
free(data); free(data);
if ( res == PM3_SUCCESS ) if (res == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename); PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
return res; return res;
} }

View file

@ -178,7 +178,7 @@ int CmdHFTune(const char *Cmd) {
if (cmdp == 'h') return usage_hf_tune(); if (cmdp == 'h') return usage_hf_tune();
int iter = param_get32ex(Cmd, 0, 0, 10); int iter = param_get32ex(Cmd, 0, 0, 10);
PrintAndLogEx(SUCCESS, "Measuring HF antenna, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit"); PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit");
PacketResponseNG resp; PacketResponseNG resp;
clearCommandBuffer(); clearCommandBuffer();
@ -218,7 +218,7 @@ int CmdHFTune(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Done."); PrintAndLogEx(INFO, "Done.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -189,9 +189,9 @@ static int usage_hf_14a_sim(void) {
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x"));
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344556677"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); // PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n");
return 0; return 0;
} }
@ -202,7 +202,7 @@ static int usage_hf_14a_sniff(void) {
PrintAndLogEx(NORMAL, "c - triggered by first data from card"); PrintAndLogEx(NORMAL, "c - triggered by first data from card");
PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf 14a sniff c r"); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r"));
return 0; return 0;
} }
static int usage_hf_14a_raw(void) { static int usage_hf_14a_raw(void) {
@ -230,7 +230,6 @@ static int usage_hf_14a_reader(void) {
static int CmdHF14AList(const char *Cmd) { static int CmdHF14AList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead");
CmdTraceList("14a"); CmdTraceList("14a");
return 0; return 0;
} }
@ -261,7 +260,7 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
return 1; return 1;
} }
PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card->uid, card->uidlen));
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]);
if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
@ -335,17 +334,17 @@ static int CmdHF14AReader(const char *Cmd) {
if (select_status == 3) { if (select_status == 3) {
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
DropField(); DropField();
return 1; return 1;
} }
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len));
} }
if (!disconnectAfter) { if (!disconnectAfter) {
@ -354,14 +353,14 @@ static int CmdHF14AReader(const char *Cmd) {
} }
if (disconnectAfter) { if (disconnectAfter) {
if (!silent) PrintAndLogEx(SUCCESS, "field dropped."); if (!silent) PrintAndLogEx(INFO, "field dropped.");
} }
return 0; return 0;
} }
static int CmdHF14AInfo(const char *Cmd) { static int CmdHF14AInfo(const char *Cmd) {
bool verbose = false; bool verbose = true;
bool do_nack_test = false; bool do_nack_test = false;
bool do_aid_search = false; bool do_aid_search = false;
@ -467,7 +466,7 @@ int CmdHF14ASim(const char *Cmd) {
break; break;
} }
if (!errors) { if (!errors) {
PrintAndLogEx(SUCCESS, "Emulating ISO/IEC 14443 type A tag with %d byte UID (%s)", uidlen, sprint_hex(uid, uidlen)); PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")"with " _GREEN_("%d byte UID (%s)"), uidlen, sprint_hex(uid, uidlen));
useUIDfromEML = false; useUIDfromEML = false;
} }
cmdp += 2; cmdp += 2;
@ -485,7 +484,7 @@ int CmdHF14ASim(const char *Cmd) {
cmdp++; cmdp++;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -511,7 +510,7 @@ int CmdHF14ASim(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp; PacketResponseNG resp;
PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
bool keypress = kbd_enter_pressed(); bool keypress = kbd_enter_pressed();
while (!keypress) { while (!keypress) {
@ -1276,16 +1275,24 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (select_status == 3) { if (select_status == 3) {
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
DropField(); DropField();
return select_status; return select_status;
} }
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); if (verbose) {
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "-- ISO14443-a Information -----------------------------------");
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, "-------------------------------------------------------------");
}
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
bool isMifareClassic = true; bool isMifareClassic = true;
bool isMifareDesfire = false;
bool isMifarePlus = false;
bool isMifareUltralight = false;
switch (card.sak) { switch (card.sak) {
case 0x00: case 0x00:
isMifareClassic = false; isMifareClassic = false;
@ -1294,10 +1301,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
DropField(); DropField();
uint32_t tagT = GetHF14AMfU_Type(); uint32_t tagT = GetHF14AMfU_Type();
if (tagT != UL_ERROR) if (tagT != UL_ERROR) {
ul_print_type(tagT, 0); ul_print_type(tagT, 0);
else isMifareUltralight = true;
} else {
PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)"); PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)");
}
// reconnect for further tests // reconnect for further tests
clearCommandBuffer(); clearCommandBuffer();
@ -1314,49 +1323,55 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
break; break;
case 0x01: case 0x01:
PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP TNP3xxx Activision Game Appliance"));
break; break;
case 0x04: case 0x04:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE (various !DESFire !DESFire EV1)"));
isMifareClassic = false; isMifareClassic = false;
isMifareDesfire = true;
break; break;
case 0x08: case 0x08:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"));
break; break;
case 0x09: case 0x09:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Mini 0.3k"));
break; break;
case 0x0A: case 0x0A:
PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("FM11RF005SH (Shanghai Metro)"));
break; break;
case 0x10: case 0x10:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 2k SL2"));
isMifarePlus = true;
break; break;
case 0x11: case 0x11:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 4k SL2"));
isMifarePlus = true;
break; break;
case 0x18: case 0x18:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"));
break; break;
case 0x20: case 0x20:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"));
isMifareClassic = false; isMifareClassic = false;
isMifareDesfire = true;
isMifarePlus = true;
break; break;
case 0x24: case 0x24:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire | DESFire EV1"));
isMifareClassic = false; isMifareClassic = false;
isMifareDesfire = true;
break; break;
case 0x28: case 0x28:
PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("JCOP31 or JCOP41 v2.3.1"));
break; break;
case 0x38: case 0x38:
PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Nokia 6212 or 6131 MIFARE CLASSIC 4K"));
break; break;
case 0x88: case 0x88:
PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Infineon MIFARE CLASSIC 1K"));
break; break;
case 0x98: case 0x98:
PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS"); PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Gemplus MPCOS"));
break; break;
default: default:
; ;
@ -1364,7 +1379,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
// Double & triple sized UID, can be mapped to a manufacturer. // Double & triple sized UID, can be mapped to a manufacturer.
if (card.uidlen > 4) { if (card.uidlen > 4) {
PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0])); PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
} }
// try to request ATS even if tag claims not to support it // try to request ATS even if tag claims not to support it
@ -1385,7 +1400,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (select_status == 2) { if (select_status == 2) {
PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS"); PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS");
} }
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card.ats, card.ats_len));
PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]); PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
if (card.ats[0] != card.ats_len - 2) { if (card.ats[0] != card.ats_len - 2) {
PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
@ -1461,9 +1476,15 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
switch (card.ats[pos + 2] & 0xf0) { switch (card.ats[pos + 2] & 0xf0) {
case 0x10: case 0x10:
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
isMifareDesfire = true;
isMifareClassic = false;
isMifarePlus = false;
break; break;
case 0x20: case 0x20:
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
isMifarePlus = true;
isMifareDesfire = false;
isMifareClassic = false;
break; break;
} }
switch (card.ats[pos + 2] & 0x0f) { switch (card.ats[pos + 2] & 0x0f) {
@ -1590,22 +1611,32 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (isMifareClassic) { if (isMifareClassic) {
int res = detect_classic_prng(); int res = detect_classic_prng();
if (res == 1) if (res == 1)
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("WEAK")); PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak"));
else if (res == 0) else if (res == 0)
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("HARD")); PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
else else
PrintAndLogEx(FAILED, "prng detection: " _RED_("Fail")); PrintAndLogEx(FAILED, "prng detection: " _RED_("fail"));
if (do_nack_test) if (do_nack_test)
detect_classic_nackbug(!verbose); detect_classic_nackbug(false);
res = detect_classic_static_nonce(); res = detect_classic_static_nonce();
if (res == 1) if (res == 1)
PrintAndLogEx(SUCCESS, "Static nonce detected"); PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes") );
if (res == 2 && verbose) if (res == 2 && verbose)
PrintAndLogEx(SUCCESS, "Static nonce detection failed"); PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail"));
} }
if (isMifareUltralight) {
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`"));
}
if (isMifarePlus) {
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`"));
}
if (isMifareDesfire) {
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
}
return select_status; return select_status;
} }

View file

@ -1142,4 +1142,3 @@ int readHF14B(bool verbose) {
if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found");
return 0; return 0;
} }

View file

@ -785,7 +785,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
return usage_hf_iclass_decrypt(); return usage_hf_iclass_decrypt();
case 'd': case 'd':
if (param_gethex(Cmd, cmdp + 1, enc_data, 16)) { if (param_gethex(Cmd, cmdp + 1, enc_data, 16)) {
PrintAndLogEx(ERR, "data must be 16 HEX symbols"); PrintAndLogEx(ERR, "Data must be 16 HEX symbols");
errors = true; errors = true;
break; break;
} }
@ -794,7 +794,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
break; break;
case 'f': case 'f':
if (param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)) == 0) { if (param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)) == 0) {
PrintAndLogEx(WARNING, "no filename found after f"); PrintAndLogEx(WARNING, "No filename found after f");
errors = true; errors = true;
break; break;
} }
@ -861,21 +861,27 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
getMemConfig(mem, chip, &max_blk, &app_areas, &kb); getMemConfig(mem, chip, &max_blk, &app_areas, &kb);
uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t empty[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03); BLOCK79ENCRYPTION aa1_encryption = (decrypted[(6 * 8) + 7] & 0x03);
for (uint16_t blocknum = 0; blocknum < applimit; ++blocknum) { uint32_t limit = MIN(applimit, decryptedlen / 8);
if (decryptedlen / 8 != applimit) {
PrintAndLogEx(WARNING, "Actual file len " _YELLOW_("%u") "vs HID app-limit len " _YELLOW_("%u"), decryptedlen, applimit * 8);
PrintAndLogEx(INFO, "Setting limit to " _GREEN_("%u"), limit * 8);
}
uint8_t numblocks4userid = GetNumberBlocksForUserId(decrypted + (6 * 8));
for (uint16_t blocknum = 0; blocknum < limit; ++blocknum) {
uint8_t idx = blocknum * 8; uint8_t idx = blocknum * 8;
memcpy(enc_data, decrypted + idx, 8); memcpy(enc_data, decrypted + idx, 8);
// block 7 or higher, and not empty 0xFF if (aa1_encryption == RFU || aa1_encryption == None)
// look inside block 6 to determine if aa1 is encrypted. continue;
if (blocknum > 6 && memcmp(enc_data, empty, 8) != 0) {
// Decrypted block 7,8,9 if configured.
if (aa1_encryption == RFU || aa1_encryption == None) if (blocknum > 6 && blocknum <= 6 + numblocks4userid && memcmp(enc_data, empty, 8) != 0) {
continue;
if (use_sc) { if (use_sc) {
Decrypt(enc_data, decrypted + idx); Decrypt(enc_data, decrypted + idx);
} else { } else {
@ -885,7 +891,12 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
} }
//Use the first block (CSN) for filename //Use the first block (CSN) for filename
char *fptr = calloc(42, sizeof(uint8_t)); char *fptr = calloc(50, sizeof(uint8_t));
if (!fptr) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
free(decrypted);
return PM3_EMALLOC;
}
strcat(fptr, "hf-iclass-"); strcat(fptr, "hf-iclass-");
FillFileNameByUID(fptr, hdr->csn, "-data-decrypted", sizeof(hdr->csn)); FillFileNameByUID(fptr, hdr->csn, "-data-decrypted", sizeof(hdr->csn));
@ -893,37 +904,37 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
saveFileEML(fptr, decrypted, decryptedlen, 8); saveFileEML(fptr, decrypted, decryptedlen, 8);
saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen); saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen);
PrintAndLogEx(INFO, "Following output skips CSN / block0");
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen);
// decode block 6 // decode block 6
if (memcmp(decrypted + (8*6), empty, 8) != 0 ) { if (memcmp(decrypted + (8 * 6), empty, 8) != 0) {
if (use_sc) { if (use_sc) {
DecodeBlock6(decrypted + (8*6)); DecodeBlock6(decrypted + (8 * 6));
} }
} }
// decode block 7-8-9 // decode block 7-8-9
if (memcmp(decrypted + (8*7), empty, 8) != 0 ) { if (memcmp(decrypted + (8 * 7), empty, 8) != 0) {
//todo: remove preamble/sentinal //todo: remove preamble/sentinal
uint32_t top = 0, mid, bot; uint32_t top = 0, mid, bot;
mid = bytes_to_num(decrypted + (8*7), 4); mid = bytes_to_num(decrypted + (8 * 7), 4);
bot = bytes_to_num(decrypted + (8*7) + 4, 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}; char hexstr[8 + 1] = {0};
hex_to_buffer((uint8_t *)hexstr, decrypted + (8*7), 8, sizeof(hexstr) - 1, 0, 0, true); hex_to_buffer((uint8_t *)hexstr, decrypted + (8 * 7), 8, sizeof(hexstr) - 1, 0, 0, true);
char binstr[8*8+1] = {0}; char binstr[8 * 8 + 1] = {0};
hextobinstring(binstr, hexstr); hextobinstring(binstr, hexstr);
uint8_t i=0; uint8_t i = 0;
while (i<strlen(binstr) && binstr[i++] == '0'); while (i < strlen(binstr) && binstr[i++] == '0');
PrintAndLogEx(SUCCESS, "%s", binstr + i); PrintAndLogEx(SUCCESS, "%s", binstr + i);
PrintAndLogEx(INFO, "Wiegand decode"); PrintAndLogEx(INFO, "Wiegand decode");
wiegand_message_t packed = initialize_message_object(top, mid, bot); wiegand_message_t packed = initialize_message_object(top, mid, bot);
HIDTryUnpack(&packed, true); HIDTryUnpack(&packed, true);
@ -931,7 +942,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
} else { } else {
PrintAndLogEx(INFO, "No credential found."); PrintAndLogEx(INFO, "No credential found.");
} }
free(decrypted); free(decrypted);
free(fptr); free(fptr);
} }
@ -1251,7 +1262,7 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
if (kbd_enter_pressed()) { if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\n[!] aborted via keyboard!\n"); PrintAndLogEx(WARNING, "\n[!] aborted via keyboard!\n");
DropField(); DropField();
return 0; return PM3_EOPABORTED;
} }
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) if (WaitForResponseTimeout(CMD_ACK, &resp, 2000))
@ -1343,8 +1354,8 @@ static int CmdHFiClassReader_Dump(const char *Cmd) {
// print the dump // print the dump
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "------+--+-------------------------+"); PrintAndLogEx(INFO, "------+--+-------------------------+");
PrintAndLogEx(NORMAL, "CSN |00| %s|", sprint_hex(tag_data, 8)); PrintAndLogEx(INFO, "CSN |00| %s|", sprint_hex(tag_data, 8));
printIclassDumpContents(tag_data, 1, (gotBytes / 8), gotBytes); printIclassDumpContents(tag_data, 1, (gotBytes / 8), gotBytes);
if (filename[0] == 0) { if (filename[0] == 0) {
@ -1757,7 +1768,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))); PrintAndLogEx(SUCCESS, "block %02X: %s\n", blockno, sprint_hex(result->blockdata, sizeof(result->blockdata)));
if (blockno == 6) { if (blockno == 6) {
if (IsCryptoHelperPresent()) { if (IsCryptoHelperPresent()) {
DecodeBlock6(result->blockdata); DecodeBlock6(result->blockdata);

View file

@ -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; uint16_t resp_len = 18;
uint8_t rdbl_cmd[] = {0x30, blk}; 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); 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 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); 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 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_d16_d31[18];
uint8_t block_data[32]; 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); 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': case 'h':
return usage_lto_rdbl(); return usage_lto_rdbl();
case 's': case 's':
st_blk = param_get8(Cmd, cmdp+1); st_blk = param_get8(Cmd, cmdp + 1);
if ( end_blk < st_blk ) { if (end_blk < st_blk) {
errors = true; errors = true;
break; break;
} }
@ -295,10 +295,11 @@ static int CmdHfLTOReadBlock(const char *Cmd) {
break; break;
case 'e': case 'e':
end_blk = param_get8(Cmd, cmdp+1); end_blk = param_get8(Cmd, cmdp + 1);
if ( end_blk < st_blk ) { if (end_blk < st_blk) {
errors = true; errors = true;
break; } break;
}
cmdp += 2; cmdp += 2;
break; break;
@ -328,7 +329,7 @@ static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
wrbl_d00_d15[i] = data[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); 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': case 'h':
return usage_lto_wrbl(); return usage_lto_wrbl();
case 'b': case 'b':
blk = param_get8(Cmd, cmdp+1); blk = param_get8(Cmd, cmdp + 1);
b_opt_selected = true; b_opt_selected = true;
cmdp += 2; cmdp += 2;
break; break;
case 'd': 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"); PrintAndLogEx(WARNING, "block data must include 64 HEX symbols");
errors = true; errors = true;
break; break;
} }
d_opt_selected = true; d_opt_selected = true;
cmdp += 2; cmdp += 2;
@ -409,7 +410,7 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
break; break;
} }
} }
//Validations //Validations
if (errors) { if (errors) {
usage_lto_wrbl(); 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_d00_d15[18];
uint8_t block_data_d16_d31[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); 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); int ret_val = dumpLTO(dump, true);
if (ret_val != PM3_SUCCESS) { if (ret_val != PM3_SUCCESS) {
free(dump); free(dump);
return ret_val; return ret_val;
} }
// save to file // save to file
if (filename[0] == '\0') { if (filename[0] == '\0') {
memcpy(serial_number, sprint_hex_inrow(dump, sizeof(serial_number)), sizeof(serial_number)); memcpy(serial_number, sprint_hex_inrow(dump, sizeof(serial_number)), sizeof(serial_number));
char tmp_name[17] = "hf_lto_"; char tmp_name[17] = "hf_lto_";
@ -523,7 +524,7 @@ static int CmdHfLTODump(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int restoreLTO(uint8_t *dump_data, bool verbose) { int restoreLTO(uint8_t *dump, bool verbose) {
clearCommandBuffer(); clearCommandBuffer();
lto_switch_on_field(); lto_switch_on_field();
@ -538,19 +539,19 @@ int restoreLTO(uint8_t *dump_data, bool verbose) {
return ret_val; return ret_val;
} }
uint8_t blkData[32] = {0}; uint8_t blkData[32] = {0};
//Block address 0 and 1 are read-only //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++) { for (int i = 0; i < 32; i++) {
blkData[i] = dump_data[i + blk * 32]; blkData[i] = dump[i + blk * 32];
} }
ret_val = lto_wrbl(blk, blkData, verbose); ret_val = lto_wrbl(blk, blkData, verbose);
if (ret_val == PM3_SUCCESS) { if (ret_val == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk); PrintAndLogEx(SUCCESS, "Block %03d - " _YELLOW_("write success"), blk);
} else { } else {
lto_switch_off_field(); lto_switch_off_field();
return ret_val; return ret_val;
@ -566,7 +567,7 @@ static int CmdHfLTRestore(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = false; bool errors = false;
int is_data_loaded = PM3_ESOFT; int is_data_loaded = PM3_ESOFT;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
char extension[FILE_PATH_SIZE] = {0}; char extension[FILE_PATH_SIZE] = {0};
@ -623,7 +624,7 @@ static int CmdHfLTRestore(const char *Cmd) {
} else { } else {
return PM3_EFILE; return PM3_EFILE;
} }
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {

View file

@ -3129,7 +3129,7 @@ out:
} }
sector_t *k_sector = NULL; sector_t *k_sector = NULL;
uint8_t k_sectorsCount = 16; uint8_t k_sectorsCount = 40;
void showSectorTable() { void showSectorTable() {
if (k_sector != NULL) { if (k_sector != NULL) {
@ -4798,6 +4798,95 @@ static int CmdHFMFNDEF(const char *Cmd) {
return PM3_SUCCESS; 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) { static int CmdHF14AMfList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
return CmdTraceList("mf"); return CmdTraceList("mf");
@ -4845,7 +4934,7 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, IfPm3Iso14443a, ""}, {"-----------", CmdHelp, IfPm3Iso14443a, ""},
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {"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"}, {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -17,6 +17,9 @@
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "mbedtls/des.h" #include "mbedtls/des.h"
#include "crypto/libpcrypto.h"
#include "protocols.h"
#include "mifare.h" // desfire raw command options
uint8_t key_zero_data[16] = { 0x00 }; uint8_t key_zero_data[16] = { 0x00 };
uint8_t key_ones_data[16] = { 0x01 }; uint8_t key_ones_data[16] = { 0x01 };
@ -25,19 +28,339 @@ uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
//ICEMAN: Turn on field method?
//none
static int test_desfire_authenticate() {
uint8_t c[] = {AUTHENTICATE, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x0A, KEY 0
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
DropField();
return PM3_ETIMEOUT;
}
if (resp.length == 13)
return PM3_SUCCESS;
return PM3_ESOFT;
}
// none
static int test_desfire_authenticate_iso() {
uint8_t c[] = {AUTHENTICATE_ISO, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x1A, KEY 0
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
DropField();
return PM3_ETIMEOUT;
}
if (resp.length >= 13)
return PM3_SUCCESS;
return PM3_ESOFT;
}
//none
static int test_desfire_authenticate_aes() {
uint8_t c[] = {AUTHENTICATE_AES, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0xAA, KEY 0
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {
DropField();
return PM3_ETIMEOUT;
}
if (resp.length >= 13)
return PM3_SUCCESS;
return PM3_ESOFT;
}
// --- FREE MEM
static int desfire_print_freemem(uint32_t free_mem) {
PrintAndLogEx(SUCCESS, " Available free memory on card : " _GREEN_("%d bytes"), free_mem);
return PM3_SUCCESS;
}
// init / disconnect
static int get_desfire_freemem(uint32_t *free_mem) {
uint8_t c[] = {GET_FREE_MEMORY, 0x00, 0x00, 0x00}; // 0x6E
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return PM3_ETIMEOUT;
}
if (resp.length == 8) {
*free_mem = le24toh(resp.data.asBytes + 1);
return PM3_SUCCESS;
}
*free_mem = 0;
return PM3_ESOFT;
}
// --- GET SIGNATURE
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len) {
#define PUBLIC_DESFIRE_ECDA_KEYLEN 57
// ref: MIFARE Desfire Originality Signature Validation
uint8_t nxp_desfire_keys[1][PUBLIC_DESFIRE_ECDA_KEYLEN] = {
// DESFire Light
{
0x04, 0x0E, 0x98, 0xE1, 0x17, 0xAA, 0xA3, 0x64,
0x57, 0xF4, 0x31, 0x73, 0xDC, 0x92, 0x0A, 0x87,
0x57, 0x26, 0x7F, 0x44, 0xCE, 0x4E, 0xC5, 0xAD,
0xD3, 0xC5, 0x40, 0x75, 0x57, 0x1A, 0xEB, 0xBF,
0x7B, 0x94, 0x2A, 0x97, 0x74, 0xA1, 0xD9, 0x4A,
0xD0, 0x25, 0x72, 0x42, 0x7E, 0x5A, 0xE0, 0xA2,
0xDD, 0x36, 0x59, 0x1B, 0x1F, 0xB3, 0x4F, 0xCF, 0x3D
}
// DESFire Ev2
};
uint8_t public_key = 0;
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, nxp_desfire_keys[public_key], uid, 7, signature, signature_len, false);
bool is_valid = (res == 0);
PrintAndLogEx(INFO, " Tag Signature");
PrintAndLogEx(INFO, " IC signature public key name : NXP DESFire Light");
PrintAndLogEx(INFO, " IC signature public key value : %s", sprint_hex(nxp_desfire_keys[public_key], 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(nxp_desfire_keys[public_key] + 48, PUBLIC_DESFIRE_ECDA_KEYLEN - 48));
PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp224r1");
PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 16, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 32, 16));
PrintAndLogEx(INFO, " : %s", sprint_hex(signature + 48, signature_len - 48));
PrintAndLogEx( (is_valid) ? SUCCESS : WARNING, " Signature verified %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
PrintAndLogEx(INFO, "-------------------------------------------------------------");
return PM3_SUCCESS;
}
// init / disconnect
static int get_desfire_signature(uint8_t *signature, size_t *signature_len) {
uint8_t c[] = {MFDES_READSIG, 0x00, 0x00, 0x01, 0x00, 0x00}; // 0x3C
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500))
return PM3_ETIMEOUT;
if (resp.length == 61) {
memcpy(signature, resp.data.asBytes + 1, 56);
*signature_len = 56;
return PM3_SUCCESS;
} else {
*signature_len = 0;
return PM3_ESOFT;
}
}
// --- KEY SETTING
static int desfire_print_keysetting(uint8_t key_settings, uint8_t num_keys) {
PrintAndLogEx(SUCCESS, " AID Key settings : %02x", key_settings);
PrintAndLogEx(SUCCESS, " Max number of keys in AID : %d", num_keys);
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(SUCCESS, " Changekey Access rights");
// Access rights.
uint8_t rights = (key_settings >> 4 & 0x0F);
switch (rights) {
case 0x0:
PrintAndLogEx(SUCCESS, " -- AMK authentication is necessary to change any key (default)");
break;
case 0xE:
PrintAndLogEx(SUCCESS, " -- Authentication with the key to be changed (same KeyNo) is necessary to change a key");
break;
case 0xF:
PrintAndLogEx(SUCCESS, " -- All keys (except AMK,see Bit0) within this application are frozen");
break;
default:
PrintAndLogEx(SUCCESS, " -- Authentication with the specified key is necessary to change any key.\nA change key and a PICC master key (CMK) can only be changed after authentication with the master key.\nFor keys other then the master or change key, an authentication with the same key is needed.");
break;
}
PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_settings & (1 << 3)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x04] AMK required for create/delete : %s", (key_settings & (1 << 2)) ? "NO" : "YES");
PrintAndLogEx(SUCCESS, " [0x02] Directory list access with AMK : %s", (key_settings & (1 << 1)) ? "NO" : "YES");
PrintAndLogEx(SUCCESS, " [0x01] AMK is changeable : %s", (key_settings & (1 << 0)) ? _GREEN_("YES") : "NO");
return PM3_SUCCESS;
}
// none
static int get_desfire_keysettings(uint8_t *key_settings, uint8_t *num_keys) {
PacketResponseNG resp;
uint8_t c[] = {MFDES_GET_KEY_SETTINGS, 0x00, 0x00, 0x00}; // 0x45
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, _RED_(" Timed-out"));
return PM3_ETIMEOUT;
}
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (isOK == false) {
return PM3_ESOFT;
}
if (resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0xae) {
PrintAndLogEx(WARNING, _RED_(" authentication error"));
return PM3_ESOFT;
}
// PrintAndLogEx(INFO, "ICE: KEYSETTING resp :: %s", sprint_hex(resp.data.asBytes, resp.length));
*key_settings = resp.data.asBytes[1];
*num_keys = resp.data.asBytes[2];
return PM3_SUCCESS;
}
// --- KEY VERSION
static int desfire_print_keyversion(uint8_t key_idx, uint8_t key_version) {
PrintAndLogEx(SUCCESS, " Key [%u] Version : %d (0x%02x)", key_idx, key_version, key_version);
return PM3_SUCCESS;
}
// none
static int get_desfire_keyversion(uint8_t curr_key, uint8_t *num_versions) {
PacketResponseNG resp;
uint8_t c[] = {MFDES_GET_KEY_VERSION, 0x00, 0x00, 0x01, curr_key, 0x00}; // 0x64
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, _RED_(" Timed-out"));
return PM3_ETIMEOUT;
}
uint8_t isOK = resp.oldarg[0] & 0xFF;
if (isOK == false) {
return PM3_ESOFT;
}
if ( resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0x40) {
return PM3_ESOFT;
}
*num_versions = resp.data.asBytes[1];
return PM3_SUCCESS;
}
// init
static int get_desfire_select_application(uint8_t *aid) {
if (aid == NULL) return PM3_ESOFT;
uint8_t c[] = {SELECT_APPLICATION, 0x00, 0x00, 0x03, aid[0], aid[1], aid[2], 0x00}; // 0x5a
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
PrintAndLogEx(WARNING, _RED_(" timed-out"));
return PM3_ETIMEOUT;
}
uint8_t isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't select AID: " _RED_("%s"), sprint_hex(aid, 3));
return PM3_ESOFT;
}
if (resp.data.asBytes[1] == 0x91 && resp.data.asBytes[2] == 0x00) {
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
// init / disconnect
static int get_desfire_appids(uint8_t *dest, uint8_t *app_ids_len) {
uint8_t c[] = {GET_APPLICATION_IDS, 0x00, 0x00, 0x00}; //0x6a
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE | DISCONNECT , sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return PM3_ETIMEOUT;
}
uint8_t isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
return PM3_ESOFT;
}
*app_ids_len = resp.length - 5;
// resp.length - 2crc, 2status, 1pcb...
memcpy(dest, resp.data.asBytes + 1, *app_ids_len);
if (resp.data.asBytes[resp.length - 3] == MFDES_ADDITIONAL_FRAME) {
c[0] = MFDES_ADDITIONAL_FRAME; //0xAF
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return PM3_ETIMEOUT;
}
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
return PM3_ESOFT;
}
memcpy(dest + *app_ids_len, resp.data.asBytes + 1, resp.length - 5);
*app_ids_len += (resp.length - 5);
}
return PM3_SUCCESS;
}
// none
static int get_desfire_fileids(uint8_t *dest, uint8_t *file_ids_len) {
uint8_t c[] = {MFDES_GET_FILE_IDS, 0x00, 0x00, 0x00}; // 0x6f
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(c), 0, c, sizeof(c));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, _RED_(" Timed-out"));
return PM3_ETIMEOUT;
}
uint8_t isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
return PM3_ESOFT;
}
if (resp.data.asBytes[resp.length - 4] == 0x91 && resp.data.asBytes[resp.length - 3] == 0x00) {
*file_ids_len = resp.length - 5;
memcpy(dest, resp.data.asBytes + 1, *file_ids_len);
return PM3_SUCCESS;
}
return PM3_ESOFT;
}
static int CmdHF14ADesInfo(const char *Cmd) { static int CmdHF14ADesInfo(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0); SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500)) {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
DropField();
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
uint8_t isOK = resp.oldarg[0] & 0xff;
if (!isOK) { struct p {
switch (resp.oldarg[1]) { uint8_t isOK;
uint8_t uid[7];
uint8_t versionHW[7];
uint8_t versionSW[7];
uint8_t details[14];
} PACKED;
struct p *package = (struct p *) resp.data.asBytes;
if (resp.status != PM3_SUCCESS) {
switch (package->isOK) {
case 1: case 1:
PrintAndLogEx(WARNING, "Can't select card"); PrintAndLogEx(WARNING, "Can't select card");
break; break;
@ -46,49 +369,77 @@ static int CmdHF14ADesInfo(const char *Cmd) {
break; break;
case 3: case 3:
default: default:
PrintAndLogEx(WARNING, "Command unsuccessful"); PrintAndLogEx(WARNING, _RED_("Command unsuccessful"));
break; break;
} }
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------"); PrintAndLogEx(INFO, "-- Mifare DESFire Tag Information ---------------------------");
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(resp.data.asBytes, 7)); PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(package->uid, sizeof(package->uid)));
PrintAndLogEx(NORMAL, " Batch number : %s", sprint_hex(resp.data.asBytes + 28, 5)); PrintAndLogEx(SUCCESS, " Batch number : " _GREEN_("%s"), sprint_hex(package->details + 7, 5));
PrintAndLogEx(NORMAL, " Production date : week %02x, 20%02x", resp.data.asBytes[33], resp.data.asBytes[34]); PrintAndLogEx(SUCCESS, " Production date : week " _GREEN_("%02x") "/ " _GREEN_("20%02x"), package->details[12], package->details[13]);
PrintAndLogEx(NORMAL, " -----------------------------------------------------------"); PrintAndLogEx(INFO, " -----------------------------------------------------------");
PrintAndLogEx(NORMAL, " Hardware Information"); PrintAndLogEx(INFO, " Hardware Information");
PrintAndLogEx(NORMAL, " Vendor Id : %s", getTagInfo(resp.data.asBytes[7])); PrintAndLogEx(SUCCESS, " Vendor Id : " _YELLOW_("%s"), getTagInfo(package->versionHW[0]));
PrintAndLogEx(NORMAL, " Type : 0x%02X", resp.data.asBytes[8]); PrintAndLogEx(SUCCESS, " Type : " _YELLOW_("0x%02X"), package->versionHW[1]);
PrintAndLogEx(NORMAL, " Subtype : 0x%02X", resp.data.asBytes[9]); PrintAndLogEx(SUCCESS, " Subtype : " _YELLOW_("0x%02X"), package->versionHW[2]);
PrintAndLogEx(NORMAL, " Version : %s", getVersionStr(resp.data.asBytes[10], resp.data.asBytes[11])); PrintAndLogEx(SUCCESS, " Version : %s", getVersionStr(package->versionHW[3], package->versionHW[4]));
PrintAndLogEx(NORMAL, " Storage size : %s", getCardSizeStr(resp.data.asBytes[12])); PrintAndLogEx(SUCCESS, " Storage size : %s", getCardSizeStr(package->versionHW[5]));
PrintAndLogEx(NORMAL, " Protocol : %s", getProtocolStr(resp.data.asBytes[13])); PrintAndLogEx(SUCCESS, " Protocol : %s", getProtocolStr(package->versionHW[6]));
PrintAndLogEx(NORMAL, " -----------------------------------------------------------"); PrintAndLogEx(INFO, " -----------------------------------------------------------");
PrintAndLogEx(NORMAL, " Software Information"); PrintAndLogEx(INFO, " Software Information");
PrintAndLogEx(NORMAL, " Vendor Id : %s", getTagInfo(resp.data.asBytes[14])); PrintAndLogEx(SUCCESS, " Vendor Id : " _YELLOW_("%s"), getTagInfo(package->versionSW[0]));
PrintAndLogEx(NORMAL, " Type : 0x%02X", resp.data.asBytes[15]); PrintAndLogEx(SUCCESS, " Type : " _YELLOW_("0x%02X"), package->versionSW[1]);
PrintAndLogEx(NORMAL, " Subtype : 0x%02X", resp.data.asBytes[16]); PrintAndLogEx(SUCCESS, " Subtype : " _YELLOW_("0x%02X"), package->versionSW[2]);
PrintAndLogEx(NORMAL, " Version : %d.%d", resp.data.asBytes[17], resp.data.asBytes[18]); PrintAndLogEx(SUCCESS, " Version : " _YELLOW_("%d.%d"), package->versionSW[3], package->versionSW[4]);
PrintAndLogEx(NORMAL, " storage size : %s", getCardSizeStr(resp.data.asBytes[19])); PrintAndLogEx(SUCCESS, " storage size : %s", getCardSizeStr(package->versionSW[5]));
PrintAndLogEx(NORMAL, " Protocol : %s", getProtocolStr(resp.data.asBytes[20])); PrintAndLogEx(SUCCESS, " Protocol : %s", getProtocolStr(package->versionSW[6]));
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, "Card capabilities");
uint8_t major = package->versionSW[3];
uint8_t minor = package->versionSW[4];
if (major == 0 && minor == 4)
PrintAndLogEx(INFO, "\t0.4 - DESFire MF3ICD40, No support for APDU (only native commands)");
if (major == 0 && minor == 5)
PrintAndLogEx(INFO, "\t0.5 - DESFire MF3ICD40, Support for wrapping commands inside ISO 7816 style APDUs");
if (major == 0 && minor == 6)
PrintAndLogEx(INFO, "\t0.6 - DESFire MF3ICD40, Add ISO/IEC 7816 command set compatibility");
if (major == 1 && minor == 3)
PrintAndLogEx(INFO, "\t1.3 - DESFire Ev1, Support extended APDU commands");
if (major == 1 && minor == 4)
PrintAndLogEx(INFO, "\t1.4 - DESFire Ev1, N/A information about this version. report to iceman!");
if (major == 2 && minor == 0)
PrintAndLogEx(INFO, "\t2.0 - DESFire Ev2, Originality check, proximity check");
if (major == 0 && minor == 2)
PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, ");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
// Signature originality check
uint8_t signature[56] = {0};
size_t signature_len = 0;
if (get_desfire_signature(signature, &signature_len) == PM3_SUCCESS)
desfire_print_signature(package->uid, signature, signature_len);
// Master Key settings // Master Key settings
getKeySettings(NULL); uint8_t master_aid[3] = {0x00, 0x00, 0x00};
getKeySettings(master_aid);
// Free memory on card // Free memory on card
uint8_t data[1] = {GET_FREE_MEMORY}; PrintAndLogEx(INFO, " Free memory");
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data)); uint32_t free_mem = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) if (get_desfire_freemem(&free_mem) == PM3_SUCCESS) {
return PM3_ETIMEOUT; desfire_print_freemem(free_mem);
} else {
uint8_t tmp[3]; PrintAndLogEx(SUCCESS, " Card doesn't support 'free mem' cmd");
memcpy(tmp, resp.data.asBytes + 3, 3); }
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(NORMAL, " Available free memory on card : %d bytes", le24toh(tmp));
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
/* /*
Card Master key (CMK) 0x00 AID = 00 00 00 (card level) Card Master key (CMK) 0x00 AID = 00 00 00 (card level)
@ -105,6 +456,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
*/ */
DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -116,7 +468,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
*/ */
char *getCardSizeStr(uint8_t fsize) { char *getCardSizeStr(uint8_t fsize) {
static char buf[30] = {0x00}; static char buf[40] = {0x00};
char *retStr = buf; char *retStr = buf;
uint16_t usize = 1 << ((fsize >> 1) + 1); uint16_t usize = 1 << ((fsize >> 1) + 1);
@ -124,37 +476,39 @@ char *getCardSizeStr(uint8_t fsize) {
// is LSB set? // is LSB set?
if (fsize & 1) if (fsize & 1)
sprintf(retStr, "0x%02X (%d - %d bytes)", fsize, usize, lsize); sprintf(retStr, "0x%02X ( " _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize);
else else
sprintf(retStr, "0x%02X (%d bytes)", fsize, lsize); sprintf(retStr, "0x%02X ( " _YELLOW_("%d bytes") ")", fsize, lsize);
return buf; return buf;
} }
char *getProtocolStr(uint8_t id) { char *getProtocolStr(uint8_t id) {
static char buf[30] = {0x00}; static char buf[40] = {0x00};
char *retStr = buf; char *retStr = buf;
if (id == 0x05) if (id == 0x05)
sprintf(retStr, "0x%02X (ISO 14443-3, 14443-4)", id); sprintf(retStr, "0x%02X ( " _YELLOW_("ISO 14443-3, 14443-4") ")", id);
else else
sprintf(retStr, "0x%02X (Unknown)", id); sprintf(retStr, "0x%02X ( " _YELLOW_("Unknown") ")", id);
return buf; return buf;
} }
char *getVersionStr(uint8_t major, uint8_t minor) { char *getVersionStr(uint8_t major, uint8_t minor) {
static char buf[30] = {0x00}; static char buf[40] = {0x00};
char *retStr = buf; char *retStr = buf;
if (major == 0x00) if (major == 0x00)
sprintf(retStr, "%d.%d (Desfire MF3ICD40)", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire MF3ICD40") ")", major, minor);
else if (major == 0x01 && minor == 0x00) else if (major == 0x01 && minor == 0x00)
sprintf(retStr, "%d.%d (Desfire EV1)", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV1") ")", major, minor);
else if (major == 0x12 && minor == 0x00) else if (major == 0x12 && minor == 0x00)
sprintf(retStr, "%d.%d (Desfire EV2)", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire EV2") ")", major, minor);
else if (major == 0x30 && minor == 0x00)
sprintf(retStr, "%x.%x ( " _YELLOW_("DESFire Light") ")", major, minor);
else else
sprintf(retStr, "%d.%d (Unknown)", major, minor); sprintf(retStr, "%x.%x ( " _YELLOW_("Unknown") ")", major, minor);
return buf; return buf;
} }
@ -162,279 +516,201 @@ void getKeySettings(uint8_t *aid) {
char messStr[512] = {0x00}; char messStr[512] = {0x00};
const char *str = messStr; const char *str = messStr;
uint8_t isOK = 0;
PacketResponseNG resp;
//memset(messStr, 0x00, 512); if (memcmp(aid, "\x00\x00\x00", 3) == 0) {
// CARD MASTER KEY
PrintAndLogEx(INFO, " CMK - PICC, Card Master Key settings");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
if (aid == NULL) { if (get_desfire_select_application(aid) != PM3_SUCCESS) {
PrintAndLogEx(NORMAL, " CMK - PICC, Card Master Key settings "); PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
PrintAndLogEx(NORMAL, ""); DropField();
{
uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
}
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't select master application");
return; return;
} }
str = (resp.data.asBytes[3] & (1 << 3)) ? "YES" : "NO"; // KEY Settings - AMK
PrintAndLogEx(NORMAL, " [0x08] Configuration changeable : %s", str); uint8_t num_keys = 0;
str = (resp.data.asBytes[3] & (1 << 2)) ? "NO" : "YES"; uint8_t key_setting = 0;
PrintAndLogEx(NORMAL, " [0x04] CMK required for create/delete : %s", str); if (get_desfire_keysettings(&key_setting, &num_keys) == PM3_SUCCESS) {
str = (resp.data.asBytes[3] & (1 << 1)) ? "NO" : "YES"; // number of Master keys (0x01)
PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str); PrintAndLogEx(SUCCESS, " Number of Masterkeys : " _YELLOW_("%u"), (num_keys & 0x3F) );
str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO";
PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str);
{ PrintAndLogEx(SUCCESS, " [0x08] Configuration changeable : %s", (key_setting & (1 << 3)) ? _GREEN_("YES") : "NO");
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 PrintAndLogEx(SUCCESS, " [0x04] CMK required for create/delete : %s", (key_setting & (1 << 2)) ? _GREEN_("YES") : "NO");
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); PrintAndLogEx(SUCCESS, " [0x02] Directory list access with CMK : %s", (key_setting & (1 << 1)) ? _GREEN_("YES") : "NO");
PrintAndLogEx(SUCCESS, " [0x01] CMK is changeable : %s", (key_setting & (1 << 0)) ? _GREEN_("YES") : "NO");
} else {
PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
} }
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; }
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't read key-version");
return;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Max number of keys : %d", resp.data.asBytes[4]);
PrintAndLogEx(NORMAL, " Master key Version : %d (0x%02x)", resp.data.asBytes[3], resp.data.asBytes[3]);
PrintAndLogEx(NORMAL, " ----------------------------------------------------------");
{ memset(messStr, 0x00, sizeof(messStr));
uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0 str = " Operation of PICC master key : " _YELLOW_("%s");
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
// 2 MSB denotes
switch (num_keys >> 6) {
case 0:
PrintAndLogEx(SUCCESS, str, "(3)DES");
break;
case 1:
PrintAndLogEx(SUCCESS, str, "3K3DES");
break;
case 2:
PrintAndLogEx(SUCCESS, str, "AES");
break;
default:
break;
} }
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} uint8_t cmk_num_versions = 0;
isOK = resp.data.asBytes[2] & 0xff; if (get_desfire_keyversion(0, &cmk_num_versions) == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES"); PrintAndLogEx(SUCCESS, " PICC Master key Version : " _YELLOW_("%d (0x%02x)"), cmk_num_versions, cmk_num_versions);
PrintAndLogEx(INFO, " ----------------------------------------------------------");
{
uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
} }
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} // Authentication tests
isOK = resp.data.asBytes[2] & 0xff; int res = test_desfire_authenticate();
PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES"); if (res == PM3_ETIMEOUT) return;
PrintAndLogEx(SUCCESS, " [0x0A] Authenticate : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
{ res = test_desfire_authenticate_iso();
uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0 if (res == PM3_ETIMEOUT) return;
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); PrintAndLogEx(SUCCESS, " [0x1A] Authenticate ISO : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
}
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} res = test_desfire_authenticate_aes();
isOK = resp.data.asBytes[2] & 0xff; if (res == PM3_ETIMEOUT) return;
PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES"); PrintAndLogEx(SUCCESS, " [0xAA] Authenticate AES : %s", (res == PM3_SUCCESS) ? _YELLOW_("YES") : "NO");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " ----------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
} else { } else {
PrintAndLogEx(NORMAL, " AMK - Application Master Key settings");
// AID - APPLICATION MASTER KEYS
PrintAndLogEx(SUCCESS, " AMK - Application Master Key settings");
PrintAndLogEx(INFO, " ----------------------------------------------------------");
// SELECT AID if (get_desfire_select_application(aid) != PM3_SUCCESS) {
{ PrintAndLogEx(WARNING, _RED_(" Can't select AID"));
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a DropField();
memcpy(data + 1, aid, 3);
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data));
}
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, " Timed-out");
return;
}
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't select AID: %s", sprint_hex(aid, 3));
return; return;
} }
// KEY SETTINGS // KEY Settings - AMK
{ uint8_t num_keys = 0;
uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45 uint8_t key_setting = 0;
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); if (get_desfire_keysettings(&key_setting, &num_keys) == PM3_SUCCESS) {
} desfire_print_keysetting(key_setting, num_keys);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return;
}
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't read Application Master key settings");
} else { } else {
// Access rights. PrintAndLogEx(WARNING, _RED_(" Can't read Application Master key settings"));
uint8_t rights = (resp.data.asBytes[3] >> 4 & 0xff);
switch (rights) {
case 0x00:
str = "AMK authentication is necessary to change any key (default)";
break;
case 0x0e:
str = "Authentication with the key to be changed (same KeyNo) is necessary to change a key";
break;
case 0x0f:
str = "All keys (except AMK,see Bit0) within this application are frozen";
break;
default:
str = "Authentication with the specified key is necessary to change any key. A change key and a PICC master key (CMK) can only be changed after authentication with the master key. For keys other then the master or change key, an authentication with the same key is needed.";
break;
}
PrintAndLogEx(NORMAL, "Changekey Access rights");
PrintAndLogEx(NORMAL, "-- %s", str);
PrintAndLogEx(NORMAL, "");
// same as CMK
str = (resp.data.asBytes[3] & (1 << 3)) ? "YES" : "NO";
PrintAndLogEx(NORMAL, " 0x08 Configuration changeable : %s", str);
str = (resp.data.asBytes[3] & (1 << 2)) ? "NO" : "YES";
PrintAndLogEx(NORMAL, " 0x04 AMK required for create/delete : %s", str);
str = (resp.data.asBytes[3] & (1 << 1)) ? "NO" : "YES";
PrintAndLogEx(NORMAL, " 0x02 Directory list access with AMK : %s", str);
str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO";
PrintAndLogEx(NORMAL, " 0x01 AMK is changeable : %s", str);
} }
// KEY VERSION - AMK // KEY VERSION - AMK
{ uint8_t num_version = 0;
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 if (get_desfire_keyversion(0, &num_version) == PM3_SUCCESS) {
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); PrintAndLogEx(INFO, "-------------------------------------------------------------");
} PrintAndLogEx(INFO, " Application keys");
desfire_print_keyversion(0, num_version);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, " Timed-out");
return;
}
int numOfKeys;
isOK = resp.oldarg[0] & 0xff;
if (isOK == false) {
PrintAndLogEx(WARNING, " Can't read Application Master key version. Trying all keys");
//numOfKeys = MAX_NUM_KEYS;
} else { } else {
numOfKeys = resp.data.asBytes[4]; PrintAndLogEx(WARNING, " Can't read AID master key version. Trying all keys");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Max number of keys : %d", numOfKeys);
PrintAndLogEx(NORMAL, " Application Master key Version : %d (0x%02x)", resp.data.asBytes[3], resp.data.asBytes[3]);
PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
} }
// LOOP over numOfKeys that we got before.
// From 0x01 to numOfKeys. We already got 0x00. (AMK) // From 0x01 to numOfKeys. We already got 0x00. (AMK)
// TODO (iceman) num_keys &= 0x3F;
/* if (num_keys > 1) {
for (int i = 0x01; i <= 0x0f; ++i) { for (uint8_t i = 0x01; i < num_keys; ++i) {
if (get_desfire_keyversion(i, &num_version) == PM3_SUCCESS) {
desfire_print_keyversion(i, num_version);
} else {
PrintAndLogEx(WARNING, " Can't read key %d (0x%02x) version", i, i);
} }
*/ }
}
PrintAndLogEx(INFO, "-------------------------------------------------------------");
} }
DropField();
} }
static int CmdHF14ADesEnumApplications(const char *Cmd) { static int CmdHF14ADesEnumApplications(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
uint8_t isOK = 0x00; // uint8_t isOK = 0x00;
uint8_t aid[3]; uint8_t aid[3];
{ uint8_t app_ids[78] = {0};
uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a uint8_t app_ids_len = 0;
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data));
} uint8_t file_ids[33] = {0};
PacketResponseNG resp; uint8_t file_ids_len = 0;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (get_desfire_appids(app_ids, &app_ids_len) != PM3_SUCCESS) {
return PM3_ETIMEOUT; PrintAndLogEx(ERR, "Can't get list of applications on tag");
}
isOK = resp.oldarg[0] & 0xff;
if (!isOK) {
PrintAndLogEx(NORMAL, "Command unsuccessful");
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------"); PrintAndLogEx(INFO, "-- Mifare DESFire Enumerate applications --------------------");
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") "application%c", app_ids_len / 3, (app_ids_len == 3) ? ' ' : 's');
for (int i = 0; i < app_ids_len; i += 3) {
PacketResponseNG respAid; aid[0] = app_ids[i];
PacketResponseNG respFiles; aid[1] = app_ids[i + 1];
aid[2] = app_ids[i + 2];
PrintAndLogEx(SUCCESS, " AID %d : " _GREEN_("%02X %02X %02X"), i, app_ids[i], app_ids[i+1], app_ids[i+2]);
uint8_t num = 0;
int max = resp.oldarg[1] - 3 - 2;
for (int i = 3; i <= max; i += 3) {
PrintAndLogEx(NORMAL, " Aid %d : %02X %02X %02X ", num, resp.data.asBytes[i], resp.data.asBytes[i + 1], resp.data.asBytes[i + 2]);
num++;
aid[0] = resp.data.asBytes[i];
aid[1] = resp.data.asBytes[i + 1];
aid[2] = resp.data.asBytes[i + 2];
getKeySettings(aid); getKeySettings(aid);
// Select Application
{
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
memcpy(data + 1, &resp.data.asBytes[i], 3);
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data));
}
if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) {
PrintAndLogEx(WARNING, " Timed-out");
continue;
}
isOK = respAid.data.asBytes[2] & 0xff;
if (isOK != 0x00) {
PrintAndLogEx(WARNING, " Can't select AID: %s", sprint_hex(resp.data.asBytes + i, 3));
continue;
}
// Get File IDs // Get File IDs
{ if (get_desfire_fileids(file_ids, &file_ids_len) == PM3_SUCCESS) {
uint8_t data[1] = {GET_FILE_IDS}; // 0x6f PrintAndLogEx(SUCCESS, " Tag report " _GREEN_("%d") "file%c", file_ids_len, (file_ids_len == 1) ? ' ' : 's');
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); for (int i = 0; i < file_ids_len; ++i) {
} PrintAndLogEx(SUCCESS, " Fileid %d (0x%02x)", file_ids[i], file_ids[i]);
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
PrintAndLogEx(WARNING, " Timed-out");
continue;
} else {
isOK = respFiles.data.asBytes[2] & 0xff;
if (!isOK) {
PrintAndLogEx(WARNING, " Can't get file ids ");
} else {
int respfileLen = resp.oldarg[1] - 3 - 2;
for (int j = 0; j < respfileLen; ++j) {
PrintAndLogEx(NORMAL, " Fileid %d :", resp.data.asBytes[j + 3]);
}
} }
} }
/*
// Get ISO File IDs // Get ISO File IDs
{ {
uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61 uint8_t data[] = {GET_ISOFILE_IDS, 0x00, 0x00, 0x00}; // 0x61
SendCommandMIX(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data)); SendCommandMIX(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data));
} }
if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
PrintAndLogEx(WARNING, " Timed-out"); PrintAndLogEx(WARNING, _RED_(" Timed-out"));
continue; continue;
} else { } else {
isOK = respFiles.data.asBytes[2] & 0xff; isOK = respFiles.data.asBytes[2] & 0xff;
if (!isOK) { if (!isOK) {
PrintAndLogEx(WARNING, " Can't get ISO file ids "); PrintAndLogEx(WARNING, _RED_(" Can't get ISO file ids"));
} else { } else {
int respfileLen = resp.oldarg[1] - 3 - 2; int respfileLen = resp.oldarg[1] - 3 - 2;
for (int j = 0; j < respfileLen; ++j) { for (int j = 0; j < respfileLen; ++j) {
PrintAndLogEx(NORMAL, " ISO Fileid %d :", resp.data.asBytes[j + 3]); PrintAndLogEx(SUCCESS, " ISO Fileid %d :", resp.data.asBytes[j + 3]);
} }
} }
} }
*/
} }
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/*
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
// MIAFRE DesFire Authentication if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0;
}
*/
// MIAFRE DESFire Authentication
// //
#define BUFSIZE 256 #define BUFSIZE 256
static int CmdHF14ADesAuth(const char *Cmd) { static int CmdHF14ADesAuth(const char *Cmd) {
@ -457,8 +733,8 @@ static int CmdHF14ADesAuth(const char *Cmd) {
PrintAndLogEx(NORMAL, " 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES"); PrintAndLogEx(NORMAL, " 1 = DES 2 = 3DES 3 = 3K3DES 4 = AES");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfdes auth 1 1 0 11223344"));
PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
uint8_t cmdAuthMode = param_get8(Cmd, 0); uint8_t cmdAuthMode = param_get8(Cmd, 0);
@ -531,18 +807,17 @@ static int CmdHF14ADesAuth(const char *Cmd) {
if (isOK) { if (isOK) {
uint8_t *session_key = resp.data.asBytes; uint8_t *session_key = resp.data.asBytes;
PrintAndLogEx(NORMAL, " Key :%s", sprint_hex(key, keylength)); PrintAndLogEx(SUCCESS, " Key : " _GREEN_("%s"), sprint_hex(key, keylength));
PrintAndLogEx(NORMAL, " SESSION :%s", sprint_hex(session_key, keylength)); PrintAndLogEx(SUCCESS, " SESSION : " _GREEN_("%s"), sprint_hex(session_key, keylength));
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
//PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); //PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56");
} else { } else {
PrintAndLogEx(NORMAL, "Client command failed."); PrintAndLogEx(WARNING, _RED_("Client command failed."));
} }
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"}, {"info", CmdHF14ADesInfo, IfPm3Iso14443a, "Tag information"},
@ -564,4 +839,3 @@ int CmdHFMFDes(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }

View file

@ -19,16 +19,6 @@ char *getProtocolStr(uint8_t id);
char *getVersionStr(uint8_t major, uint8_t minor); char *getVersionStr(uint8_t major, uint8_t minor);
void getKeySettings(uint8_t *aid); void getKeySettings(uint8_t *aid);
// Command options for Desfire behavior.
enum {
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x08,
} CmdOptions ;
#define CREATE_APPLICATION 0xca #define CREATE_APPLICATION 0xca
#define DELETE_APPLICATION 0xda #define DELETE_APPLICATION 0xda
#define GET_APPLICATION_IDS 0x6a #define GET_APPLICATION_IDS 0x6a

View file

@ -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); SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return 1; return 1;
} }
// error during nested_hard // error during nested_hard
if (resp.oldarg[0]) { if (resp.oldarg[0]) {
if (nonce_file_write) { 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" // create mutexes for accessing the statelist cache and our "book of work"
pthread_mutex_init(&statelist_cache_mutex, NULL); pthread_mutex_init(&statelist_cache_mutex, NULL);
pthread_mutex_init(&book_of_work_mutex, NULL); pthread_mutex_init(&book_of_work_mutex, NULL);
init_statelist_cache(); init_statelist_cache();
init_book_of_work(); init_book_of_work();

View file

@ -39,6 +39,10 @@ static int CmdHFMFPInfo(const char *Cmd) {
if (Cmd && strlen(Cmd) > 0) if (Cmd && strlen(Cmd) > 0)
PrintAndLogEx(WARNING, "command don't have any parameters.\n"); PrintAndLogEx(WARNING, "command don't have any parameters.\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-- Mifare Plus Tag Information ------------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
// info about 14a part // info about 14a part
infoHF14A(false, false, false); infoHF14A(false, false, false);
@ -54,61 +58,107 @@ static int CmdHFMFPInfo(const char *Cmd) {
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if (select_status == 1 || select_status == 2) { if (select_status == 1 || select_status == 2) {
PrintAndLogEx(NORMAL, "----------------------------------------------");
PrintAndLogEx(NORMAL, "Mifare Plus info:");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, " Fingerprint");
// MIFARE Type Identification Procedure // MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf // https://www.nxp.com/docs/en/application-note/AN10833.pdf
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8); uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
if (ATQA == 0x0004) PrintAndLogEx(INFO, "ATQA: Mifare Plus 2k 4bUID");
if (ATQA == 0x0002) PrintAndLogEx(INFO, "ATQA: Mifare Plus 4k 4bUID"); bool isPlus = false;
if (ATQA == 0x0044) PrintAndLogEx(INFO, "ATQA: Mifare Plus 2k 7bUID");
if (ATQA == 0x0042) PrintAndLogEx(INFO, "ATQA: Mifare Plus 4k 7bUID"); if (ATQA == 0x0004) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (4b UID)");
isPlus = true;
}
if (ATQA == 0x0002) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (4b UID)");
isPlus = true;
}
if (ATQA == 0x0044) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (7b UID)");
isPlus = true;
}
if (ATQA == 0x0042) {
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (7b UID)");
isPlus = true;
}
uint8_t SLmode = 0xff; uint8_t SLmode = 0xff;
if (card.sak == 0x08) { if (isPlus) {
PrintAndLogEx(INFO, "SAK: Mifare Plus 2k 7bUID"); if (card.sak == 0x08) {
if (select_status == 2) SLmode = 1; PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K 7b UID"));
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x18) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K 7b UID"));
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x10) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K"));
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x11) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K"));
if (select_status == 2) SLmode = 2;
}
} }
if (card.sak == 0x18) {
PrintAndLogEx(INFO, "SAK: Mifare Plus 4k 7bUID");
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x10) {
PrintAndLogEx(INFO, "SAK: Mifare Plus 2k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x11) {
PrintAndLogEx(INFO, "SAK: Mifare Plus 4k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x20) {
PrintAndLogEx(INFO, "SAK: Mifare Plus SL0/SL3 or Mifare desfire");
if (card.ats_len > 0) {
SLmode = 3;
if (card.sak == 0x20) {
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus SL0/SL3") "or " _GREEN_("Mifare DESFire"));
if (card.ats_len > 0) {
SLmode = 3;
// check SL0 // check SL0
uint8_t data[250] = {0}; uint8_t data[250] = {0};
int datalen = 0; int datalen = 0;
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161 // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
if (memcmp(data, "\x67\x00", 2) == 0) {
PrintAndLogEx(INFO, "\tMost likely a Mifare DESFire tag");
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`"));
DropField();
return PM3_SUCCESS;
}
if (!res && datalen > 1 && data[0] == 0x09) { if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0; SLmode = 0;
} }
} }
} }
if (SLmode != 0xff) // How do we detect SL0 / SL1 / SL2 / SL3 modes?!?
PrintAndLogEx(INFO, "Mifare Plus SL mode: SL%d", SLmode); PrintAndLogEx(INFO, "Security Level (SL)");
switch(SLmode) {
case 0:
PrintAndLogEx(INFO, "SL 0: initial delivery configuration, used for card personalization");
break;
case 1:
PrintAndLogEx(INFO, "SL 1: backwards functional compatibility mode (with MIFARE Classic 1K / 4K) with an optional AES authentication");
break;
case 2:
PrintAndLogEx(INFO, "SL 2: 3-Pass Authentication based on AES followed by MIFARE CRYPTO1 authentication, communication secured by MIFARE CRYPTO1");
break;
case 3:
PrintAndLogEx(INFO, "SL 3: 3-Pass authentication based on AES, data manipulation commands secured by AES encryption and an AES based MACing method.");
break;
default:
break;
}
if (SLmode != 0xFF)
PrintAndLogEx(SUCCESS, "\tMifare Plus SL mode: " _YELLOW_("SL%d"), SLmode);
else else
PrintAndLogEx(WARNING, "Mifare Plus SL mode: unknown("); PrintAndLogEx(WARNING, "\tMifare Plus SL mode: " _YELLOW_("unknown"));
} else { } else {
PrintAndLogEx(INFO, "Mifare Plus info not available."); PrintAndLogEx(INFO, "\tMifare Plus info not available.");
} }
DropField(); DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -53,48 +53,51 @@ static int usage_hf_mfu_info(void) {
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu info"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info"));
PrintAndLogEx(NORMAL, " hf mfu info k 00112233445566778899AABBCCDDEEFF"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info k 00112233445566778899AABBCCDDEEFF"));
PrintAndLogEx(NORMAL, " hf mfu info k AABBCCDD"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu info k AABBCCDD"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_dump(void) { static int usage_hf_mfu_dump(void) {
PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1");
PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216");
PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); PrintAndLogEx(NORMAL, "and saves binary dump into the file " _YELLOW_("`filename.bin`") "or " _YELLOW_("`cardUID.bin`") );
PrintAndLogEx(NORMAL, "It autodetects card type.\n"); PrintAndLogEx(NORMAL, "It autodetects card type.\n");
PrintAndLogEx(NORMAL, "Usage: hf mfu dump k <key> l f <filename w/o .bin> p <page#> q <#pages>"); PrintAndLogEx(NORMAL, "Usage: hf mfu dump k <key> l f <filename w/o .bin> p <page#> q <#pages>");
PrintAndLogEx(NORMAL, " Options :"); PrintAndLogEx(NORMAL, " Options :");
PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
PrintAndLogEx(NORMAL, " f <FN > : filename w/o .bin to save the dump as"); PrintAndLogEx(NORMAL, " f <fn> : " _YELLOW_("filename w/o .bin") "to save the dump as");
PrintAndLogEx(NORMAL, " p <Pg > : starting Page number to manually set a page to start the dump at"); PrintAndLogEx(NORMAL, " p <pg> : starting Page number to manually set a page to start the dump at");
PrintAndLogEx(NORMAL, " q <qty> : number of Pages to manually set how many pages to dump"); PrintAndLogEx(NORMAL, " q <qty> : number of Pages to manually set how many pages to dump");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu dump"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump"));
PrintAndLogEx(NORMAL, " hf mfu dump n myfile"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump f myfile"));
PrintAndLogEx(NORMAL, " hf mfu dump k 00112233445566778899AABBCCDDEEFF"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump k 00112233445566778899AABBCCDDEEFF"));
PrintAndLogEx(NORMAL, " hf mfu dump k AABBCCDD\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu dump k AABBCCDD"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_restore(void) { static int usage_hf_mfu_restore(void) {
PrintAndLogEx(NORMAL, "Restore dumpfile onto card."); PrintAndLogEx(NORMAL, "Restore dumpfile onto card.");
PrintAndLogEx(NORMAL, "Usage: hf mfu restore [h] [l] [s] k <key> n <filename w/o .bin> "); PrintAndLogEx(NORMAL, "Usage: hf mfu restore [h] [l] [s] k <key> n <filename w .bin> ");
PrintAndLogEx(NORMAL, " Options :"); PrintAndLogEx(NORMAL, " Options :");
PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); PrintAndLogEx(NORMAL, " k <key> : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]");
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
PrintAndLogEx(NORMAL, " s : (optional) enable special write UID -MAGIC TAG ONLY-"); PrintAndLogEx(NORMAL, " s : (optional) enable special write UID " _BLUE_("-MAGIC TAG ONLY-") );
PrintAndLogEx(NORMAL, " e : (optional) enable special write version/signature -MAGIC NTAG 21* ONLY-"); PrintAndLogEx(NORMAL, " e : (optional) enable special write version/signature " _BLUE_("-MAGIC NTAG 21* ONLY-") );
PrintAndLogEx(NORMAL, " r : (optional) use the password found in dumpfile to configure tag. requires 'e' parameter to work"); PrintAndLogEx(NORMAL, " r : (optional) use the password found in dumpfile to configure tag. requires " _YELLOW_("'e'") "parameter to work");
PrintAndLogEx(NORMAL, " f <FN> : filename w/o .bin to restore"); PrintAndLogEx(NORMAL, " f <fn> : " _YELLOW_("filename w .bin") "to restore");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu restore s f myfile"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore s f myfile"));
PrintAndLogEx(NORMAL, " hf mfu restore k AABBCCDD s f myfile\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s f myfile"));
PrintAndLogEx(NORMAL, " hf mfu restore k AABBCCDD s e r f myfile\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu restore k AABBCCDD s e r f myfile"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -107,9 +110,10 @@ static int usage_hf_mfu_rdbl(void) {
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu rdbl b 0"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0"));
PrintAndLogEx(NORMAL, " hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"));
PrintAndLogEx(NORMAL, " hf mfu rdbl b 0 k AABBCCDD\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu rdbl b 0 k AABBCCDD"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -123,14 +127,15 @@ static int usage_hf_mfu_wrbl(void) {
PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu wrbl b 0 d 01234567"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu wrbl b 0 d 01234567"));
PrintAndLogEx(NORMAL, " hf mfu wrbl b 0 d 01234567 k AABBCCDD\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu wrbl b 0 d 01234567 k AABBCCDD"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_eload(void) { static int usage_hf_mfu_eload(void) {
PrintAndLogEx(NORMAL, "It loads emul dump from the file `filename.eml`"); PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`") );
PrintAndLogEx(NORMAL, "Hint: See script dumptoemul-mfu.lua to convert the .bin to the eml"); PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run dumptoemul-mfu`") "to convert the .bin to the eml");
PrintAndLogEx(NORMAL, "Usage: hf mfu eload u <file name w/o `.eml`> [numblocks]"); PrintAndLogEx(NORMAL, "Usage: hf mfu eload u <file name w/o `.eml`> [numblocks]");
PrintAndLogEx(NORMAL, " Options:"); PrintAndLogEx(NORMAL, " Options:");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
@ -138,8 +143,10 @@ static int usage_hf_mfu_eload(void) {
PrintAndLogEx(NORMAL, " [filename] : without `.eml` (required)"); PrintAndLogEx(NORMAL, " [filename] : without `.eml` (required)");
PrintAndLogEx(NORMAL, " numblocks : number of blocks to load from eml file (optional)"); PrintAndLogEx(NORMAL, " numblocks : number of blocks to load from eml file (optional)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " sample: hf mfu eload u filename"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu eload u filename 57"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu eload u filename 57"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -153,8 +160,9 @@ static int usage_hf_mfu_sim(void) {
PrintAndLogEx(NORMAL, " u <uid> : 4 or 7 byte UID (optional)"); PrintAndLogEx(NORMAL, " u <uid> : 4 or 7 byte UID (optional)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu sim t 7"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7"));
PrintAndLogEx(NORMAL, " hf mfu sim t 7 u 1122344556677\n"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu sim t 7 u 1122344556677"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -168,17 +176,19 @@ static int usage_hf_mfu_ucauth(void) {
PrintAndLogEx(NORMAL, " 5 : all 0xff key"); PrintAndLogEx(NORMAL, " 5 : all 0xff key");
PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key"); PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu cauth k"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k"));
PrintAndLogEx(NORMAL, " hf mfu cauth k 3"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k 3"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_ucsetpwd(void) { static int usage_hf_mfu_ucsetpwd(void) {
PrintAndLogEx(NORMAL, "Set 3DES password on Mifare Ultralight-C tag.");
PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd <password (32 hex symbols)>"); PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd <password (32 hex symbols)>");
PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setpwd 000102030405060708090a0b0c0d0e0f"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -186,10 +196,11 @@ static int usage_hf_mfu_ucsetpwd(void) {
static int usage_hf_mfu_ucsetuid(void) { static int usage_hf_mfu_ucsetuid(void) {
PrintAndLogEx(NORMAL, "Usage: hf mfu setuid <uid (14 hex symbols)>"); PrintAndLogEx(NORMAL, "Usage: hf mfu setuid <uid (14 hex symbols)>");
PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)"); PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)");
PrintAndLogEx(NORMAL, "\nThis only works for Magic Ultralight tags."); PrintAndLogEx(NORMAL, "\n");
PrintAndLogEx(NORMAL, "This only works for " _BLUE_("Magic Ultralight") "tags.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu setuid 11223344556677"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 11223344556677"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -201,8 +212,8 @@ static int usage_hf_mfu_gendiverse(void) {
PrintAndLogEx(NORMAL, " r : read uid from tag"); PrintAndLogEx(NORMAL, " r : read uid from tag");
PrintAndLogEx(NORMAL, " <uid> : 4 byte UID (optional)"); PrintAndLogEx(NORMAL, " <uid> : 4 byte UID (optional)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu gen r"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu gen r"));
PrintAndLogEx(NORMAL, " hf mfu gen 11223344"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu gen 11223344"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -215,20 +226,21 @@ static int usage_hf_mfu_pwdgen(void) {
PrintAndLogEx(NORMAL, " r : read uid from tag"); PrintAndLogEx(NORMAL, " r : read uid from tag");
PrintAndLogEx(NORMAL, " <uid> : 7 byte UID (optional)"); PrintAndLogEx(NORMAL, " <uid> : 7 byte UID (optional)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu pwdgen r"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen r"));
PrintAndLogEx(NORMAL, " hf mfu pwdgen 11223344556677"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen 11223344556677"));
PrintAndLogEx(NORMAL, " hf mfu pwdgen t"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu pwdgen t"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_otp_tearoff(void) { static int usage_hf_mfu_otp_tearoff(void) {
PrintAndLogEx(NORMAL, "Tear-off test against OTP block on MFU tags - More help sooner or later\n"); PrintAndLogEx(NORMAL, "Tear-off test against OTP block on MFU tags.");
PrintAndLogEx(NORMAL, "Usage: hf mfu otptear [h]"); PrintAndLogEx(NORMAL, "Usage: hf mfu otptear [h]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu otptear"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu otptear"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -284,26 +296,6 @@ uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = {
MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K
}; };
static int ul_ev1_pwdgen_selftest() {
uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10};
uint32_t pwd1 = ul_ev1_pwdgenA(uid1);
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid1, 7), pwd1, (pwd1 == 0x8432EB17) ? "OK" : "->8432EB17<-");
uint8_t uid2[] = {0x04, 0x1f, 0x98, 0xea, 0x1e, 0x3e, 0x81};
uint32_t pwd2 = ul_ev1_pwdgenB(uid2);
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid2, 7), pwd2, (pwd2 == 0x5fd37eca) ? "OK" : "->5fd37eca<--");
uint8_t uid3[] = {0x04, 0x62, 0xB6, 0x8A, 0xB4, 0x42, 0x80};
uint32_t pwd3 = ul_ev1_pwdgenC(uid3);
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid3, 7), pwd3, (pwd3 == 0x5a349515) ? "OK" : "->5a349515<--");
uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
uint32_t pwd4 = ul_ev1_pwdgenD(uid4);
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--");
return PM3_SUCCESS;
}
//------------------------------------ //------------------------------------
// get version nxp product type // get version nxp product type
static char *getProductTypeStr(uint8_t id) { static char *getProductTypeStr(uint8_t id) {
@ -527,43 +519,43 @@ static int ul_print_default(uint8_t *data) {
uid[5] = data[6]; uid[5] = data[6];
uid[6] = data[7]; uid[6] = data[7];
PrintAndLogEx(NORMAL, " UID : %s ", sprint_hex(uid, 7)); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(uid, 7));
PrintAndLogEx(NORMAL, " UID[0] : %02X, %s", uid[0], getTagInfo(uid[0])); PrintAndLogEx(SUCCESS, " UID[0]: %02X, %s", uid[0], getTagInfo(uid[0]));
if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2) { // is infineon and 66RxxP if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2) { // is infineon and 66RxxP
uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU
switch (chip) { switch (chip) {
case 0xC2: case 0xC2:
PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); PrintAndLogEx(SUCCESS, " IC type: SLE 66R04P 770 Bytes");
break; //77 pages break; //77 pages
case 0xC4: case 0xC4:
PrintAndLogEx(NORMAL, " IC type : SLE 66R16P 2560 Bytes"); PrintAndLogEx(SUCCESS, " IC type: SLE 66R16P 2560 Bytes");
break; //256 pages break; //256 pages
case 0xC6: case 0xC6:
PrintAndLogEx(NORMAL, " IC type : SLE 66R32P 5120 Bytes"); PrintAndLogEx(SUCCESS, " IC type: SLE 66R32P 5120 Bytes");
break; //512 pages /2 sectors break; //512 pages /2 sectors
} }
} }
// CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2
int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
if (data[3] == crc0) if (data[3] == crc0)
PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); PrintAndLogEx(SUCCESS, " BCC0: %02X ( " _GREEN_("ok") ")", data[3]);
else else
PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); PrintAndLogEx(NORMAL, " BCC0: %02X, crc should be %02X", data[3], crc0);
int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6];
if (data[8] == crc1) if (data[8] == crc1)
PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); PrintAndLogEx(SUCCESS, " BCC1: %02X ( " _GREEN_("ok") ")", data[8]);
else else
PrintAndLogEx(NORMAL, " BCC1 : %02X, crc should be %02X", data[8], crc1); PrintAndLogEx(NORMAL, " BCC1: %02X, crc should be %02X", data[8], crc1);
PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9] == 0x48) ? "" : "not "); PrintAndLogEx(SUCCESS, " Internal: %02X ( %s)", data[9], (data[9] == 0x48) ? _GREEN_("default") : _RED_("not default") );
PrintAndLogEx(NORMAL, " Lock : %s - %s", PrintAndLogEx(SUCCESS, " Lock: %s - %s",
sprint_hex(data + 10, 2), sprint_hex(data + 10, 2),
sprint_bin(data + 10, 2) sprint_bin(data + 10, 2)
); );
PrintAndLogEx(NORMAL, "OneTimePad : %s - %s\n", PrintAndLogEx(SUCCESS, "OneTimePad : %s - %s\n",
sprint_hex(data + 12, 4), sprint_hex(data + 12, 4),
sprint_bin(data + 12, 4) sprint_bin(data + 12, 4)
); );
@ -648,10 +640,10 @@ static int ndef_print_CC(uint8_t *data) {
PrintAndLogEx(NORMAL, " Additional feature information"); PrintAndLogEx(NORMAL, " Additional feature information");
PrintAndLogEx(NORMAL, " %02X", data[3]); PrintAndLogEx(NORMAL, " %02X", data[3]);
PrintAndLogEx(NORMAL, " 00000000"); PrintAndLogEx(NORMAL, " 00000000");
PrintAndLogEx(NORMAL, " xxx - %02X : RFU (%s)", msb3, (msb3 == 0) ? _GREEN_("OK") : _RED_("Fail")); PrintAndLogEx(NORMAL, " xxx - %02X : RFU ( %s)", msb3, (msb3 == 0) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(NORMAL, " x - %02X : %s special frame", sf, (sf) ? "support" : "don\'t support"); PrintAndLogEx(NORMAL, " x - %02X : %s special frame", sf, (sf) ? "support" : "don\'t support");
PrintAndLogEx(NORMAL, " x - %02X : %s lock block", lb, (lb) ? "support" : "don\'t support"); PrintAndLogEx(NORMAL, " x - %02X : %s lock block", lb, (lb) ? "support" : "don\'t support");
PrintAndLogEx(NORMAL, " xx - %02X : RFU (%s)", mlrule, (mlrule == 0) ? _GREEN_("OK") : _RED_("Fail")); PrintAndLogEx(NORMAL, " xx - %02X : RFU ( %s)", mlrule, (mlrule == 0) ? _GREEN_("ok") : _RED_("fail"));
PrintAndLogEx(NORMAL, " x - %02X : IC %s multiple block reads", mbread, (mbread) ? "support" : "don\'t support"); PrintAndLogEx(NORMAL, " x - %02X : IC %s multiple block reads", mbread, (mbread) ? "support" : "don\'t support");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -667,57 +659,57 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) {
char *spacer = spc + (10 - spaces); char *spacer = spc + (10 - spaces);
if (tagtype & UL) if (tagtype & UL)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "<magic>" : ""); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIFARE Ultralight (MF0ICU1) %s"), spacer, (tagtype & MAGIC) ? "<magic>" : "");
else if (tagtype & UL_C) else if (tagtype & UL_C)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "<magic>" : ""); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIFARE Ultralight C (MF0ULC) %s"), spacer, (tagtype & MAGIC) ? "<magic>" : "");
else if (tagtype & UL_NANO_40) else if (tagtype & UL_NANO_40)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight Nano 40bytes (MF0UNH00)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIFARE Ultralight Nano 40bytes (MF0UNH00)"), spacer);
else if (tagtype & UL_EV1_48) else if (tagtype & UL_EV1_48)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIFARE Ultralight EV1 48bytes (MF0UL1101)"), spacer);
else if (tagtype & UL_EV1_128) else if (tagtype & UL_EV1_128)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("MIFARE Ultralight EV1 128bytes (MF0UL2101)"), spacer);
else if (tagtype & UL_EV1) else if (tagtype & UL_EV1)
PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 UNKNOWN", spacer); PrintAndLogEx(NORMAL, "%sTYPE: " _YELLOW_("MIFARE Ultralight EV1 UNKNOWN"), spacer);
else if (tagtype & NTAG) else if (tagtype & NTAG)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); PrintAndLogEx(NORMAL, "%sTYPE: " _YELLOW_("NTAG UNKNOWN"), spacer);
else if (tagtype & NTAG_203) else if (tagtype & NTAG_203)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 203 144bytes (NT2H0301F0DT)"), spacer);
else if (tagtype & NTAG_210) else if (tagtype & NTAG_210)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 210 48bytes (NT2L1011G0DU)"), spacer);
else if (tagtype & NTAG_212) else if (tagtype & NTAG_212)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 212 128bytes (NT2L1211G0DU)"), spacer);
else if (tagtype & NTAG_213) else if (tagtype & NTAG_213)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spacer);
else if (tagtype & NTAG_213_F) else if (tagtype & NTAG_213_F)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213F 144bytes (NT2H1311F0DTL)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spacer);
else if (tagtype & NTAG_215) else if (tagtype & NTAG_215)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spacer);
else if (tagtype & NTAG_216) else if (tagtype & NTAG_216)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 216 888bytes (NT2H1611G0DU)"), spacer);
else if (tagtype & NTAG_216_F) else if (tagtype & NTAG_216_F)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216F 888bytes (NT2H1611F0DTL)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG 216F 888bytes (NT2H1611F0DTL)"), spacer);
else if (tagtype & NTAG_I2C_1K) else if (tagtype & NTAG_I2C_1K)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG I2C 888bytes (NT3H1101FHK)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG I2C 888bytes (NT3H1101FHK)"), spacer);
else if (tagtype & NTAG_I2C_2K) else if (tagtype & NTAG_I2C_2K)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG I2C 1904bytes (NT3H1201FHK)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG I2C 1904bytes (NT3H1201FHK)"), spacer);
else if (tagtype & NTAG_I2C_1K_PLUS) else if (tagtype & NTAG_I2C_1K_PLUS)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG I2C plus 888bytes (NT3H2111FHK)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG I2C plus 888bytes (NT3H2111FHK)"), spacer);
else if (tagtype & NTAG_I2C_2K_PLUS) else if (tagtype & NTAG_I2C_2K_PLUS)
PrintAndLogEx(NORMAL, "%sTYPE : NTAG I2C plus 1912bytes (NT3H2211FHK)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("NTAG I2C plus 1912bytes (NT3H2211FHK)"), spacer);
else if (tagtype & MY_D) else if (tagtype & MY_D)
PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("INFINEON my-d\x99 (SLE 66RxxS)"), spacer);
else if (tagtype & MY_D_NFC) else if (tagtype & MY_D_NFC)
PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("INFINEON my-d\x99 NFC (SLE 66RxxP)"), spacer);
else if (tagtype & MY_D_MOVE) else if (tagtype & MY_D_MOVE)
PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("INFINEON my-d\x99 move (SLE 66R01P)"), spacer);
else if (tagtype & MY_D_MOVE_NFC) else if (tagtype & MY_D_MOVE_NFC)
PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("INFINEON my-d\x99 move NFC (SLE 66R01P)"), spacer);
else if (tagtype & MY_D_MOVE_LEAN) else if (tagtype & MY_D_MOVE_LEAN)
PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("INFINEON my-d\x99 move lean (SLE 66R01L)"), spacer);
else if (tagtype & FUDAN_UL) else if (tagtype & FUDAN_UL)
PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "<magic>" : ""); PrintAndLogEx(SUCCESS, "%sTYPE: " _YELLOW_("FUDAN Ultralight Compatible (or other compatible) %s"), spacer, (tagtype & MAGIC) ? "<magic>" : "");
else else
PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); PrintAndLogEx(NORMAL, "%sTYPE: " _YELLOW_("Unknown %06x"), spacer, tagtype);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -845,7 +837,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st
if (authlim == 0) if (authlim == 0)
PrintAndLogEx(NORMAL, " - Unlimited password attempts"); PrintAndLogEx(NORMAL, " - Unlimited password attempts");
else else
PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); PrintAndLogEx(NORMAL, " - Max number of password attempts is " _YELLOW_("%d"), authlim);
PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_en) ? "enabled" : "disabled"); PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_en) ? "enabled" : "disabled");
PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_prot_pwd) ? "not protected" : "password protection enabled"); PrintAndLogEx(NORMAL, " - NFC counter %s", (nfc_cnf_prot_pwd) ? "not protected" : "password protection enabled");
@ -883,25 +875,25 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, public_keys[public_key], uid, 7, signature, signature_len, false); int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, public_keys[public_key], uid, 7, signature, signature_len, false);
bool is_valid = (res == 0); bool is_valid = (res == 0);
PrintAndLogEx(NORMAL, "\n--- Tag Signature"); PrintAndLogEx(INFO, "\n--- Tag Signature");
PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); PrintAndLogEx(INFO, "IC signature public key name : NXP NTAG21x (2013)");
PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_keys[public_key], PUBLIC_ECDA_KEYLEN)); PrintAndLogEx(INFO, "IC signature public key value : %s", sprint_hex(public_keys[public_key], PUBLIC_ECDA_KEYLEN));
PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1"); PrintAndLogEx(INFO, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, signature_len)); PrintAndLogEx(INFO, " TAG IC Signature : %s", sprint_hex(signature, signature_len));
PrintAndLogEx(NORMAL, "Signature verified %s", (is_valid) ? _GREEN_("successful") : _RED_("failed")); PrintAndLogEx(SUCCESS, "Signature verified %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ulev1_print_version(uint8_t *data) { static int ulev1_print_version(uint8_t *data) {
PrintAndLogEx(NORMAL, "\n--- Tag Version"); PrintAndLogEx(NORMAL, "\n--- Tag Version");
PrintAndLogEx(NORMAL, " Raw bytes : %s", sprint_hex(data, 8)); PrintAndLogEx(NORMAL, " Raw bytes: %s", sprint_hex(data, 8));
PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getTagInfo(data[1])); PrintAndLogEx(NORMAL, " Vendor ID: %02X, %s", data[1], getTagInfo(data[1]));
PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); PrintAndLogEx(NORMAL, " Product type: %s", getProductTypeStr(data[2]));
PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3] == 1) ? "17 pF" : "50pF"); PrintAndLogEx(NORMAL, " Product subtype: %02X, %s", data[3], (data[3] == 1) ? "17 pF" : "50pF");
PrintAndLogEx(NORMAL, " Major version : %02X", data[4]); PrintAndLogEx(NORMAL, " Major version: %02X", data[4]);
PrintAndLogEx(NORMAL, " Minor version : %02X", data[5]); PrintAndLogEx(NORMAL, " Minor version: %02X", data[5]);
PrintAndLogEx(NORMAL, " Size : %s", getUlev1CardSizeStr(data[6])); PrintAndLogEx(NORMAL, " Size: %s", getUlev1CardSizeStr(data[6]));
PrintAndLogEx(NORMAL, " Protocol type : %02X %s", data[7], (data[7] == 0x3) ? "(ISO14443-3 Compliant)" : ""); PrintAndLogEx(NORMAL, " Protocol type: %02X %s", data[7], (data[7] == 0x3) ? "(ISO14443-3 Compliant)" : "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1110,7 +1102,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
cmdp++; cmdp++;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -1271,12 +1263,13 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
// 1-7 = limit. No automatic tries then. // 1-7 = limit. No automatic tries then.
// hasAuthKey, if we was called with key, skip test. // hasAuthKey, if we was called with key, skip test.
if (!authlim && !hasAuthKey) { if (!authlim && !hasAuthKey) {
PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("--- Known EV1/NTAG passwords ---"));
// test pwd gen A // test pwd gen A
num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key); num_to_bytes(ul_ev1_pwdgenA(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { if (len > -1) {
PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") "|| Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
goto out; goto out;
} }
@ -1286,7 +1279,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key); num_to_bytes(ul_ev1_pwdgenB(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { if (len > -1) {
PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") "|| Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
goto out; goto out;
} }
@ -1296,7 +1289,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key); num_to_bytes(ul_ev1_pwdgenC(card.uid), 4, key);
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { if (len > -1) {
PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") "|| Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
goto out; goto out;
} }
@ -1316,13 +1309,13 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
key = default_pwd_pack[i]; key = default_pwd_pack[i];
len = ulev1_requestAuthentication(key, pack, sizeof(pack)); len = ulev1_requestAuthentication(key, pack, sizeof(pack));
if (len > -1) { if (len > -1) {
PrintAndLogEx(SUCCESS, "Found a default password:" _GREEN_("%s") " || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); PrintAndLogEx(SUCCESS, "Found a default password: " _GREEN_("%s") "|| Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]);
break; break;
} else { } else {
if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT;
} }
} }
if (len < 1) PrintAndLogEx(WARNING, "password not known"); if (len < 1) PrintAndLogEx(WARNING, _YELLOW_("password not known"));
} }
} }
out: out:
@ -1395,7 +1388,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
cmdp += 2; cmdp += 2;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -1509,7 +1502,7 @@ static int CmdHF14AMfURdBl(const char *Cmd) {
cmdp++; cmdp++;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -1779,7 +1772,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
manualPages = true; manualPages = true;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -2020,7 +2013,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
read_key = true; read_key = true;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -2565,7 +2558,7 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_hf_mfu_pwdgen();
if (cmdp == 't') return ul_ev1_pwdgen_selftest(); if (cmdp == 't') return generator_selftest();
if (cmdp == 'r') { if (cmdp == 'r') {
// read uid from tag // read uid from tag
@ -2671,4 +2664,3 @@ int CmdHFMFUltra(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }

View file

@ -253,7 +253,7 @@ static int CmdLFTune(const char *Cmd) {
//Validations //Validations
if (errors) return usage_lf_tune(); if (errors) return usage_lf_tune();
PrintAndLogEx(SUCCESS, "Measuring LF antenna at " _YELLOW_("%.2f") "kHz, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit", LF_DIV2FREQ(divisor)); PrintAndLogEx(INFO, "Measuring LF antenna at " _YELLOW_("%.2f") "kHz, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit", LF_DIV2FREQ(divisor));
uint8_t params[] = {1, 0}; uint8_t params[] = {1, 0};
params[1] = divisor; params[1] = divisor;
@ -295,7 +295,7 @@ static int CmdLFTune(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Done."); PrintAndLogEx(INFO, "Done.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1189,7 +1189,7 @@ static bool CheckChipType(bool getDeviceData) {
uint32_t word = 0; uint32_t word = 0;
if (EM4x05IsBlock0(&word)) { if (EM4x05IsBlock0(&word)) {
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05/EM4x69")); PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05/EM4x69"));
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x05`") "commands"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05`") "commands");
retval = true; retval = true;
goto out; goto out;
} }
@ -1197,7 +1197,7 @@ static bool CheckChipType(bool getDeviceData) {
//check for t55xx chip... //check for t55xx chip...
if (tryDetectP1(true)) { if (tryDetectP1(true)) {
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("T55xx")); PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("T55xx"));
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf t55xx`") "commands"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf t55xx`") "commands");
retval = true; retval = true;
} }
@ -1351,7 +1351,7 @@ static command_t CommandTable[] = {
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"}, {"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"}, {"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"}, {"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
{"hid", CmdLFHID, AlwaysAvailable, "{ HID RFIDs... }"}, {"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},
{"hitag", CmdLFHitag, AlwaysAvailable, "{ Hitag CHIPs... }"}, {"hitag", CmdLFHitag, AlwaysAvailable, "{ Hitag CHIPs... }"},
{"indala", CmdLFINDALA, AlwaysAvailable, "{ Indala RFIDs... }"}, {"indala", CmdLFINDALA, AlwaysAvailable, "{ Indala RFIDs... }"},
{"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"}, {"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"},

View file

@ -424,7 +424,7 @@ static int CmdAWIDClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf awid read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid read`") "to verify");
return res; return res;
} }

View file

@ -701,7 +701,7 @@ static int CmdEM410xWrite(const char *Cmd) {
SendCommandMIX(CMD_LF_EM410X_WRITE, card, (uint32_t)(id >> 32), (uint32_t)id, NULL, 0); SendCommandMIX(CMD_LF_EM410X_WRITE, card, (uint32_t)(id >> 32), (uint32_t)id, NULL, 0);
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 410x_read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") "to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1039,9 +1039,9 @@ static int CmdEM4x50Write(const char *Cmd) {
uint8_t ctmp = tolower(param_getchar(Cmd, 0)); uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_lf_em4x50_write(); if (ctmp == 'h') return usage_lf_em4x50_write();
PrintAndLogEx(NORMAL, "no implemented yet"); PrintAndLogEx(NORMAL, "no implemented yet");
// //
// PrintAndLogEx(SUCCESS, "Done"); // PrintAndLogEx(SUCCESS, "Done");
// PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify"); // PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1440,9 +1440,9 @@ static int CmdEM4x05Write(const char *Cmd) {
int status = demodEM4x05resp(&dummy); int status = demodEM4x05resp(&dummy);
if (status == PM3_SUCCESS) if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Success writing to tag"); PrintAndLogEx(SUCCESS, "Success writing to tag");
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify");
return status; return status;
} }
static int CmdEM4x05Wipe(const char *Cmd) { static int CmdEM4x05Wipe(const char *Cmd) {

View file

@ -303,7 +303,7 @@ static int CmdFdxClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf fdx read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdx read`") "to verify");
return res; return res;
} }

View file

@ -180,7 +180,7 @@ static int CmdGallagherClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf gallagher read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher read`") "to verify");
return res; return res;
} }

View file

@ -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); PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
print_blocks(blocks, ARRAYLEN(blocks)); print_blocks(blocks, ARRAYLEN(blocks));
return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gprox read`") "to verify");
return res;
} }
static int CmdGuardSim(const char *Cmd) { static int CmdGuardSim(const char *Cmd) {

View file

@ -50,7 +50,7 @@ static int usage_lf_hid_watch(void) {
PrintAndLogEx(NORMAL, "Usage: lf hid watch"); PrintAndLogEx(NORMAL, "Usage: lf hid watch");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid watch"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid watch"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_hid_sim(void) { static int usage_lf_hid_sim(void) {
@ -62,11 +62,11 @@ static int usage_lf_hid_sim(void) {
PrintAndLogEx(NORMAL, " h - This help"); PrintAndLogEx(NORMAL, " h - This help");
PrintAndLogEx(NORMAL, " ID - HID id"); PrintAndLogEx(NORMAL, " ID - HID id");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid sim 2006ec0c86"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid sim 2006ec0c86"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_hid_clone(void) { static int usage_lf_hid_clone(void) {
PrintAndLogEx(NORMAL, "Clone HID to T55x7. Tag must be on antenna. "); PrintAndLogEx(NORMAL, "Clone HID to T55x7. " _BLUE_("Tag must be on antenna!"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hid clone [h] [l] ID"); PrintAndLogEx(NORMAL, "Usage: lf hid clone [h] [l] ID");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
@ -74,8 +74,8 @@ static int usage_lf_hid_clone(void) {
PrintAndLogEx(NORMAL, " l - 84bit ID"); PrintAndLogEx(NORMAL, " l - 84bit ID");
PrintAndLogEx(NORMAL, " ID - HID id"); PrintAndLogEx(NORMAL, " ID - HID id");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid clone 2006ec0c86"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone 2006ec0c86"));
PrintAndLogEx(NORMAL, " lf hid clone l 2006ec0c86"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone l 2006ec0c86"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_hid_brute(void) { static int usage_lf_hid_brute(void) {
@ -97,9 +97,9 @@ static int usage_lf_hid_brute(void) {
PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)"); PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 224"));
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 21 d 2000"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 21 d 2000"));
PrintAndLogEx(NORMAL, " lf hid brute v w H10301 f 21 c 200 d 2000"); PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute v w H10301 f 21 c 200 d 2000"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -162,7 +162,7 @@ static int CmdHIDDemod(const char *Cmd) {
uint8_t bits[GraphTraceLen]; uint8_t bits[GraphTraceLen];
size_t size = getFromGraphBuf(bits); size_t size = getFromGraphBuf(bits);
if (size == 0) { if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
return PM3_ESOFT; return PM3_ESOFT;
} }
//get binary from fsk wave //get binary from fsk wave
@ -171,17 +171,17 @@ static int CmdHIDDemod(const char *Cmd) {
if (idx < 0) { if (idx < 0) {
if (idx == -1) if (idx == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
else if (idx == -2) else if (idx == -2)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID just noise detected"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID just noise detected"));
else if (idx == -3) else if (idx == -3)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID problem during FSK demod"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID problem during FSK demod"));
else if (idx == -4) else if (idx == -4)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID preamble not found"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID preamble not found"));
else if (idx == -5) else if (idx == -5)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID error in Manchester data, size %zu", size); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error in Manchester data, size %zu"), size);
else else
PrintAndLogEx(DEBUG, "DEBUG: Error - HID error demoding fsk %d", idx); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -190,12 +190,12 @@ static int CmdHIDDemod(const char *Cmd) {
setClockGrid(50, waveIdx + (idx * 50)); setClockGrid(50, waveIdx + (idx * 50));
if (hi2 == 0 && hi == 0 && lo == 0) { if (hi2 == 0 && hi == 0 && lo == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - HID no values found"); PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID no values found"));
return PM3_ESOFT; return PM3_ESOFT;
} }
if (hi2 != 0) { //extra large HID tags if (hi2 != 0) { //extra large HID tags
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo >> 1) & 0xFFFF); PrintAndLogEx(SUCCESS, "HID Prox TAG ID: " _GREEN_("%x%08x%08x (%u)"), hi2, hi, lo, (lo >> 1) & 0xFFFF);
} else { //standard HID tags <38 bits } else { //standard HID tags <38 bits
uint8_t fmtLen = 0; uint8_t fmtLen = 0;
uint32_t cc = 0; uint32_t cc = 0;
@ -241,14 +241,14 @@ static int CmdHIDDemod(const char *Cmd) {
fc = ((hi & 0xF) << 12) | (lo >> 20); fc = ((hi & 0xF) << 12) | (lo >> 20);
} }
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: %x%08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum); PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: " _GREEN_("%x%08x (%u)")"- Format Len: 32bit - CC: %u - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
} else { } else {
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - OEM: %03u - FC: %u - Card: %u", PrintAndLogEx(SUCCESS, "HID Prox TAG ID: " _GREEN_("%x%08x (%u)")"- Format Len: " _GREEN_("%u bit")"- OEM: %03u - FC: " _GREEN_("%u")"- Card: " _GREEN_("%u"),
hi, lo, cardnum, fmtLen, oem, fc, cardnum); hi, lo, cardnum, fmtLen, oem, fc, cardnum);
} }
} }
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer:", idx, size); PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
if (g_debugMode) if (g_debugMode)
printDemodBuff(); printDemodBuff();
@ -268,6 +268,8 @@ static int CmdHIDWatch(const char *Cmd) {
if (ctmp == 'h') return usage_lf_hid_watch(); if (ctmp == 'h') return usage_lf_hid_watch();
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_HID_DEMOD, NULL, 0); SendCommandNG(CMD_LF_HID_DEMOD, NULL, 0);
PrintAndLogEx(SUCCESS, "Watching for new HID cards - place tag on antenna");
PrintAndLogEx(INFO, "Press pm3-button to stop reading new cards");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -288,18 +290,18 @@ static int CmdHIDSim(const char *Cmd) {
lo = (lo << 4) | (n & 0xf); lo = (lo << 4) | (n & 0xf);
} }
PrintAndLogEx(INFO, "Simulating HID tag with long ID %x%08x%08x", hi2, hi, lo); PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
payload.longFMT = 1; payload.longFMT = 1;
} else { } else {
while (sscanf(&Cmd[i++], "%1x", &n) == 1) { while (sscanf(&Cmd[i++], "%1x", &n) == 1) {
hi = (hi << 4) | (lo >> 28); hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf); lo = (lo << 4) | (n & 0xf);
} }
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID %x%08x", hi, lo); PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0; hi2 = 0;
} }
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
payload.hi2 = hi2; payload.hi2 = hi2;
payload.hi = hi; payload.hi = hi;
@ -331,7 +333,7 @@ static int CmdHIDClone(const char *Cmd) {
lo = (lo << 4) | (n & 0xf); lo = (lo << 4) | (n & 0xf);
} }
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID %x%08x%08x", hi2, hi, lo); PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
longid[0] = 1; longid[0] = 1;
} else { } else {
@ -339,14 +341,14 @@ static int CmdHIDClone(const char *Cmd) {
hi = (hi << 4) | (lo >> 28); hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf); lo = (lo << 4) | (n & 0xf);
} }
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID %x%08x", hi, lo); PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0; hi2 = 0;
} }
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid)); SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf hid read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") "to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -400,7 +402,7 @@ static int CmdHIDBrute(const char *Cmd) {
param_getstr(Cmd, cmdp + 1, format, sizeof(format)); param_getstr(Cmd, cmdp + 1, format, sizeof(format));
format_idx = HIDFindCardFormat(format); format_idx = HIDFindCardFormat(format);
if (format_idx == -1) { if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: %s", format); PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
errors = true; errors = true;
} }
cmdp += 2; cmdp += 2;
@ -431,7 +433,7 @@ static int CmdHIDBrute(const char *Cmd) {
cmdp++; cmdp++;
break; break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter: " _YELLOW_("'%c'"), param_getchar(Cmd, cmdp));
errors = true; errors = true;
break; break;
} }
@ -450,7 +452,7 @@ static int CmdHIDBrute(const char *Cmd) {
PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel); PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel);
PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode); PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode);
PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber); PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber);
switch( direction) { switch (direction) {
case 0: case 0:
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH")); PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH"));
break; break;
@ -460,7 +462,8 @@ static int CmdHIDBrute(const char *Cmd) {
case 2: case 2:
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN")); PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN"));
break; break;
default: break; default:
break;
} }
} }
PrintAndLogEx(INFO, "Brute-forcing HID reader"); PrintAndLogEx(INFO, "Brute-forcing HID reader");
@ -495,7 +498,7 @@ static int CmdHIDBrute(const char *Cmd) {
fin_hi = true; fin_hi = true;
} }
} }
// do one down // do one down
if (direction != 1) { if (direction != 1) {
if (cn_low.CardNumber > 0) { if (cn_low.CardNumber > 0) {
@ -507,7 +510,7 @@ static int CmdHIDBrute(const char *Cmd) {
} }
switch (direction) { switch (direction) {
case 0: case 0:
if (fin_hi && fin_low) { if (fin_hi && fin_low) {
exitloop = true; exitloop = true;
} }
@ -518,7 +521,8 @@ static int CmdHIDBrute(const char *Cmd) {
case 2: case 2:
exitloop = fin_low; exitloop = fin_low;
break; break;
default: break; default:
break;
} }
} while (exitloop == false); } while (exitloop == false);

View file

@ -28,6 +28,8 @@
#include "protocols.h" // t55 defines #include "protocols.h" // t55 defines
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#define INDALA_ARR_LEN 64
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
//large 224 bit indala formats (different preamble too...) //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 + 7]) cardnumber += 16384;
if (bits[offset + 23]) cardnumber += 32768; if (bits[offset + 23]) cardnumber += 32768;
PrintAndLogEx(SUCCESS, "\tHeden-2L | %u", cardnumber); PrintAndLogEx(SUCCESS, "\tHeden-2L | " _YELLOW_("%u"), cardnumber);
} }
// Indala 26 bit decode // Indala 26 bit decode
@ -192,7 +194,7 @@ static int CmdIndalaDemod(const char *Cmd) {
if (DemodBufferLen == 64) { if (DemodBufferLen == 64) {
PrintAndLogEx( PrintAndLogEx(
SUCCESS SUCCESS
, "Indala Found - bitlength %zu, Raw %x%08x" , "Indala Found - bitlength %zu, Raw " _YELLOW_("%x%08x")
, DemodBufferLen , DemodBufferLen
, uid1 , uid1
, uid2 , uid2
@ -244,14 +246,18 @@ static int CmdIndalaDemod(const char *Cmd) {
checksum |= DemodBuffer[63] << 0; // b1 checksum |= DemodBuffer[63] << 0; // b1
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC " _YELLOW_("%u") ", CN " _YELLOW_("%u") ", checksum " _YELLOW_("%1d%1d")
, fc
, csn
, checksum >> 1 & 0x01
, checksum & 0x01
);
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1); PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo); PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo);
decodeHeden2L(DemodBuffer); decodeHeden2L(DemodBuffer);
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01);
} else { } else {
uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32); uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32);
@ -499,6 +505,7 @@ static int CmdIndalaSim(const char *Cmd) {
uint8_t hexuid[100]; uint8_t hexuid[100];
int len = 0; int len = 0;
param_gethex_ex(Cmd, 0, hexuid, &len); param_gethex_ex(Cmd, 0, hexuid, &len);
if (len > 28) if (len > 28)
return usage_lf_indala_sim(); return usage_lf_indala_sim();
@ -542,49 +549,62 @@ static int CmdIndalaSim(const char *Cmd) {
static int CmdIndalaClone(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; bool is_t5555 = false;
int32_t cardnumber; int32_t cardnumber;
uint32_t blocks[8] = {0}; uint32_t blocks[8] = {0};
uint8_t max = 0; uint8_t max = 0;
uint8_t data[7 * 4]; uint8_t data[7 * 4];
int datalen = 0; int datalen = 0;
uint8_t fc = 0;
uint16_t cn = 0;
CLIParserInit("lf indala clone", CLIParserInit("lf indala clone",
"clone INDALA tag to T55x7 (or to q5/T5555)", "clone INDALA tag to T55x7 (or to q5/T5555)",
"Examples:\n" "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 -r a0000000a0002021\n"
"\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"); "\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("lL", "long", "optional - long UID 224 bits"), arg_lit0("lL", "long", "optional - long UID 224 bits"),
arg_int0("cC", "cn", "<decimal>", "Cardnumber for Heden 2L format"), arg_int0("cC", "heden", "<decimal>", "Cardnumber for Heden 2L format"),
arg_strx0("rR", "raw", "<hex>", "raw bytes"), arg_strx0("rR", "raw", "<hex>", "raw bytes"),
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"), 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 arg_param_end
}; };
CLIExecWithReturn(Cmd, argtable, false); CLIExecWithReturn(Cmd, argtable, false);
is_long_uid = arg_get_lit(1); 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) { // raw param
CLIGetHexWithReturn(3, data, &datalen); CLIGetHexWithReturn(3, data, &datalen);
}
is_t5555 = arg_get_lit(4); 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(); CLIParserFree();
if (is_long_uid) { if (is_long_uid) {
// 224 BIT UID // 224 BIT UID
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) // 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) if (is_t5555)
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT); blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
@ -602,12 +622,41 @@ static int CmdIndalaClone(const char *Cmd) {
} else { } else {
// 64 BIT UID // 64 BIT UID
if (got_cn) { if (got_cn) {
PrintAndLogEx(INFO, "Using Indala HEDEN cardnumber %u", cardnumber);
encodeHeden2L(data, cardnumber); encodeHeden2L(data, cardnumber);
datalen = 8; 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) // 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) if (is_t5555)
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT); blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);
@ -622,7 +671,7 @@ static int CmdIndalaClone(const char *Cmd) {
print_blocks(blocks, max); print_blocks(blocks, max);
int res = clone_t55xx_tag(blocks, max); int res = clone_t55xx_tag(blocks, max);
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf indala read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf indala read`") "to verify");
return res; return res;
} }
@ -647,6 +696,71 @@ int CmdLFINDALA(const char *Cmd) {
return CmdsParse(CommandTable, 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;
}
// add parity
bits[34] = 1; // p1 64 - 30 = 34
bits[38] = 1; // p2 68 - 30 = 38
// 92 = 62
// 93 = 63
return PM3_SUCCESS;
}
// redesigned by marshmellow adjusted from existing decode functions // redesigned by marshmellow adjusted from existing decode functions
// indala id decoding // indala id decoding
int detectIndala(uint8_t *dest, size_t *size, uint8_t *invert) { int detectIndala(uint8_t *dest, size_t *size, uint8_t *invert) {

View file

@ -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 detectIndala64(uint8_t *bitStream, size_t *size, uint8_t *invert);
int detectIndala224(uint8_t *bitStream, size_t *size, uint8_t *invert); int detectIndala224(uint8_t *bitStream, size_t *size, uint8_t *invert);
int demodIndala(void); int demodIndala(void);
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits);
#endif #endif

View file

@ -277,7 +277,7 @@ static int CmdIOProxClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf io read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf io read`") "to verify");
return res; return res;
} }

View file

@ -59,20 +59,15 @@ typedef enum {Scramble = 0,Descramble = 1} KeriMSScramble_t;
static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID) static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID)
{ {
// 255 = Not used/Unknown other values are the bit offset in the ID/FC values // 255 = Not used/Unknown other values are the bit offset in the ID/FC values
uint8_t CardToID [] = { 255,255,255,255, 13, 12, 17, 5,255, 6,255, 18, 8,255, 0, 7, uint8_t CardToID [] = { 255,255,255,255, 13, 12, 20, 5, 16, 6, 21, 17, 8,255, 0, 7,
10,255,255, 11, 4, 1,255, 19,255, 20, 2,255, 3, 9,255,255 }; 10, 15,255, 11, 4, 1,255, 18,255, 19, 2, 14, 3, 9,255,255 };
uint8_t CardToFC [] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255, 2,255,255,255,255,255,255,255,255,255,255,255, 1,255 }; uint8_t CardToFC [] = { 255,255,255,255,255,255,255,255,255,255,255,255,255, 0,255,255,
255,255, 2,255,255,255, 3,255, 4,255,255,255,255,255, 1,255 };
uint8_t CardIdx; // 0 - 31 uint8_t CardIdx; // 0 - 31
bool BitState; bool BitState;
// Used to track known bit states - remove when all bit maps are known
char IDDecodeState[33] = {0x00};
char FCDecodeState[33] = {0x00};
memset (IDDecodeState,'-',32);
memset (FCDecodeState,'-',32);
if (Action == Descramble) { if (Action == Descramble) {
*FC = 0; *FC = 0;
*ID = 0; *ID = 0;
@ -82,31 +77,12 @@ static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *I
// Card ID // Card ID
if (CardToID[CardIdx] < 32) { if (CardToID[CardIdx] < 32) {
*ID = *ID | (BitState << CardToID[CardIdx]); *ID = *ID | (BitState << CardToID[CardIdx]);
// Remove when all bits are known
IDDecodeState[31-CardToID[CardIdx]] = '0'+BitState;
} }
// Card FC // Card FC
if (CardToFC[CardIdx] < 32) { if (CardToFC[CardIdx] < 32) {
*FC = *FC | (BitState << CardToFC[CardIdx]); *FC = *FC | (BitState << CardToFC[CardIdx]);
// Remove when all bits are known
FCDecodeState[31-CardToFC[CardIdx]] = '0'+BitState;
} }
} }
// Patch for bit order group unknown - remove when all Keri MS Bits maps are known
// Reverse order for easy mapping for unknowns
// I know that these bit groups are a in the correct location, unknown order.
if (IDDecodeState[31-17] == '1') IDDecodeState[31-17] = '?';
if (IDDecodeState[31-18] == '1') IDDecodeState[31-18] = '?';
if (IDDecodeState[31-19] == '1') IDDecodeState[31-19] = '?';
if (IDDecodeState[31-20] == '1') IDDecodeState[31-20] = '?';
if (FCDecodeState[31- 1] == '1') FCDecodeState[31- 1] = '?';
if (FCDecodeState[31- 2] == '1') FCDecodeState[31- 2] = '?';
PrintAndLogEx(SUCCESS, "Partial Keri MS decode");
PrintAndLogEx(SUCCESS, "BitState ID : %s",IDDecodeState);
PrintAndLogEx(SUCCESS, "BitState FC : %s",FCDecodeState);
} }
if (Action == Scramble) if (Action == Scramble)
@ -119,12 +95,12 @@ static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *I
if (CardToID[CardIdx] < 32) { if (CardToID[CardIdx] < 32) {
if ((*ID & (1 << CardToID[CardIdx])) > 0) if ((*ID & (1 << CardToID[CardIdx])) > 0)
*CardID |= (1 << CardIdx); *CardID |= (1 << CardIdx);
} }
// Card FC // Card FC
if (CardToFC[CardIdx] < 32) { if (CardToFC[CardIdx] < 32) {
if ((*ID & (1 << CardToFC[CardIdx])) > 0) if ((*ID & (1 << CardToFC[CardIdx])) > 0)
*CardID |= (1 << CardIdx); *CardID |= (1 << CardIdx);
} }
} }
// Fixed bits and parity/check bits // Fixed bits and parity/check bits
@ -144,7 +120,7 @@ static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *I
*CardID = *CardID | Parity; *CardID = *CardID | Parity;
// Bit 31 was fixed but not in check/parity bits // Bit 31 was fixed but not in check/parity bits
*CardID |= (1 << 31); *CardID |= (uint32_t)(1 << 31);
PrintAndLogEx(SUCCESS, "Scrambled FC : %d - Card ID : %d to RAW : E0000000%08X",*FC,*ID,*CardID); PrintAndLogEx(SUCCESS, "Scrambled FC : %d - Card ID : %d to RAW : E0000000%08X",*FC,*ID,*CardID);
} }
@ -282,7 +258,7 @@ static int CmdKeriClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf keri read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf keri read`") "to verify");
return res; return res;
} }

View file

@ -179,7 +179,7 @@ static int CmdMotorolaClone(const char *Cmd) {
print_blocks(blocks, ARRAYLEN(blocks)); print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf motorola read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") "to verify");
return res; return res;
} }

View file

@ -476,7 +476,7 @@ static int CmdLFNedapClone(const char *Cmd) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
} }
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf nedap read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nedap read`") "to verify");
return res; return res;
} }

View file

@ -160,7 +160,7 @@ static int CmdNexWatchClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf nexwatch read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") "to verify");
return res; return res;
} }

View file

@ -171,7 +171,7 @@ static int CmdNoralsyClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf noralsy read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") "to verify");
return res; return res;
} }

View file

@ -241,7 +241,7 @@ static int CmdPacClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pac read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") "to verify");
return res; return res;
} }

View file

@ -171,7 +171,7 @@ static int CmdParadoxClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf paradox read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") "to verify");
return res; return res;
} }

View file

@ -151,7 +151,7 @@ static int CmdLFPCF7931Write(const char *Cmd) {
SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf)); SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pcf7931 read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 read`") "to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -138,7 +138,7 @@ static int CmdPrescoClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf presco read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") "to verify");
return res; return res;
} }

View file

@ -252,7 +252,7 @@ static int CmdPyramidClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf pyramid read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") "to verify");
return res; return res;
} }

View file

@ -170,7 +170,7 @@ static int CmdSecurakeyClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf securakey read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") "to verify");
return res; return res;
} }

View file

@ -297,7 +297,7 @@ static int CmdTIWrite(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0); SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf ti read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti read`") "to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -123,7 +123,7 @@ static int CmdVerichipClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf verichip read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf verichip read`") "to verify");
return res; return res;
} }

View file

@ -118,7 +118,7 @@ static int CmdVikingClone(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf viking read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") "to verify");
return resp.status; return resp.status;
} }

View file

@ -186,7 +186,7 @@ static int CmdVisa2kClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf visa2000 read`") "to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") "to verify");
return res; return res;
} }

View file

@ -36,9 +36,23 @@
#include "cmdwiegand.h" // wiegand commands #include "cmdwiegand.h" // wiegand commands
#include "ui.h" #include "ui.h"
#include "util_posix.h" #include "util_posix.h"
#include "commonutil.h" // ARRAYLEN
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_hints(void) {
PrintAndLogEx(NORMAL, "Turn on/off hints");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: hints [h] <0|1>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " <0|1> off or on");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hints 1");
return PM3_SUCCESS;
}
static int usage_msleep(void) { static int usage_msleep(void) {
PrintAndLogEx(NORMAL, "Sleep for given amount of milliseconds"); PrintAndLogEx(NORMAL, "Sleep for given amount of milliseconds");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
@ -78,6 +92,70 @@ static void AppendDate(char *s, size_t slen, char *fmt) {
strftime(s, slen, fmt, ct); strftime(s, slen, fmt, ct);
} }
static int lf_search_plus(const char *Cmd) {
sample_config oldconfig;
memset(&oldconfig, 0, sizeof(sample_config));
int retval = lf_getconfig(&oldconfig);
if (retval != PM3_SUCCESS) {
PrintAndLogEx(ERR, "failed to get current device config");
return retval;
}
// Divisor : frequency(khz)
// 95 88 47 31 23
// 125.00 134.83 250.00 375.00 500.00
int16_t default_divisor[] = {95, 88, 47, 31, 23};
/*
default LF config is set to:
decimation = 1
bits_per_sample = 8
averaging = YES
divisor = 95 (125kHz)
trigger_threshold = 0
samples_to_skip = 0
verbose = YES
*/
sample_config config = {
.decimation = 1,
.bits_per_sample = 8,
.averaging = 1,
.trigger_threshold = 0,
.samples_to_skip = 0,
.verbose = false
};
// Iteration defaults
for (int i = 0; i < ARRAYLEN(default_divisor); ++i) {
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "Keyboard pressed. Done.");
break;
}
// Try to change config!
uint32_t d;
d = config.divisor = default_divisor[i];
PrintAndLogEx(INFO, "--> trying ( " _GREEN_("%d.%02d kHz")")", 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100));
retval = lf_config(&config);
if (retval != PM3_SUCCESS)
break;
// The config for pm3 is changed, we can trying search!
retval = CmdLFfind(Cmd);
if (retval == PM3_SUCCESS)
break;
}
lf_config(&oldconfig);
return retval;
}
static int CmdAuto(const char *Cmd) { static int CmdAuto(const char *Cmd) {
char ctmp = tolower(param_getchar(Cmd, 0)); char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_auto(); if (ctmp == 'h') return usage_auto();
@ -90,8 +168,12 @@ static int CmdAuto(const char *Cmd) {
if (ret == PM3_SUCCESS) if (ret == PM3_SUCCESS)
return ret; return ret;
ret = lf_search_plus("");
if (ret == PM3_SUCCESS)
return ret;
PrintAndLogEx(INFO, "Failed both LF / HF SEARCH,"); PrintAndLogEx(INFO, "Failed both LF / HF SEARCH,");
PrintAndLogEx(INFO, "Trying 'lf read' and save a trace for you..."); PrintAndLogEx(INFO, "Trying " _YELLOW_("`lf read`") "and save a trace for you");
CmdPlot(""); CmdPlot("");
lf_read(false, 40000); lf_read(false, 40000);
@ -109,6 +191,33 @@ int CmdRem(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHints(const char *Cmd) {
uint32_t ms = 0;
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_hints();
if (strlen(Cmd) > 1){
str_lower((char *)Cmd);
if (str_startswith(Cmd, "of")) {
session.show_hints = false;
} else {
session.show_hints = true;
}
} else if (strlen(Cmd) == 1) {
if (param_getchar(Cmd, 0) != 0x00) {
ms = param_get32ex(Cmd, 0, 0, 10);
if (ms == 0) {
session.show_hints = false;
} else {
session.show_hints = true;
}
}
}
PrintAndLogEx(INFO, "Hints are %s", (session.show_hints) ? "ON" : "OFF");
return PM3_SUCCESS;
}
static int CmdMsleep(const char *Cmd) { static int CmdMsleep(const char *Cmd) {
uint32_t ms = 0; uint32_t ms = 0;
char ctmp = tolower(param_getchar(Cmd, 0)); char ctmp = tolower(param_getchar(Cmd, 0));
@ -149,6 +258,7 @@ static command_t CommandTable[] = {
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"}, {"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"}, {"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
{"", CmdHelp, AlwaysAvailable, ""}, {"", CmdHelp, AlwaysAvailable, ""},
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"}, {"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
{"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"}, {"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"},
{"quit", CmdQuit, AlwaysAvailable, ""}, {"quit", CmdQuit, AlwaysAvailable, ""},

View file

@ -1076,7 +1076,7 @@ f0f0172066b2
f3864fcca693 f3864fcca693
f3f0172066b2 f3f0172066b2
fc9839273862 fc9839273862
#
# various hotel keys # various hotel keys
34D3C568B348 34D3C568B348
91FF18E63887 91FF18E63887
@ -1084,3 +1084,27 @@ fc9839273862
354A787087F1 354A787087F1
4a306e62e9b6 4a306e62e9b6
B9C874AE63D0 B9C874AE63D0
#
# Data from offical repo
f00dfeedd0d0
0bb31dc123e5
7578bf2c66a9
cd212889c3ed
6936c035ae1b
c6c866aa421e
590bd659cdd2
aa734d2f40e0
09800ff94aaf
5a12f83326e7
c554ef6a6015
0d8ca561bdf3
b8937130b6ba
d7744a1a0c44
82908b57ef4f
fe04ecfe5577
# comfort inn hotel
4d57414c5648
4d48414c5648
#
# unknown hotel key
6d9b485a4845

1861
client/emojis.h Normal file

File diff suppressed because it is too large Load diff

15
client/emojis_alt.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef EMOJIS_ALT_H__
#define EMOJIS_ALT_H__
typedef struct emoji_alt_s {
const char *alias;
const char *alttext;
} emoji_alt_t;
// emoji_alt_t array are expected to be NULL terminated
static emoji_alt_t EmojiAltTable[] = {
{":wink:", ";)"},
{NULL, NULL}
};
#endif

38
client/emojis_scrap_github.py Executable file
View file

@ -0,0 +1,38 @@
#!/usr/bin/env python3
# Mostly derived from https://github.com/mrowa44/emojify Copyright (c) 2015 Justyna Rachowicz
from urllib.request import urlopen
import json
EMOJI_JSON_URL = 'https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json'
def print_emoji(emoji_json):
for alias in emoji_json['aliases']:
print(' {{":{0}:", "{1}"}}, // {2}'.format(alias,
''.join('\\x{:02x}'.format(b) for b in emoji_json['emoji'].encode('utf8')),
emoji_json['emoji']))
print(
"""#ifndef EMOJIS_H__
#define EMOJIS_H__
typedef struct emoji_s {
const char *alias;
const char *emoji;
} emoji_t;
// emoji_t array are expected to be NULL terminated
static emoji_t EmojiTable[] = {""")
with urlopen(EMOJI_JSON_URL) as conn:
emojis_json = json.loads(conn.read().decode('utf-8'))
for emoji_json in emojis_json:
print_emoji(emoji_json)
print(""" {NULL, NULL}
};
#endif""")

View file

@ -70,7 +70,7 @@ struct wave_info_t {
char tag[4]; char tag[4];
uint32_t size; uint32_t size;
} PACKED audio_data; } PACKED audio_data;
} PACKED wave_info; } PACKED;
/** /**
* @brief checks if a file exists * @brief checks if a file exists

View file

@ -529,7 +529,7 @@ const char ice[] =
" !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n" " !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n"
_RED_(" . .. .. . . .. ... . . . . . .. . ") _RED_(" . .. .. . . .. ... . . . . . .. . ")
"\n...................................................................\n" "\n...................................................................\n"
; ;
// Write a file's segments to Flash // Write a file's segments to Flash
int flash_write(flash_file_t *ctx) { int flash_write(flash_file_t *ctx) {
@ -566,8 +566,8 @@ int flash_write(flash_file_t *ctx) {
baddr += block_size; baddr += block_size;
length -= block_size; length -= block_size;
block++; block++;
if ( len < strlen(ice) ) { if (len < strlen(ice)) {
if (filter_ansi && !isalpha(ice[len]) ) { if (filter_ansi && !isalpha(ice[len])) {
len++; len++;
} else { } else {
fprintf(stdout, "%c", ice[len++]); fprintf(stdout, "%c", ice[len++]);

View file

@ -0,0 +1,231 @@
local utils = require('utils')
local getopt = require('getopt')
local read14a = require('read14a')
--[[
---Suggestions of improvement:
--- Add support another types of dumps: BIN, JSON
--- Maybe it will be not only as `mfc_gen3_writer`, like a universal dump manager.
--- Add undependence from the operation system. At the moment code not working in Linux.
--- Add more chinesse backdoors RAW commands for UID changing (find RAW for the 4 byte familiar chinese card, from native it soft: http://bit.ly/39VIDsU)
--- Hide system messages when you writing a dumps, replace it to some of like [#####----------] 40%
-- iceman notes:
-- doesn't take consideration filepaths for dump files.
-- doesn't allow A keys for authenticating when writing
-- doesn't verify that card is magic gen3.
-- doesn't take several versions of same dump ( -1, -2, -3 ) styles.
--]]
copyright = ''
author = 'Winds'
version = 'v1.0.0'
desc = [[
The script gives you a easy way to write your *.eml dumps onto normal MFC and magic Gen3 cards.
Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards.
The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards.
It supports the following functionality.
1. Write it to the same of current card UID.
2. Write it to magic Gen3 card.
3. Change uid to match dump on magic Gen3 card.
4. Permanent lock UID on magic Gen3 card.
5. Erase all data at the card and set the FF FF FF FF FF FF keys, and Access Conditions to 78778800.
Script works in a wizard styled way.
]]
example = [[
1. script run mfc_gen3_writer
]]
usage = [[
Select your *.eml dump from list to write to the card.
]]
-- Some globals
local DEBUG = false -- the debug flag
-------------------------------
-- Some utilities
-------------------------------
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print('Example usage')
print(example)
print(usage)
end
---
-- GetUID
local function GetUID()
return read14a.read(true, true).uid
end
---
--
local function dropfield()
read14a.disconnect()
core.clearCommandBuffer()
end
---
-- Wait for tag (MFC)
local function wait()
read14a.waitFor14443a()
end
---
--
local function main(args)
-- Arguments for the script
for o, a in getopt.getopt(args, 'hd') do
if o == 'h' then return help() end
if o == 'd' then DEBUG = true end
end
local files = {} -- Array for eml files
local b_keys = {} -- Array for B keys
local eml = {} -- Array for data in block 32
local num_dumps = 0 -- num of found eml dump files
local tab = string.rep('-', 64)
--
wait()
print(tab)
local length = 25
local e = 16
-- Detect 7 byte card
if string.len(GetUID()) == 14 then
length = 31
e = 22
end
dropfield()
---List all EML files in /client
local dumpEML = "find '.' -iname '*dump.eml' -type f"
local p = assert(io.popen(dumpEML))
for _ in p:lines() do
-- The length of eml file
if string.len(_) == length then
num_dumps = num_dumps + 1
-- cut UID from eml file
files[num_dumps] = string.sub(_, 9, e)
print(' '..num_dumps..' | '..files[num_dumps])
end
end
p.close()
if num_dumps == 0 then return oops("Didn't find any dump files") end
print(tab)
print(' Your card has UID '..GetUID())
print('')
print(' Select which dump to write (1 until '..num_dumps..')')
print(tab)
io.write(' --> ')
local no = tonumber(io.read())
print(tab)
print(' You have been selected card dump ' .. no .. ', with UID : '..files[no])
--- Load eml file
local dumpfile = assert(io.open('./hf-mf-' .. files[no] .. '-dump.eml', 'r'))
for _ in dumpfile:lines() do table.insert(eml, _); end
dumpfile.close()
--- Extract B key from EML file
local b = 0
for i = 1, #eml do
if (i % 4 == 0) then
repeat
b = b + 1
-- Cut key from block
b_keys[b] = string.sub(eml[i], (#eml[i] - 11), #eml[i])
until b % 4 == 0
end
end
print(tab)
dbg(b_keys)
dbg(eml)
--- Change UID on certain version of magic Gen3 card.
if (utils.confirm(' Change UID ?') == true) then
wait()
--core.console('hf 14a raw -s -c -t 2000 90f0cccc10'..tostring(eml[1]))
print('hf 14a raw -s -c -t 2000 90f0cccc10'..tostring(eml[1]))
print(tab)
print(' The new card UID : ' .. GetUID())
end
print(tab)
--- Lock UID
if (utils.confirm(' Permanent lock UID ? (card can never change uid again) ') == true) then
wait()
core.console('hf 14a raw -s -c -t 2000 90fd111100')
end
print(tab)
--- Writing blocks
local default_key = 'FFFFFFFFFFFF'
local default_key_blk = 'FFFFFFFFFFFF78778800FFFFFFFFFFFF'
local empty = string.rep('0', 32)
local cmd_wrbl = 'hf mf wrbl %d B %s %s'
if (utils.confirm(' Are you using a empty card with default key?') == true) then
wait()
for i = 1, #eml do
core.console(string.format(cmd_wrbl, (i-1), default_key, eml[i]))
end
else
print(tab)
if (utils.confirm(' Delete ALL data and write all keys to 0x'..default_key..' ?') == true) then
wait()
for i = 1, #eml do
if (i % 4 == 0) then
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], default_key_blk))
else
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], empty))
end
end
else
print(tab)
print('Writing to card')
wait()
for i = 1, #eml do
core.console(string.format(cmd_wrbl, (i-1), b_keys[i], eml[i]))
end
end
end
dropfield()
print(tab)
print('Done')
end
main(args)

View file

@ -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') local getopt = require('getopt')
copyright = '' copyright = ''
author = 'Keld Norman' author = 'Daniel Underhay (updated), Keld Norman(original)'
version = 'v1.0.0' version = 'v2.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
]]
usage = [[ 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: Arguments:
-h this help -h this help
-s 0-0xFFFFFFFF start id -s 0-0xFFFFFFFF start id
-e 0-0xFFFFFFFF end 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) print(usage)
end end
--- ---
-- Exit message --- Print user message
local function exitMsg(msg) local function msg(msg)
print( string.rep('--',20) ) print( string.rep('--',20) )
print('')
print(msg) print(msg)
print('')
print( string.rep('--',20) ) print( string.rep('--',20) )
print()
end end
--- ---
-- Start -- Start
local function main(args) local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
local timeout = 0 local timeout = 0
local start_id = 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 == 's' then start_id = a end
if o == 'e' then end_id = a end if o == 'e' then end_id = a end
if o == 't' then timeout = a end if o == 't' then timeout = a end
if o == 'x' then mftype = a end
if o == 'h' then return print(usage) end if o == 'h' then return print(usage) end
end end
-- template -- template
local command = 'hf 14a sim t 1 u %08X' local command = ''
print(' Bruteforcing MFC card numbers from 00000000 to FFFFFFFF using delay: '..timeout) if mftype == 'mfc' then
print('') command = 'hf 14a sim t 1 u %14X'
print( string.rep('--',20) ) 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 for n = start_id, end_id do
local c = string.format( command, n ) local c = string.format( command, n )
print(' Running: "'..c..'"') print('Running: "'..c..'"')
core.console(c) core.console(c)
core.console('msleep '..timeout); core.console('msleep '..timeout);
core.console('hw ping') core.console('hw ping')
@ -102,4 +117,3 @@ local function main(args)
end end
main(args) main(args)

View file

@ -152,7 +152,7 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
if (*key != UINT64_C(-1)) { if (*key != UINT64_C(-1)) {
break; break;
} else { } else {
PrintAndLogEx(FAILED, "all candidate keys failed. Restarting darkside attack"); PrintAndLogEx(FAILED, "all key candidates failed. Restarting darkside attack");
free(last_keylist); free(last_keylist);
last_keylist = keylist; last_keylist = keylist;
first_run = true; 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 // copy candidatekeys to test key block
memcpy(keyBlock, candidates + i, KEYBLOCK_SIZE); 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) { if (mfCheckKeys(blockNo, keyType, true, KEYS_IN_BLOCK, keyBlock, &key64) == PM3_SUCCESS) {
*resultkey = key64; *resultkey = key64;
found = true; 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; uint32_t keycnt = statelists[0].len;
if (keycnt == 0) goto out; 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); memset(resultKey, 0, 6);
uint64_t key64 = -1; uint64_t key64 = -1;
@ -544,10 +544,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
return -5; return -5;
} }
float bruteforce_per_second = (float)KEYS_IN_BLOCK / (msclock() - start_time) * 1000.0; // if (i + 1 % 10 == 0) {
float bruteforce_per_second = (float)(i + max_keys) / ((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);
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; uint32_t keycnt = statelists[0].len;
if (keycnt == 0) goto out; 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); memset(resultKey, 0, 6);
uint64_t key64 = -1; 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 maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK;
uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt; 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) { if (mem == NULL) {
free(statelists[0].head.slhead); free(statelists[0].head.slhead);
return PM3_EMALLOC; 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); mem[4] = (max_keys_chunk & 0xFF);
uint8_t destfn[32]; 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(); uint64_t start_time = msclock();
for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) { 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); 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()) { if (IfPm3Flash()) {
// upload to flash. // upload to flash.
res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6) ); res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6));
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "SPIFFS upload failed"); PrintAndLogEx(WARNING, "SPIFFS upload failed");
free(mem); free(mem);
@ -705,13 +705,13 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
} }
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
p_keyblock = NULL; p_keyblock = NULL;
free(statelists[0].head.slhead); free(statelists[0].head.slhead);
free(mem); 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->block,
package->keytype ? 'B' : 'A', package->keytype ? 'B' : 'A',
sprint_hex_inrow(resultKey, 6) 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) { // if (i%10 == 0) {
float bruteforce_per_second = (float)i + max_keys_chunk / (msclock() - start_time) * 1000.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); 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);
// } // }
} }
@ -1316,6 +1316,8 @@ int detect_classic_nackbug(bool verbose) {
SendCommandNG(CMD_HF_MIFARE_NACK_DETECT, NULL, 0); SendCommandNG(CMD_HF_MIFARE_NACK_DETECT, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
PrintAndLogEx(INFO, "Checking for NACK bug");
if (verbose) if (verbose)
PrintAndLogEx(SUCCESS, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client.\n"); PrintAndLogEx(SUCCESS, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client.\n");
@ -1358,16 +1360,16 @@ int detect_classic_nackbug(bool verbose) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
case 2 : case 2 :
PrintAndLogEx(SUCCESS, _GREEN_("always leak NACK detected")); PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("always leak NACK"));
return PM3_SUCCESS; return PM3_SUCCESS;
case 1 : case 1 :
PrintAndLogEx(SUCCESS, _GREEN_("NACK bug detected")); PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("detected"));
return PM3_SUCCESS; return PM3_SUCCESS;
case 0 : case 0 :
PrintAndLogEx(SUCCESS, "No NACK bug detected"); PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("no bug"));
return PM3_SUCCESS; return PM3_SUCCESS;
default : default :
PrintAndLogEx(ERR, "errorcode from device [%i]", ok); PrintAndLogEx(ERR, "errorcode from device " _RED_("[%i]"), ok);
return PM3_EUNDEF; return PM3_EUNDEF;
} }
break; break;

View file

@ -56,7 +56,6 @@ extern size_t g_DemodStartIdx;
extern bool showDemod; extern bool showDemod;
extern uint8_t g_debugMode; extern uint8_t g_debugMode;
#ifndef FILE_PATH_SIZE #ifndef FILE_PATH_SIZE
#define FILE_PATH_SIZE 1000 #define FILE_PATH_SIZE 1000
#endif #endif

View file

@ -199,7 +199,7 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
setLayout(layout); setLayout(layout);
// plot window title // 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); setWindowTitle(pt);
// shows plot window on the screen. // shows plot window on the screen.
@ -210,7 +210,7 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
controlWidget->resize(size().width(), 200); controlWidget->resize(size().width(), 200);
// Olverlays / slider window title // 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->setWindowTitle(ct);
controlWidget->show(); controlWidget->show();

View file

@ -36,14 +36,14 @@ static void showBanner(void) {
PrintAndLogEx(NORMAL, " " _BLUE_("██████╗ ███╗ ███╗ ████╗ ")); PrintAndLogEx(NORMAL, " " _BLUE_("██████╗ ███╗ ███╗ ████╗ "));
PrintAndLogEx(NORMAL, " " _BLUE_("██╔══██╗████╗ ████║ ══█║")); PrintAndLogEx(NORMAL, " " _BLUE_("██╔══██╗████╗ ████║ ══█║"));
PrintAndLogEx(NORMAL, " " _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); PrintAndLogEx(NORMAL, " " _BLUE_("██████╔╝██╔████╔██║ ████╔╝"));
PrintAndLogEx(NORMAL, " " _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net"); PrintAndLogEx(NORMAL, " " _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " :snowflake: iceman@icesql.net :coffee:");
PrintAndLogEx(NORMAL, " " _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/"); PrintAndLogEx(NORMAL, " " _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/");
PrintAndLogEx(NORMAL, " " _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0"); PrintAndLogEx(NORMAL, " " _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0");
#else #else
PrintAndLogEx(NORMAL, " ======. ===. ===. ====."); PrintAndLogEx(NORMAL, " ======. ===. ===. ====.");
PrintAndLogEx(NORMAL, " ==...==.====. ====. ..=."); PrintAndLogEx(NORMAL, " ==...==.====. ====. ..=.");
PrintAndLogEx(NORMAL, " ======..==.====.==. ====.."); PrintAndLogEx(NORMAL, " ======..==.====.==. ====..");
PrintAndLogEx(NORMAL, " ==..... ==..==..==. ..=. iceman@icesql.net"); PrintAndLogEx(NORMAL, " ==..... ==..==..==. ..=. iceman@icesql.net :coffee:");
PrintAndLogEx(NORMAL, " ==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/"); PrintAndLogEx(NORMAL, " ==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/");
PrintAndLogEx(NORMAL, " ... ... ... ..... pre-release v4.0"); PrintAndLogEx(NORMAL, " ... ... ... ..... pre-release v4.0");
#endif #endif
@ -58,7 +58,11 @@ static void showBanner(void) {
static int check_comm(void) { static int check_comm(void) {
// If communications thread goes down. Device disconnected then this should hook up PM3 again. // If communications thread goes down. Device disconnected then this should hook up PM3 again.
if (IsCommunicationThreadDead() && session.pm3_present) { if (IsCommunicationThreadDead() && session.pm3_present) {
rl_set_prompt(PROXPROMPT_OFFLINE); if (session.supports_colors)
rl_set_prompt(PROXPROMPT_OFFLINE_COLOR);
else
rl_set_prompt(PROXPROMPT_OFFLINE);
rl_forced_update_display(); rl_forced_update_display();
CloseProxmark(); CloseProxmark();
PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Use "_YELLOW_("\"hw connect\"") "to reconnect\n"); PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Use "_YELLOW_("\"hw connect\"") "to reconnect\n");
@ -150,7 +154,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
// loops every time enter is pressed... // loops every time enter is pressed...
while (1) { while (1) {
bool printprompt = false; bool printprompt = false;
const char *prompt = PROXPROMPT_CON; const char *prompt = (session.supports_colors) ? PROXPROMPT_CON_COLOR : PROXPROMPT_CON;
check_script: check_script:
// If there is a script file // If there is a script file
@ -214,11 +218,11 @@ check_script:
rl_event_hook = check_comm; rl_event_hook = check_comm;
if (session.pm3_present) { if (session.pm3_present) {
if (conn.send_via_fpc_usart == false) if (conn.send_via_fpc_usart == false)
prompt = PROXPROMPT_USB; prompt = (session.supports_colors) ? PROXPROMPT_USB_COLOR : PROXPROMPT_USB;
else else
prompt = PROXPROMPT_FPC; prompt = (session.supports_colors) ? PROXPROMPT_FPC_COLOR : PROXPROMPT_FPC;
} else { } else {
prompt = PROXPROMPT_OFFLINE; prompt = (session.supports_colors) ? PROXPROMPT_OFFLINE_COLOR : PROXPROMPT_OFFLINE;
} }
cmd = readline(prompt); cmd = readline(prompt);
fflush(NULL); fflush(NULL);
@ -756,6 +760,7 @@ int main(int argc, char *argv[]) {
} }
session.supports_colors = DetectWindowsAnsiSupport(); session.supports_colors = DetectWindowsAnsiSupport();
session.emoji_mode = ALTTEXT;
session.stdinOnTTY = isatty(STDIN_FILENO); session.stdinOnTTY = isatty(STDIN_FILENO);
session.stdoutOnTTY = isatty(STDOUT_FILENO); session.stdoutOnTTY = isatty(STDOUT_FILENO);
@ -766,8 +771,10 @@ int main(int argc, char *argv[]) {
// For info, grep --color=auto is doing sth like this, plus test getenv("TERM") != "dumb": // For info, grep --color=auto is doing sth like this, plus test getenv("TERM") != "dumb":
// struct stat tmp_stat; // struct stat tmp_stat;
// if ((fstat (STDOUT_FILENO, &tmp_stat) == 0) && (S_ISCHR (tmp_stat.st_mode)) && isatty(STDIN_FILENO)) // if ((fstat (STDOUT_FILENO, &tmp_stat) == 0) && (S_ISCHR (tmp_stat.st_mode)) && isatty(STDIN_FILENO))
if (session.stdinOnTTY && session.stdoutOnTTY) if (session.stdinOnTTY && session.stdoutOnTTY) {
session.supports_colors = true; session.supports_colors = true;
session.emoji_mode = EMOJI;
}
#endif #endif
// Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway
if (speed == 0) if (speed == 0)

View file

@ -15,9 +15,17 @@
#include "common.h" #include "common.h"
#define PROXPROMPT_CON "[con] pm3 --> " #define PROXPROMPT_CON "[con] pm3 --> "
#define PROXPROMPT_CON_COLOR "[\001\033[1;32m\002con\001\033[0m\002] pm3 --> "
#define PROXPROMPT_USB "[usb] pm3 --> " #define PROXPROMPT_USB "[usb] pm3 --> "
#define PROXPROMPT_USB_COLOR "[\001\033[1;32m\002usb\001\033[0m\002] pm3 --> "
#define PROXPROMPT_FPC "[fpc] pm3 --> " #define PROXPROMPT_FPC "[fpc] pm3 --> "
#define PROXPROMPT_FPC_COLOR "[\001\033[1;32m\002fpc\001\033[0m\002] pm3 --> "
#define PROXPROMPT_OFFLINE "[offline] pm3 --> " #define PROXPROMPT_OFFLINE "[offline] pm3 --> "
#define PROXPROMPT_OFFLINE_COLOR "[\001\033[1;31m\002offline\001\033[0m\002] pm3 --> "
#define PROXHISTORY "history.txt" #define PROXHISTORY "history.txt"
#define PROXLOG "log_%Y%m%d.txt" #define PROXLOG "log_%Y%m%d.txt"
#define MAX_NESTED_CMDSCRIPT 10 #define MAX_NESTED_CMDSCRIPT 10

View file

@ -31,6 +31,8 @@
# include <direct.h> // _mkdir # include <direct.h> // _mkdir
#endif #endif
#include <time.h> #include <time.h>
#include "emojis.h"
#include "emojis_alt.h"
session_arg_t session; session_arg_t session;
double CursorScaleFactor = 1; double CursorScaleFactor = 1;
@ -127,39 +129,61 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
// skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG 0' // skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG 0'
if (g_debugMode == 0 && level == DEBUG) if (g_debugMode == 0 && level == DEBUG)
return; return;
// skip HINT messages if client has hints turned off i.e. 'HINT 0'
if (session.show_hints == false && level == HINT)
return;
char prefix[20] = {0}; char prefix[40] = {0};
char buffer[MAX_PRINT_BUFFER] = {0}; char buffer[MAX_PRINT_BUFFER] = {0};
char buffer2[MAX_PRINT_BUFFER + 20] = {0}; char buffer2[MAX_PRINT_BUFFER + sizeof(prefix)] = {0};
char *token = NULL; char *token = NULL;
char *tmp_ptr = NULL; char *tmp_ptr = NULL;
FILE *stream = stdout; FILE *stream = stdout;
const char *spinner[] = {_YELLOW_("[\\]"), _YELLOW_("[|]"), _YELLOW_("[/]"), _YELLOW_("[-]")}; const char *spinner[] = {_YELLOW_("[\\]"), _YELLOW_("[|]"), _YELLOW_("[/]"), _YELLOW_("[-]")};
const char *spinner_emoji[] = {" :clock1: ", " :clock2: ", " :clock3: ", " :clock4: ", " :clock5: ", " :clock6: ",
" :clock7: ", " :clock8: ", " :clock9: ", " :clock10: ", " :clock11: ", " :clock12: "};
switch (level) { switch (level) {
case ERR: case ERR:
strncpy(prefix, _RED_("[!!]"), sizeof(prefix) - 1); if (session.emoji_mode == EMOJI)
strncpy(prefix, _RED_("[!!]") " :rotating_light: ", sizeof(prefix) - 1);
else
strncpy(prefix, _RED_("[!!]"), sizeof(prefix) - 1);
stream = stderr; stream = stderr;
break; break;
case FAILED: case FAILED:
strncpy(prefix, _RED_("[-]"), sizeof(prefix) - 1); if (session.emoji_mode == EMOJI)
strncpy(prefix, _RED_("[-]") " :no_entry: ", sizeof(prefix) - 1);
else
strncpy(prefix, _RED_("[-]"), sizeof(prefix) - 1);
break; break;
case DEBUG: case DEBUG:
strncpy(prefix, _BLUE_("[#]"), sizeof(prefix) - 1); strncpy(prefix, _BLUE_("[#]"), sizeof(prefix) - 1);
break; case HINT:
case SUCCESS: case SUCCESS:
strncpy(prefix, _GREEN_("[+]"), sizeof(prefix) - 1); strncpy(prefix, _GREEN_("[+]"), sizeof(prefix) - 1);
break; break;
case WARNING: case WARNING:
strncpy(prefix, _CYAN_("[!]"), sizeof(prefix) - 1); if (session.emoji_mode == EMOJI)
strncpy(prefix, _CYAN_("[!]") " :warning: ", sizeof(prefix) - 1);
else
strncpy(prefix, _CYAN_("[!]"), sizeof(prefix) - 1);
break; break;
case INFO: case INFO:
strncpy(prefix, _YELLOW_("[=]"), sizeof(prefix) - 1); strncpy(prefix, _YELLOW_("[=]"), sizeof(prefix) - 1);
break; break;
case INPLACE: case INPLACE:
strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1); if (session.emoji_mode == EMOJI) {
PrintAndLogEx_spinidx++; strncpy(prefix, spinner_emoji[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
if (PrintAndLogEx_spinidx == ARRAYLEN(spinner)) PrintAndLogEx_spinidx++;
PrintAndLogEx_spinidx = 0; if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji))
PrintAndLogEx_spinidx = 0;
} else {
strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
PrintAndLogEx_spinidx++;
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner))
PrintAndLogEx_spinidx = 0;
}
break; break;
case NORMAL: case NORMAL:
// no prefixes for normal // no prefixes for normal
@ -202,9 +226,11 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
} else { } else {
snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer);
if (level == INPLACE) { if (level == INPLACE) {
char buffer3[MAX_PRINT_BUFFER + 20] = {0}; char buffer3[sizeof(buffer2)] = {0};
char buffer4[sizeof(buffer2)] = {0};
memcpy_filter_ansi(buffer3, buffer2, sizeof(buffer2), !session.supports_colors); memcpy_filter_ansi(buffer3, buffer2, sizeof(buffer2), !session.supports_colors);
fprintf(stream, "\r%s", buffer3); memcpy_filter_emoji(buffer4, buffer3, sizeof(buffer3), session.emoji_mode);
fprintf(stream, "\r%s", buffer4);
fflush(stream); fflush(stream);
} else { } else {
fPrintAndLog(stream, "%s", buffer2); fPrintAndLog(stream, "%s", buffer2);
@ -220,6 +246,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
static int logging = 1; static int logging = 1;
char buffer[MAX_PRINT_BUFFER] = {0}; char buffer[MAX_PRINT_BUFFER] = {0};
char buffer2[MAX_PRINT_BUFFER] = {0}; char buffer2[MAX_PRINT_BUFFER] = {0};
char buffer3[MAX_PRINT_BUFFER] = {0};
// lock this section to avoid interlacing prints from different threads // lock this section to avoid interlacing prints from different threads
pthread_mutex_lock(&print_lock); pthread_mutex_lock(&print_lock);
@ -276,7 +303,8 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
bool filter_ansi = !session.supports_colors; bool filter_ansi = !session.supports_colors;
memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi); memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi);
if (g_printAndLog & PRINTANDLOG_PRINT) { if (g_printAndLog & PRINTANDLOG_PRINT) {
fprintf(stream, "%s", buffer2); memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), session.emoji_mode);
fprintf(stream, "%s", buffer3);
fprintf(stream, " "); // cleaning prompt fprintf(stream, " "); // cleaning prompt
fprintf(stream, "\n"); fprintf(stream, "\n");
} }
@ -293,10 +321,11 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
#endif #endif
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) { if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), ALTTEXT);
if (filter_ansi) { // already done if (filter_ansi) { // already done
fprintf(logfile, "%s\n", buffer2); fprintf(logfile, "%s\n", buffer3);
} else { } else {
memcpy_filter_ansi(buffer, buffer2, sizeof(buffer2), true); memcpy_filter_ansi(buffer, buffer3, sizeof(buffer3), true);
fprintf(logfile, "%s\n", buffer); fprintf(logfile, "%s\n", buffer);
} }
fflush(logfile); fflush(logfile);
@ -351,6 +380,102 @@ void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter) {
} }
} }
static bool emojify_token(const char *token, uint8_t token_length, const char **emojified_token, uint8_t *emojified_token_length, emojiMode_t mode) {
int i = 0;
while (EmojiTable[i].alias && EmojiTable[i].emoji) {
if ((strlen(EmojiTable[i].alias) == token_length) && (0 == memcmp(EmojiTable[i].alias, token, token_length))) {
switch (mode) {
case EMOJI: {
*emojified_token = EmojiTable[i].emoji;
*emojified_token_length = strlen(EmojiTable[i].emoji);
break;
}
case ALTTEXT: {
int j = 0;
*emojified_token_length = 0;
while (EmojiAltTable[j].alias && EmojiAltTable[i].alttext) {
if ((strlen(EmojiAltTable[j].alias) == token_length) && (0 == memcmp(EmojiAltTable[j].alias, token, token_length))) {
*emojified_token = EmojiAltTable[j].alttext;
*emojified_token_length = strlen(EmojiAltTable[j].alttext);
break;
}
++j;
}
break;
}
default: {// ERASE
*emojified_token_length = 0;
break;
}
}
return true;
}
++i;
}
return false;
}
static bool token_charset(uint8_t c) {
if ((c >= '0') && (c <= '9')) return true;
if ((c >= 'a') && (c <= 'z')) return true;
if ((c >= 'A') && (c <= 'Z')) return true;
if ((c == '_') || (c == '+') || (c == '-')) return true;
return false;
}
void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode) {
if (mode == ALIAS) {
memcpy(dest, src, n);
} else {
// tokenize emoji
const char *emojified_token = NULL;
uint8_t emojified_token_length = 0;
char *current_token = NULL;
uint8_t current_token_length=0;
char current_char;
char *rdest = (char *)dest;
char *rsrc = (char *)src;
uint16_t si = 0;
for (uint16_t i = 0; i < n; i++) {
current_char = rsrc[i];
if (current_token_length == 0) {
// starting a new token.
if (current_char == ':') {
current_token = rsrc + i;
current_token_length = 1;
} else { // not starting a new token.
rdest[si++] = current_char;
}
} else {
// finishing the current token.
if (current_char == ':') {
// nothing changed? we still need the ending ':' as it might serve for an upcoming emoji
if (! emojify_token(current_token, current_token_length + 1, &emojified_token, &emojified_token_length, mode)) {
memcpy(rdest + si, current_token, current_token_length);
si += current_token_length;
current_token = rsrc + i;
current_token_length = 1;
} else {
memcpy(rdest + si, emojified_token, emojified_token_length);
si += emojified_token_length;
current_token_length = 0;
}
} else if (token_charset(current_char)) { // continuing the current token.
current_token_length++;
} else { // dropping the current token.
current_token_length++;
memcpy(rdest + si, current_token, current_token_length);
si += current_token_length;
current_token_length = 0;
}
}
}
memcpy(rdest + si, current_token, current_token_length);
si += current_token_length;
}
}
void iceIIR_Butterworth(int *data, const size_t len) { void iceIIR_Butterworth(int *data, const size_t len) {
int *output = (int *) calloc(sizeof(int) * len, sizeof(uint8_t)); int *output = (int *) calloc(sizeof(int) * len, sizeof(uint8_t));

View file

@ -17,12 +17,17 @@
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE, HINT} logLevel_t;
typedef enum emojiMode {ALIAS, EMOJI, ALTTEXT, ERASE} emojiMode_t;
typedef struct { typedef struct {
bool stdinOnTTY; bool stdinOnTTY;
bool stdoutOnTTY; bool stdoutOnTTY;
bool supports_colors; bool supports_colors;
emojiMode_t emoji_mode;
bool pm3_present; bool pm3_present;
bool help_dump_mode; bool help_dump_mode;
bool show_hints;
} session_arg_t; } session_arg_t;
extern session_arg_t session; extern session_arg_t session;
@ -31,7 +36,6 @@ extern session_arg_t session;
#define M_PI 3.14159265358979323846264338327 #define M_PI 3.14159265358979323846264338327
#endif #endif
#define MAX_PRINT_BUFFER 2048 #define MAX_PRINT_BUFFER 2048
typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE} logLevel_t;
void ShowGui(void); void ShowGui(void);
void HideGraphWindow(void); void HideGraphWindow(void);
@ -41,6 +45,7 @@ void PrintAndLogOptions(const char *str[][2], size_t size, size_t space);
void PrintAndLogEx(logLevel_t level, const char *fmt, ...); void PrintAndLogEx(logLevel_t level, const char *fmt, ...);
void SetFlushAfterWrite(bool value); void SetFlushAfterWrite(bool value);
void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter); void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter);
void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode);
extern double CursorScaleFactor; extern double CursorScaleFactor;
extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset; extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset;

View file

@ -15,9 +15,10 @@
#include "ui.h" #include "ui.h"
#include "util.h" #include "util.h"
#define CARD_INS_DECRYPT 0x01 #define CARD_INS_DECRYPT 0x01
#define CARD_INS_ENCRYPT 0x02 #define CARD_INS_ENCRYPT 0x02
#define CARD_INS_DECODE 0x06 #define CARD_INS_DECODE 0x06
#define CARD_INS_NUMBLOCKS 0x07
static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint8_t cmd[] = {0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// look for CryptoHelper // look for CryptoHelper
@ -29,7 +30,7 @@ bool IsCryptoHelperPresent(void) {
uint8_t resp[20] = {0}; uint8_t resp[20] = {0};
ExchangeAPDUSC(true, version, sizeof(version), true, true, resp, sizeof(resp), &resp_len); 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"); PrintAndLogEx(INFO, "Found smart card helper");
return true; return true;
} else { } else {
@ -56,14 +57,15 @@ static bool executeCrypto(uint8_t ins, uint8_t *src, uint8_t *dest) {
return false; 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); 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); return executeCrypto(CARD_INS_ENCRYPT, src, dest);
} }
// Call with block6
void DecodeBlock6(uint8_t *src) { void DecodeBlock6(uint8_t *src) {
int resp_len = 0; int resp_len = 0;
uint8_t resp[254] = {0}; uint8_t resp[254] = {0};
@ -81,3 +83,12 @@ void DecodeBlock6(uint8_t *src) {
PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9); PrintAndLogEx(SUCCESS, "%.*s", resp_len - 11, resp + 9);
} }
// Call with block6
uint8_t GetNumberBlocksForUserId(uint8_t *src) {
int resp_len = 0;
uint8_t resp[254] = {0};
uint8_t c[] = {0x96, CARD_INS_NUMBLOCKS, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
memcpy(c + 5, src, 8);
ExchangeAPDUSC(true, c, sizeof(c), false, true, resp, sizeof(resp), &resp_len);
return resp[8];
}

View file

@ -18,4 +18,5 @@ bool IsCryptoHelperPresent(void);
bool Encrypt(uint8_t *src, uint8_t *dest); bool Encrypt(uint8_t *src, uint8_t *dest);
bool Decrypt(uint8_t *src, uint8_t *dest); bool Decrypt(uint8_t *src, uint8_t *dest);
void DecodeBlock6(uint8_t *src); void DecodeBlock6(uint8_t *src);
uint8_t GetNumberBlocksForUserId(uint8_t *src);
#endif #endif

View file

@ -34,7 +34,7 @@
// XYZ 3D printing // XYZ 3D printing
// Vinglock // Vinglock
//------------------------------------ //------------------------------------
static void transform_D(uint8_t *ru) { void transform_D(uint8_t* ru) {
const uint32_t c_D[] = { const uint32_t c_D[] = {
0x6D835AFC, 0x7D15CD97, 0x0942B409, 0x32F9C923, 0xA811FB02, 0x64F121E8, 0x6D835AFC, 0x7D15CD97, 0x0942B409, 0x32F9C923, 0xA811FB02, 0x64F121E8,
@ -44,32 +44,32 @@ static void transform_D(uint8_t *ru) {
0x5728B869, 0x30726D5A 0x5728B869, 0x30726D5A
}; };
//Transform //Transform
uint8_t i; uint8_t i;
uint8_t p = 0; uint8_t p = 0;
uint32_t v1 = ((ru[3] << 24) | (ru[2] << 16) | (ru[1] << 8) | ru[0]) + c_D[p++]; uint32_t v1 = ((ru[3] << 24) | (ru[2] << 16) | (ru[1] << 8) | ru[0]) + c_D[p++];
uint32_t v2 = ((ru[7] << 24) | (ru[6] << 16) | (ru[5] << 8) | ru[4]) + c_D[p++]; uint32_t v2 = ((ru[7] << 24) | (ru[6] << 16) | (ru[5] << 8) | ru[4]) + c_D[p++];
for (i = 0; i < 12; i += 2)
{
uint32_t tempA = v1 ^ v2;
uint32_t t1 = PM3_ROTL(tempA, v2 & 0x1F) + c_D[p++];
uint32_t tempB = v2 ^ t1;
uint32_t t2 = PM3_ROTL(tempB, t1 & 0x1F) + c_D[p++];
tempA = t1 ^ t2;
v1 = PM3_ROTL(tempA, t2 & 0x1F) + c_D[p++];
tempB = t2 ^ v1;
v2 = PM3_ROTL(tempB, v1 & 0x1F) + c_D[p++];
}
for (i = 0; i < 12; i += 2) { //Re-use ru
uint32_t xor1 = v1 ^ v2; ru[0] = v1 & 0xFF;
uint32_t t1 = ROTL(xor1, v2 & 0x1F) + c_D[p++]; ru[1] = (v1 >> 8) & 0xFF;
uint32_t xor2 = v2 ^ t1; ru[2] = (v1 >> 16) & 0xFF;
uint32_t t2 = ROTL(xor2, t1 & 0x1F) + c_D[p++]; ru[3] = (v1 >> 24) & 0xFF;
uint32_t xor3 = t1 ^ t2; ru[4] = v2 & 0xFF;
uint32_t xor4 = t2 ^ v1; ru[5] = (v2 >> 8) & 0xFF;
v1 = ROTL(xor3, t2 & 0x1F) + c_D[p++]; ru[6] = (v2 >> 16) & 0xFF;
v2 = ROTL(xor4, v1 & 0x1F) + c_D[p++]; ru[7] = (v2 >> 24) & 0xFF;
}
//Re-use ru
ru[0] = v1 & 0xFF;
ru[1] = (v1 >> 8) & 0xFF;
ru[2] = (v1 >> 16) & 0xFF;
ru[3] = (v1 >> 24) & 0xFF;
ru[4] = v2 & 0xFF;
ru[5] = (v2 >> 8) & 0xFF;
ru[6] = (v2 >> 16) & 0xFF;
ru[7] = (v2 >> 24) & 0xFF;
} }
// Transport system (IT) pwd generation algo nickname A. // Transport system (IT) pwd generation algo nickname A.
@ -130,17 +130,23 @@ uint32_t ul_ev1_pwdgenC(uint8_t *uid) {
// XYZ 3d printing pwd generation algo nickname D. // XYZ 3d printing pwd generation algo nickname D.
uint32_t ul_ev1_pwdgenD(uint8_t *uid) { uint32_t ul_ev1_pwdgenD(uint8_t *uid) {
uint8_t i; uint8_t i;
uint8_t r = (uid[1] + uid[3] + uid[5]) & 7; // rotation offset // rotation offset
uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // rotated UID uint8_t r = (uid[1] + uid[3] + uid[5]) & 7;
// rotated UID
uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
for (i = 0; i < 7; i++) for (i = 0; i < 7; i++)
ru[(i + r) & 7] = uid[i]; ru[(i + r) & 7] = uid[i];
transform_D(ru); transform_D(ru);
// calc key // offset
r = (ru[0] + ru[2] + ru[4] + ru[6]) & 3;
// calc key
uint32_t pwd = 0; uint32_t pwd = 0;
r = (ru[0] + ru[2] + ru[4] + ru[6]) & 3; // offset
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
pwd = ru[i + r] + (pwd << 8); pwd = ru[i + r] + (pwd << 8);
@ -412,43 +418,56 @@ int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys) {
//------------------------------------ //------------------------------------
int generator_selftest() { int generator_selftest() {
PrintAndLogEx(SUCCESS, "Generators selftest"); #define NUM_OF_TEST 5
PrintAndLogEx(SUCCESS, "-------------------");
bool success; PrintAndLogEx(INFO, "PWD / KEY generator selftest");
PrintAndLogEx(INFO, "----------------------------");
bool success = false;
uint8_t testresult = 0;
uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10}; uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10};
uint32_t pwd1 = ul_ev1_pwdgenA(uid1); uint32_t pwd1 = ul_ev1_pwdgenA(uid1);
success = (pwd1 == 0x8432EB17); success = (pwd1 == 0x8432EB17);
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid1, 7), pwd1, success ? "OK" : "->8432EB17<-"); if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid1, 7), pwd1, success ? "OK" : "->8432EB17<-");
uint8_t uid2[] = {0x04, 0x1f, 0x98, 0xea, 0x1e, 0x3e, 0x81}; uint8_t uid2[] = {0x04, 0x1f, 0x98, 0xea, 0x1e, 0x3e, 0x81};
uint32_t pwd2 = ul_ev1_pwdgenB(uid2); uint32_t pwd2 = ul_ev1_pwdgenB(uid2);
success = (pwd2 == 0x5fd37eca); success = (pwd2 == 0x5fd37eca);
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid2, 7), pwd2, success ? "OK" : "->5fd37eca<--"); if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid2, 7), pwd2, success ? "OK" : "->5fd37eca<--");
uint8_t uid3[] = {0x04, 0x62, 0xB6, 0x8A, 0xB4, 0x42, 0x80}; uint8_t uid3[] = {0x04, 0x62, 0xB6, 0x8A, 0xB4, 0x42, 0x80};
uint32_t pwd3 = ul_ev1_pwdgenC(uid3); uint32_t pwd3 = ul_ev1_pwdgenC(uid3);
success = (pwd3 == 0x5a349515); success = (pwd3 == 0x5a349515);
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid3, 7), pwd3, success ? "OK" : "->5a349515<--"); if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid3, 7), pwd3, success ? "OK" : "->5a349515<--");
uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80}; uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
uint32_t pwd4 = ul_ev1_pwdgenD(uid4); uint32_t pwd4 = ul_ev1_pwdgenD(uid4);
success = (pwd4 == 0x72B1EC61); success = (pwd4 == 0x72B1EC61);
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, success ? "OK" : "->72B1EC61<--"); if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X - %s", sprint_hex(uid4, 7), pwd4, success ? "OK" : "->72B1EC61<--");
// uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44}; // uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44};
// uint64_t key1 = mfc_algo_a(uid5); // uint64_t key1 = mfc_algo_a(uid5);
// success = (key1 == 0xD1E2AA68E39A); // success = (key1 == 0xD1E2AA68E39A);
// PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" | %s", sprint_hex(uid5, 4), key1, success ? "OK" : "->D1E2AA68E39A<--"); // PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid5, 4), key1, success ? "OK" : "->D1E2AA68E39A<--");
uint8_t uid6[] = {0x74, 0x57, 0xCA, 0xA9}; uint8_t uid6[] = {0x74, 0x57, 0xCA, 0xA9};
uint64_t key6 = 0; uint64_t key6 = 0;
mfc_algo_sky_one(uid6, 15, 0, &key6); mfc_algo_sky_one(uid6, 15, 0, &key6);
success = (key6 == 0x82c7e64bc565); success = (key6 == 0x82c7e64bc565);
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" | %s", sprint_hex(uid6, 4), key6, success ? "OK" : "->82C7E64BC565<--"); if (success)
testresult++;
PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid6, 4), key6, success ? "OK" : "->82C7E64BC565<--");
PrintAndLogEx(SUCCESS, "-------------------"); PrintAndLogEx(SUCCESS, "------------------- Selftest %s", (testresult == NUM_OF_TEST) ? "OK" : "fail");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -206,7 +206,7 @@ void getHiLo(int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo) {
*low = signalprop.low; *low = signalprop.low;
} }
// prnt("getHiLo fuzzed: High %d | Low %d", *high, *low); // prnt("getHiLo fuzzed: High %d | Low %d", *high, *low);
} }
// by marshmellow // by marshmellow

View file

@ -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 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 ## Wiegand manipulation
^[Top](#top) ^[Top](#top)

View file

@ -33,7 +33,7 @@ brew upgrade --fetch-HEAD proxmark3
## Flash the BOOTROM & FULLIMAGE ## 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: In principle, the helper script `pm3-flash-all` should auto-detect your port, so you can just try:

View file

@ -64,8 +64,8 @@ extern int DBGLEVEL;
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
#endif #endif
#ifndef ROTL #ifndef PM3_ROTL
# define ROTL(x,n) (((uintmax_t)(x) << (n)) | ((uintmax_t)(x) >> ((sizeof(x) * 8) - (n)))) # define PM3_ROTL(x,n) (((uintmax_t)(x) << (n)) | ((uintmax_t)(x) >> ((sizeof(x) * 8) - (n))))
#endif #endif
// endian change for 64bit // endian change for 64bit

View file

@ -70,6 +70,16 @@ typedef struct {
uint32_t ProxToAirDuration; uint32_t ProxToAirDuration;
uint8_t par; // enough for precalculated parity of 8 Byte responses uint8_t par; // enough for precalculated parity of 8 Byte responses
} PACKED tag_response_info_t; } PACKED tag_response_info_t;
// DESFIRE_RAW flag enums
typedef enum DESFIRE_COMMAND {
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x10,
} desfire_command_t;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ISO 14443B // ISO 14443B
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -505,6 +505,8 @@ typedef struct {
#define CMD_HF_MIFARE_SNIFF 0x0630 #define CMD_HF_MIFARE_SNIFF 0x0630
#define CMD_HF_MIFARE_MFKEY 0x0631 #define CMD_HF_MIFARE_MFKEY 0x0631
#define CMD_HF_MIFARE_PERSONALIZE_UID 0x0632
//ultralightC //ultralightC
#define CMD_HF_MIFAREUC_AUTH 0x0724 #define CMD_HF_MIFAREUC_AUTH 0x0724
//0x0725 and 0x0726 no longer used //0x0725 and 0x0726 no longer used

View file

@ -163,6 +163,10 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_EV1_PERSONAL_UID 0x40 #define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43 #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_WRITE 0xA2
#define MIFARE_ULC_COMP_WRITE 0xA0 #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 PROTO_HITAG1 10
#define THINFILM 11 #define THINFILM 11
#define LTO 12 #define LTO 12
#define PROTO_HITAG2 13 #define PROTO_HITAG2 13
#define PROTO_HITAGS 14 #define PROTO_HITAGS 14
//-- Picopass fuses //-- Picopass fuses
@ -381,6 +385,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MFDES_CHANGE_KEY 0xc4 #define MFDES_CHANGE_KEY 0xc4
#define MFDES_GET_KEY_VERSION 0x64 #define MFDES_GET_KEY_VERSION 0x64
#define MFDES_AUTHENTICATION_FRAME 0xAF #define MFDES_AUTHENTICATION_FRAME 0xAF
#define MFDES_ADDITIONAL_FRAME 0xAF
#define MFDES_READSIG 0x3C
// LEGIC Commands // LEGIC Commands
#define LEGIC_MIM_22 0x0D #define LEGIC_MIM_22 0x0D
@ -595,7 +601,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 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_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 // HITAG S commands

View file

@ -95,7 +95,8 @@ while true; do
printf "\n${C_BLUE}Testing data manipulation:${C_NC}\n" printf "\n${C_BLUE}Testing data manipulation:${C_NC}\n"
if ! CheckExecute "reveng test" "./client/proxmark3 -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi if ! CheckExecute "reveng test" "./client/proxmark3 -c 'reveng -w 8 -s 01020304e3 010204039d'" "CRC-8/SMBUS"; then break; fi
if ! CheckExecute "mfu pwdgen test" "./client/proxmark3 -c 'hf mfu pwdgen t'" "Selftest OK"; then break; fi
printf "\n${C_BLUE}Testing LF:${C_NC}\n" printf "\n${C_BLUE}Testing LF:${C_NC}\n"
if ! CheckExecute "lf em4x05 test" "./client/proxmark3 -c 'data load traces/em4x05.pm3;lf search'" "FDX-B ID found"; then break; fi if ! CheckExecute "lf em4x05 test" "./client/proxmark3 -c 'data load traces/em4x05.pm3;lf search'" "FDX-B ID found"; then break; fi
@ -120,6 +121,7 @@ while true; do
if ! CheckExecute "findbits test" "tools/findbits.py 73 0110010101110011" "Match at bit 9: 011001010"; then break; fi if ! CheckExecute "findbits test" "tools/findbits.py 73 0110010101110011" "Match at bit 9: 011001010"; then break; fi
if ! CheckExecute "findbits_test test" "tools/findbits_test.py 2>&1" "OK"; then break; fi if ! CheckExecute "findbits_test test" "tools/findbits_test.py 2>&1" "OK"; then break; fi
if ! CheckExecute "pm3_eml_mfd test" "tools/pm3_eml_mfd_test.py 2>&1" "OK"; then break; fi if ! CheckExecute "pm3_eml_mfd test" "tools/pm3_eml_mfd_test.py 2>&1" "OK"; then break; fi
printf "\n${C_GREEN}Tests [OK]${C_NC}\n\n" printf "\n${C_GREEN}Tests [OK]${C_NC}\n\n"
exit 0 exit 0
done done

View file

@ -22,4 +22,4 @@ $(OBJDIR)/libz.a:
tarbin: $(BINS) tarbin: $(BINS)
$(info [=] TAR ../proxmark3-$(platform)-bin.tar) $(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/%)

View file

@ -142,11 +142,11 @@ typedef int rtccDate;
#ifndef __PIC32MX__ #ifndef __PIC32MX__
#define __PIC32MX__ #define __PIC32MX__
#endif #endif
#define GetSystemClock() (80000000ul) #define GetSystemClock() (80000000ul)
#define GetPeripheralClock() (GetSystemClock()) #define GetPeripheralClock() (GetSystemClock())
#define GetInstructionClock() (GetSystemClock()) #define GetInstructionClock() (GetSystemClock())
//#define USE_SELF_POWER_SENSE_IO //#define USE_SELF_POWER_SENSE_IO
@ -322,7 +322,7 @@ typedef int rtccDate;
// spi for SD card // spi for SD card
#define SD_CARD_DET LATFbits.LATF0 #define SD_CARD_DET LATFbits.LATF0
#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it #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 SPI_CHANNEL1
#define SPI_SD_BUFF SPI1BUF #define SPI_SD_BUFF SPI1BUF
#define SPI_SD_STAT SPI1STATbits #define SPI_SD_STAT SPI1STATbits

View file

@ -228,19 +228,17 @@ static uint32_t hitag2_crypt(uint64_t x);
#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ #define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \
((S >> (C - 3)) & 8) ) ((S >> (C - 3)) & 8) )
static uint32_t hitag2_crypt(uint64_t x) {
static uint32_t hitag2_crypt(uint64_t s)
{
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
uint32_t bitindex; uint32_t bitindex;
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; bitindex = (ht2_function4a >> pickbits2_2(x, 1, 4)) & 1;
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(x, 7, 11, 13)) & 0x02;
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; bitindex |= ((ht2_function4b << 2) >> pickbits1x4(x, 16, 20, 22, 25)) & 0x04;
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(x, 27, 30, 32)) & 0x08;
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(x, 33, 42, 45)) & 0x10;
DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex); DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex);
return (ht2_function5c >> bitindex) & 1; return (ht2_function5c >> bitindex) & 1;
@ -253,13 +251,12 @@ static uint32_t hitag2_crypt(uint64_t s)
* uint32_t serialnum - 32 bit tag serial number * uint32_t serialnum - 32 bit tag serial number
* uint32_t initvector - 32 bit random IV from reader, part of tag authentication * 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 // init state, from serial number and lowest 16 bits of shared key
uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum; uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum;
// mix the initialisation vector and highest 32 bits of the shared key // 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 // 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 // these will be XORed in turn with output of the crypto function
@ -320,9 +317,9 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
// optimise with one 64-bit intermediate // optimise with one 64-bit intermediate
uint64_t temp = state ^ (state >> 1); uint64_t temp = state ^ (state >> 1);
pstate->lfsr = state ^ (state >> 6) ^ (state >> 16) pstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
^ (temp >> 42) ^ (temp >> 46); ^ (temp >> 42) ^ (temp >> 46);
} }
} }
@ -338,8 +335,7 @@ void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, ui
* Hitag_State* pstate - in/out, internal cipher state after initialisation * Hitag_State* pstate - in/out, internal cipher state after initialisation
* uint32_t steps - number of bits requested, (capped at 32) * 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; uint64_t state = pstate->shiftreg;
uint32_t result = 0; uint32_t result = 0;
uint64_t lfsr = pstate->lfsr; uint64_t lfsr = pstate->lfsr;
@ -448,7 +444,7 @@ unsigned hitag2_verifytest()
const uint64_t key = rev64 (0x524B494D4E4FUL); const uint64_t key = rev64 (0x524B494D4E4FUL);
const uint32_t serial = rev32 (0x69574349); const uint32_t serial = rev32 (0x69574349);
const uint32_t initvec = rev32 (0x72456E65); const uint32_t initvec = rev32 (0x72456E65);
uint32_t i; uint32_t i;
Hitag_State state; Hitag_State state;
@ -471,11 +467,10 @@ unsigned hitag2_verifytest()
#ifdef UNIT_TEST #ifdef UNIT_TEST
int main(int argc, char* argv[]) int main(int argc, char *argv[]) {
{
unsigned pass = hitag2_verifytest(); 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) { if (pass) {
hitag2_benchtest(10000); hitag2_benchtest(10000);

View file

@ -159,9 +159,9 @@ typedef struct {
uint64_t lfsr; // fast lfsr, used to make software faster uint64_t lfsr; // fast lfsr, used to make software faster
} Hitag_State; } 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_gen32();
unsigned int hitag2_benchtest(uint32_t count); unsigned int hitag2_benchtest(uint32_t count);

View file

@ -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 // 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 // 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. // USB2/3 should keep up.
// //
// These MUST be a power of 2 for the maths to work - you have been warned! // 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; int nsteps2;
// create table entry // 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) { if (!t) {
printf("create_table: t is NULL\n"); printf("create_table: t is NULL\n");
exit(1); exit(1);
@ -83,8 +82,7 @@ void create_table(struct table *t, int d1, int d2)
// create all table entries // create all table entries
void create_tables(struct table *t) void create_tables(struct table *t) {
{
int i, j; int i, j;
if (!t) { if (!t) {
@ -92,8 +90,8 @@ void create_tables(struct table *t)
exit(1); exit(1);
} }
for (i=0; i<0x100; i++) { for (i = 0; i < 0x100; i++) {
for (j=0; j<0x100; j++) { for (j = 0; j < 0x100; j++) {
create_table(t + ((i * 0x100) + j), i, j); create_table(t + ((i * 0x100) + j), i, j);
} }
} }
@ -101,8 +99,7 @@ void create_tables(struct table *t)
// free the table memory // free the table memory
void free_tables(struct table *t) void free_tables(struct table *t) {
{
int i; int i;
struct table *ttmp; struct table *ttmp;
@ -111,7 +108,7 @@ void free_tables(struct table *t)
exit(1); exit(1);
} }
for (i=0; i<0x10000; i++) { for (i = 0; i < 0x10000; i++) {
ttmp = t + i; ttmp = t + i;
free(ttmp->data); free(ttmp->data);
} }
@ -120,8 +117,7 @@ void free_tables(struct table *t)
// write (partial) table to file // write (partial) table to file
void writetable(struct table *t1) void writetable(struct table *t1) {
{
int fd; int fd;
if (debug) printf("writetable %s\n", t1->path); if (debug) printf("writetable %s\n", t1->path);
@ -146,18 +142,17 @@ void writetable(struct table *t1)
// store value in table // store value in table
void store(unsigned char *data) void store(unsigned char *data) {
{ unsigned char d_1, d_2;
unsigned char d1, d2;
int offset; int offset;
struct table *t1; struct table *t1;
// use the first two bytes as an index // use the first two bytes as an index
d1 = data[0]; d_1 = data[0];
d2 = data[1]; d_2 = data[1];
offset = (d1 * 0x100) + d2; offset = (d_1 * 0x100) + d_2;
if (debug) printf("store, d1=%02X, d2=%02X, offset = %d\n", d1, d2, offset); if (debug) printf("store, d1=%02X, d2=%02X, offset = %d\n", d_1, d_2, offset);
// get pointer to table entry // get pointer to table entry
t1 = t + offset; t1 = t + offset;
@ -171,7 +166,7 @@ void store(unsigned char *data)
if (debug) printf("store, offset = %d, got lock\n", offset); if (debug) printf("store, offset = %d, got lock\n", offset);
// store the entry // 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); 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) // 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]; unsigned char buf[16];
// create buffer // create buffer
writebuf(buf, ks1, 3); writebuf(buf, ks1, 3);
writebuf(buf+3, ks2, 3); writebuf(buf + 3, ks2, 3);
writebuf(buf+6, shiftreg, 6); writebuf(buf + 6, shiftreg, 6);
// store buffer // store buffer
store(buf); 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 // builds the di table for jumping
void builddi(int steps, int table) void builddi(int steps, int table) {
{
uint64_t statemask; uint64_t statemask;
int i; int i;
Hitag_State mystate; Hitag_State mystate;
@ -237,7 +230,7 @@ void builddi(int steps, int table)
} }
// build di states // build di states
for (i=0; i<48; i++) { for (i = 0; i < 48; i++) {
mystate.shiftreg = statemask; mystate.shiftreg = statemask;
buildlfsr(&mystate); buildlfsr(&mystate);
hitag2_nstep(&mystate, steps); hitag2_nstep(&mystate, steps);
@ -248,8 +241,7 @@ void builddi(int steps, int table)
} }
// jump function - quickly jumps a load of steps // 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 output = 0;
uint64_t bitmask; uint64_t bitmask;
int i; 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 // if si is 1, di.si = di; if si is 0, di.si = 0
bitmask = 1; bitmask = 1;
for (i=0; i<48; i++) { for (i = 0; i < 48; i++) {
if (hstate->shiftreg & bitmask) { if (hstate->shiftreg & bitmask) {
output = output ^ thisd[i]; output = output ^ thisd[i];
} }
@ -281,12 +273,11 @@ void jumpnsteps(Hitag_State *hstate, int table)
hstate->shiftreg = output; hstate->shiftreg = output;
buildlfsr(hstate); buildlfsr(hstate);
} }
// thread to build a part of the table // thread to build a part of the table
void *buildtable(void *d) void *buildtable(void *d) {
{
Hitag_State hstate; Hitag_State hstate;
Hitag_State hstate2; Hitag_State hstate2;
unsigned long i; unsigned long i;
@ -301,7 +292,7 @@ void *buildtable(void *d)
buildlfsr(&hstate); buildlfsr(&hstate);
/* jump to offset using jump table 2 (2048) */ /* jump to offset using jump table 2 (2048) */
for (i=0; i<index; i++) { for (i = 0; i < index; i++) {
jumpnsteps(&hstate, 2); jumpnsteps(&hstate, 2);
} }
@ -319,7 +310,7 @@ void *buildtable(void *d)
} }
/* make the entries */ /* make the entries */
for (i=0; i<maxentries; i++) { for (i = 0; i < maxentries; i++) {
// copy the current state // copy the current state
hstate2.shiftreg = hstate.shiftreg; hstate2.shiftreg = hstate.shiftreg;
@ -343,8 +334,7 @@ void *buildtable(void *d)
// make 'table/' (unsorted) and 'sorted/' dir structures // make 'table/' (unsorted) and 'sorted/' dir structures
void makedirs() void makedirs() {
{
char path[32]; char path[32];
int i; int i;
@ -357,7 +347,7 @@ void makedirs()
exit(1); exit(1);
} }
for (i=0; i<0x100; i++) { for (i = 0; i < 0x100; i++) {
sprintf(path, "table/%02x", i); sprintf(path, "table/%02x", i);
if (mkdir(path, 0755)) { if (mkdir(path, 0755)) {
printf("cannot make dir %s\n", path); 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 *d_1 = (unsigned char *)p1;
unsigned char *d1 = (unsigned char *)p1; unsigned char *d_2 = (unsigned char *)p2;
unsigned char *d2 = (unsigned char *)p2;
return memcmp(d1, d2, DATASIZE); return memcmp(d_1, d_2, DATASIZE);
} }
void *sorttable(void *d) void *sorttable(void *d) {
{
int i, j; int i, j;
int fdin; int fdin;
int fdout; int fdout;
@ -401,9 +389,9 @@ void *sorttable(void *d)
} }
// loop over our first byte values // 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 // 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); printf("sorttable: processing bytes 0x%02x/0x%02x\n", i, j);
@ -464,8 +452,7 @@ void *sorttable(void *d)
return NULL; return NULL;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
pthread_t threads[NUM_BUILD_THREADS]; pthread_t threads[NUM_BUILD_THREADS];
void *status; void *status;
long i; long i;
@ -493,7 +480,7 @@ int main(int argc, char *argv[])
builddi(2048, 2); builddi(2048, 2);
// start the threads // 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)); ret = pthread_create(&(threads[i]), NULL, buildtable, (void *)(i));
if (ret) { if (ret) {
printf("cannot start buildtable thread %ld\n", i); 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"); if (debug) printf("main, started buildtable threads\n");
// wait for threads to finish // 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); ret = pthread_join(threads[i], &status);
if (ret) { if (ret) {
printf("cannot join buildtable thread %ld\n", i); printf("cannot join buildtable thread %ld\n", i);
@ -514,7 +501,7 @@ int main(int argc, char *argv[])
} }
// write all remaining files // write all remaining files
for (i=0; i<0x10000; i++) { for (i = 0; i < 0x10000; i++) {
t1 = t + i; t1 = t + i;
if (t1->ptr > t1->data) { if (t1->ptr > t1->data) {
writetable(t1); writetable(t1);
@ -531,7 +518,7 @@ int main(int argc, char *argv[])
// start the threads // 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)); ret = pthread_create(&(threads[i]), NULL, sorttable, (void *)(i));
if (ret) { if (ret) {
printf("cannot start sorttable thread %ld\n", i); 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"); if (debug) printf("main, started sorttable threads\n");
// wait for threads to finish // 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); ret = pthread_join(threads[i], &status);
if (ret) { if (ret) {
printf("cannot join sorttable thread %ld\n", i); printf("cannot join sorttable thread %ld\n", i);

View file

@ -6,8 +6,7 @@
#include "ht2crack2utils.h" #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]; unsigned char raw[32];
int i; int i;
@ -26,7 +25,7 @@ int makerandom(char *hex, unsigned int len, int fd)
exit(1); exit(1);
} }
for (i=0; i<len; i++) { for (i = 0; i < len; i++) {
sprintf(hex + (2 * i), "%02X", raw[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; Hitag_State hstate;
char key[32]; char key[32];
char uid[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(key, 6, urandomfd);
makerandom(uid, 4, urandomfd); makerandom(uid, 4, urandomfd);
@ -84,7 +82,7 @@ int main(int argc, char *argv[])
hitag2_nstep(&hstate, 64); hitag2_nstep(&hstate, 64);
for (j=0; j<64; j++) { for (j = 0; j < 64; j++) {
fprintf(fp, "%08X\n", hitag2_nstep(&hstate, 32)); fprintf(fp, "%08X\n", hitag2_nstep(&hstate, 32));
} }

View file

@ -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 *d1 = (unsigned char *)p1;
unsigned char *d2 = (unsigned char *)p2; unsigned char *d2 = (unsigned char *)p2;
return memcmp(d1, d2, DATASIZE - 6); return memcmp(d1, d2, DATASIZE - 6);
} }
int loadrngdata(struct rngdata *r, char *file) int loadrngdata(struct rngdata *r, char *file) {
{
int fd; int fd;
int i, j; int i, j;
int nibble; int nibble;
@ -72,7 +70,7 @@ int loadrngdata(struct rngdata *r, char *file)
j = 0; j = 0;
nibble = 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 ((data[i] != 0x0a) && (data[i] != 0x0d) && (data[i] != 0x20)) {
if (!nibble) { if (!nibble) {
r->data[j] = hex2bin(data[i]) << 4; r->data[j] = hex2bin(data[i]) << 4;
@ -93,8 +91,7 @@ int loadrngdata(struct rngdata *r, char *file)
return 1; 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 bytenum;
int bitnum; int bitnum;
int i; int i;
@ -107,7 +104,7 @@ int makecand(unsigned char *c, struct rngdata *r, int bitoffset)
bytenum = bitoffset / 8; bytenum = bitoffset / 8;
bitnum = bitoffset % 8; bitnum = bitoffset % 8;
for (i=0; i<6; i++) { for (i = 0; i < 6; i++) {
if (!bitnum) { if (!bitnum) {
c[i] = r->data[bytenum + i]; c[i] = r->data[bytenum + i];
} else { } 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 // 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; Hitag_State hstate;
int i; int i;
uint32_t ks1; uint32_t ks1;
@ -130,8 +126,8 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd)
// build the prng state at the candidate // build the prng state at the candidate
hstate.shiftreg = 0; hstate.shiftreg = 0;
for (i=0; i<6; i++) { for (i = 0; i < 6; i++) {
hstate.shiftreg = (hstate.shiftreg << 8) | f[i+4]; hstate.shiftreg = (hstate.shiftreg << 8) | f[i + 4];
} }
buildlfsr(&hstate); buildlfsr(&hstate);
@ -149,7 +145,7 @@ int testcand(unsigned char *f, unsigned char *rt, int fwd)
ks2 = hitag2_nstep(&hstate, 24); ks2 = hitag2_nstep(&hstate, 24);
writebuf(buf, ks1, 3); writebuf(buf, ks1, 3);
writebuf(buf+3, ks2, 3); writebuf(buf + 3, ks2, 3);
// compare them // compare them
if (!memcmp(buf, rt, 6)) { 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; int fd;
struct stat filestat; struct stat filestat;
char file[64]; char file[64];
@ -193,7 +188,7 @@ int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, u
exit(1); exit(1);
} }
memcpy(item, c+2, 4); memcpy(item, c + 2, 4);
found = (unsigned char *)bsearch(item, data, filestat.st_size / DATASIZE, DATASIZE, datacmp); 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))) { while (((found - data) <= (filestat.st_size - DATASIZE)) && (!memcmp(found, item, 4))) {
if (testcand(found, rt, fwd)) { if (testcand(found, rt, fwd)) {
memcpy(m, c, 2); memcpy(m, c, 2);
memcpy(m+2, found, 4); memcpy(m + 2, found, 4);
memcpy(s, found+4, 6); memcpy(s, found + 4, 6);
munmap(data, filestat.st_size); munmap(data, filestat.st_size);
close(fd); close(fd);
return 1; return 1;
} }
found = found + DATASIZE; 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 i;
int bitlen; int bitlen;
unsigned char cand[6]; unsigned char cand[6];
@ -243,7 +237,7 @@ int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstat
bitlen = r->len * 8; bitlen = r->len * 8;
for (i=0; i<=bitlen - 48; i++) { for (i = 0; i <= bitlen - 48; i++) {
// print progress // print progress
if ((i % 100) == 0) { if ((i % 100) == 0) {
printf("searching on bit %d\n", i); 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; int i;
if (!s) { if (!s) {
@ -294,7 +287,7 @@ void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset)
// build prng at recovered offset // build prng at recovered offset
hstate->shiftreg = 0; hstate->shiftreg = 0;
for (i=0; i<6; i++) { for (i = 0; i < 6; i++) {
hstate->shiftreg = (hstate->shiftreg << 8) | s[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 key;
uint64_t keyupper; uint64_t keyupper;
uint32_t uid; uint32_t uid;
@ -333,7 +325,7 @@ uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr)
uidtmp = uid; uidtmp = uid;
// rollback and extract bits b // 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); hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uidtmp >> 31) & 0x1);
uidtmp = uidtmp << 1; uidtmp = uidtmp << 1;
b = (b << 1) | fnf(hstate->shiftreg); 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; Hitag_State hstate;
struct rngdata rng; struct rngdata rng;
int bitoffset = 0; int bitoffset = 0;
@ -420,7 +411,7 @@ int main(int argc, char *argv[])
printf("\n"); printf("\n");
printf("KEY:\t\t"); printf("KEY:\t\t");
for (i=0; i<6; i++) { for (i = 0; i < 6; i++) {
printf("%02X", (int)(key & 0xff)); printf("%02X", (int)(key & 0xff));
key = key >> 8; key = key >> 8;
} }

View file

@ -1,13 +1,11 @@
#include "ht2crack2utils.h" #include "ht2crack2utils.h"
// writes a value into a buffer as a series of bytes // 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; int i;
char c; char c;
for (i=len-1; i>=0; i--) for (i = len - 1; i >= 0; i--) {
{
c = val & 0xff; c = val & 0xff;
buf[i] = c; buf[i] = c;
val = val >> 8; val = val >> 8;
@ -17,18 +15,17 @@ void writebuf(unsigned char *buf, uint64_t val, unsigned int len)
/* simple hexdump for testing purposes */ /* simple hexdump for testing purposes */
void shexdump(unsigned char *data, int data_len) void shexdump(unsigned char *data, int data_len) {
{
int i; int i;
if (!data || (data_len <= 0)) { if (!data || (data_len <= 0)) {
printf("shexdump: invalid parameters\n"); printf("shexdump: invalid parameters\n");
return; return;
} }
printf("Hexdump from %p:\n", data); 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) { if ((i % HEX_PER_ROW) == 0) {
printf("\n0x%04x: ", i); 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; int i, j;
unsigned char x; unsigned char x;
@ -49,9 +45,9 @@ void printbin(unsigned char *c)
return; return;
} }
for (i=0; i<6; i++) { for (i = 0; i < 6; i++) {
x = c[i]; x = c[i];
for (j=0; j<8; j++) { for (j = 0; j < 8; j++) {
printf("%d", (x & 0x80) >> 7); printf("%d", (x & 0x80) >> 7);
x = x << 1; 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; int i;
uint64_t mask = 1; uint64_t mask = 1;
mask = mask << (size - 1); mask = mask << (size - 1);
for (i=0; i<size; i++) { for (i = 0; i < size; i++) {
if (val & mask) { if (val & mask) {
printf("1"); printf("1");
} else { } 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"); printf("shiftreg =\t");
printbin2(hstate->shiftreg, 48); printbin2(hstate->shiftreg, 48);
printf("\n"); printf("\n");
@ -89,8 +83,7 @@ void printstate(Hitag_State *hstate)
// convert hex char to binary // convert hex char to binary
unsigned char hex2bin(unsigned char c) unsigned char hex2bin(unsigned char c) {
{
if ((c >= '0') && (c <= '9')) { if ((c >= '0') && (c <= '9')) {
return (c - '0'); return (c - '0');
} else if ((c >= 'a') && (c <= 'f')) { } else if ((c >= 'a') && (c <= 'f')) {
@ -103,8 +96,7 @@ unsigned char hex2bin(unsigned char c)
} }
// return a single bit from a value // 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; uint64_t bitmask = 1;
bitmask = bitmask << bit; bitmask = bitmask << bit;
@ -118,20 +110,18 @@ int bitn(uint64_t x, int bit)
// the sub-function R that rollback depends upon // 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 // 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) ^ 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, 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, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47));
} }
// the rollback function that lets us go backwards in time // 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; int i;
for (i=0; i<steps; i++) { for (i = 0; i < steps; i++) {
hstate->shiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | fnR(hstate->shiftreg); 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 // the three filter sub-functions that feed fnf
int fa(unsigned int i) int fa(unsigned int i) {
{
return bitn(0x2C79, i); return bitn(0x2C79, i);
} }
int fb(unsigned int i) int fb(unsigned int i) {
{
return bitn(0x6671, i); return bitn(0x6671, i);
} }
int fc(unsigned int i) int fc(unsigned int i) {
{
return bitn(0x7907287B, i); return bitn(0x7907287B, i);
} }
// the filter function that generates a bit of output from the prng state // 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; 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); 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()) // 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 state = hstate->shiftreg;
uint64_t temp; uint64_t temp;
temp = state ^ (state >> 1); temp = state ^ (state >> 1);
hstate->lfsr = state ^ (state >> 6) ^ (state >> 16) hstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
^ (temp >> 42) ^ (temp >> 46); ^ (temp >> 42) ^ (temp >> 46);
} }

View file

@ -336,7 +336,7 @@ extern rtccDate RTC_date; // date structure
#define TAG_TYPE_AWID_26 17 #define TAG_TYPE_AWID_26 17
#define TAG_TYPE_EM4X05 18 #define TAG_TYPE_EM4X05 18
#define TAG_TYPE_TAMAGOTCHI 19 #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 // various

View file

@ -182,7 +182,7 @@ unsigned char getbit(unsigned char byte, unsigned char bit);
void bytestohex(unsigned char *target, unsigned char *source, unsigned int length); 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_encode(unsigned char *target, unsigned char *source, unsigned int length);
unsigned int manchester_decode(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_ack(BOOL data);
BOOL command_nack(BYTE *reason); BOOL command_nack(BYTE *reason);
BOOL command_unknown(void); BOOL command_unknown(void);

View file

@ -142,19 +142,17 @@ rtccTime RTC_time; // time structure
rtccDate RTC_date; // date structure rtccDate RTC_date; // date structure
// convert byte-reversed 8 digit hex to unsigned long // convert byte-reversed 8 digit hex to unsigned long
unsigned long hexreversetoulong(BYTE *hex) unsigned long hexreversetoulong(BYTE *hex) {
{ unsigned long ret = 0L;
unsigned long ret= 0L;
unsigned int x; unsigned int x;
BYTE i; BYTE i;
if(strlen(hex) != 8) if (strlen(hex) != 8)
return 0L; return 0L;
for(i= 0 ; i < 4 ; ++i) for (i = 0 ; i < 4 ; ++i) {
{ if (sscanf(hex, "%2X", &x) != 1)
if(sscanf(hex, "%2X", &x) != 1) return 0L;
return 0L;
ret += ((unsigned long) x) << i * 8; ret += ((unsigned long) x) << i * 8;
hex += 2; hex += 2;
} }
@ -162,18 +160,17 @@ unsigned long hexreversetoulong(BYTE *hex)
} }
// convert byte-reversed 12 digit hex to unsigned long // convert byte-reversed 12 digit hex to unsigned long
unsigned long long hexreversetoulonglong(BYTE *hex) unsigned long long hexreversetoulonglong(BYTE *hex) {
{ unsigned long long ret = 0LL;
unsigned long long ret= 0LL;
BYTE tmp[9]; 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! // breaking direct conversion!
tmp[8]= '\0'; tmp[8] = '\0';
memset(tmp + 4, '0', 4); memset(tmp + 4, '0', 4);
memcpy(tmp, hex + 8, 4); memcpy(tmp, hex + 8, 4);
ret= hexreversetoulong(tmp); ret = hexreversetoulong(tmp);
ret <<= 32; ret <<= 32;
memcpy(tmp, hex, 8); memcpy(tmp, hex, 8);
ret += hexreversetoulong(tmp); ret += hexreversetoulong(tmp);

View file

@ -142,11 +142,11 @@ typedef int rtccDate;
#ifndef __PIC32MX__ #ifndef __PIC32MX__
#define __PIC32MX__ #define __PIC32MX__
#endif #endif
#define GetSystemClock() (80000000ul) #define GetSystemClock() (80000000ul)
#define GetPeripheralClock() (GetSystemClock()) #define GetPeripheralClock() (GetSystemClock())
#define GetInstructionClock() (GetSystemClock()) #define GetInstructionClock() (GetSystemClock())
//#define USE_SELF_POWER_SENSE_IO //#define USE_SELF_POWER_SENSE_IO
@ -322,7 +322,7 @@ typedef int rtccDate;
// spi for SD card // spi for SD card
#define SD_CARD_DET LATFbits.LATF0 #define SD_CARD_DET LATFbits.LATF0
#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it #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 SPI_CHANNEL1
#define SPI_SD_BUFF SPI1BUF #define SPI_SD_BUFF SPI1BUF
#define SPI_SD_STAT SPI1STATbits #define SPI_SD_STAT SPI1STATbits

View file

@ -229,18 +229,17 @@ static uint32_t hitag2_crypt(uint64_t x);
((S >> (C - 3)) & 8) ) ((S >> (C - 3)) & 8) )
static uint32_t hitag2_crypt(uint64_t s) static uint32_t hitag2_crypt(uint64_t x) {
{
const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
uint32_t bitindex; uint32_t bitindex;
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; bitindex = (ht2_function4a >> pickbits2_2(x, 1, 4)) & 1;
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2(x, 7, 11, 13)) & 0x02;
bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; bitindex |= ((ht2_function4b << 2) >> pickbits1x4(x, 16, 20, 22, 25)) & 0x04;
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(x, 27, 30, 32)) & 0x08;
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(x, 33, 42, 45)) & 0x10;
DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex); DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex);
return (ht2_function5c >> bitindex) & 1; return (ht2_function5c >> bitindex) & 1;
@ -253,13 +252,12 @@ static uint32_t hitag2_crypt(uint64_t s)
* uint32_t serialnum - 32 bit tag serial number * uint32_t serialnum - 32 bit tag serial number
* uint32_t initvector - 32 bit random IV from reader, part of tag authentication * 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 // init state, from serial number and lowest 16 bits of shared key
uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum; uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum;
// mix the initialisation vector and highest 32 bits of the shared key // 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 // 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 // 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 // optimise with one 64-bit intermediate
uint64_t temp = state ^ (state >> 1); uint64_t temp = state ^ (state >> 1);
pstate->lfsr = state ^ (state >> 6) ^ (state >> 16) pstate->lfsr = state ^ (state >> 6) ^ (state >> 16)
^ (state >> 26) ^ (state >> 30) ^ (state >> 41) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41)
^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22)
^ (temp >> 42) ^ (temp >> 46); ^ (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 * Hitag_State* pstate - in/out, internal cipher state after initialisation
* uint32_t steps - number of bits requested, (capped at 32) * 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; uint64_t state = pstate->shiftreg;
uint32_t result = 0; uint32_t result = 0;
uint64_t lfsr = pstate->lfsr; uint64_t lfsr = pstate->lfsr;
@ -446,7 +443,7 @@ unsigned hitag2_verifytest()
const uint64_t key = rev64 (0x524B494D4E4FUL); const uint64_t key = rev64 (0x524B494D4E4FUL);
const uint32_t serial = rev32 (0x69574349); const uint32_t serial = rev32 (0x69574349);
const uint32_t initvec = rev32 (0x72456E65); const uint32_t initvec = rev32 (0x72456E65);
uint32_t i; uint32_t i;
Hitag_State state; Hitag_State state;
@ -469,11 +466,10 @@ unsigned hitag2_verifytest()
#ifdef UNIT_TEST #ifdef UNIT_TEST
int main(int argc, char* argv[]) int main(int argc, char *argv[]) {
{
unsigned pass = hitag2_verifytest(); 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) { if (pass) {
hitag2_benchtest(10000); hitag2_benchtest(10000);

View file

@ -159,9 +159,9 @@ typedef struct {
uint64_t lfsr; // fast lfsr, used to make software faster uint64_t lfsr; // fast lfsr, used to make software faster
} Hitag_State; } 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_gen32();
unsigned int hitag2_benchtest(uint32_t count); unsigned int hitag2_benchtest(uint32_t count);

View file

@ -1,6 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h> #include <pthread.h>
#include <inttypes.h>
#include "HardwareProfile.h" #include "HardwareProfile.h"
#include "rfidler.h" #include "rfidler.h"
@ -34,11 +35,10 @@ struct threaddata {
uint64_t klowerrange; uint64_t klowerrange;
}; };
void printbin(uint64_t val) void printbin(uint64_t val) {
{
int i; int i;
for (i=0; i<64; i++) { for (i = 0; i < 64; i++) {
if (val & 0x8000000000000000) { if (val & 0x8000000000000000) {
printf("1"); printf("1");
} else { } else {
@ -48,8 +48,7 @@ void printbin(uint64_t val)
} }
} }
void printstate(Hitag_State *hstate) void printstate(Hitag_State *hstate) {
{
printf("shiftreg =\t"); printf("shiftreg =\t");
printbin(hstate->shiftreg); printbin(hstate->shiftreg);
printf("\n"); printf("\n");
@ -70,17 +69,16 @@ void printstate(Hitag_State *hstate)
((S >> (C - 3)) & 8) ) ((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_function4a = 0x2C79; // 0010 1100 0111 1001
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
uint32_t bitindex; uint32_t bitindex;
bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; bitindex = (ht2_function4a >> pickbits2_2(s, 1, 4)) & 1;
bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; 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 << 2) >> pickbits1x4(s, 16, 20, 22, 25)) & 0x04;
bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1(s, 27, 30, 32)) & 0x08;
bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10;
return (ht2_function5c >> bitindex) & 1; return (ht2_function5c >> bitindex) & 1;
@ -89,17 +87,16 @@ static uint32_t hitag2_crypt(uint64_t s)
// this function is a modification of the filter function f, based heavily // this function is a modification of the filter function f, based heavily
// on the hitag2_crypt function in Rfidler // 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_function4a = 0x2C79; // 0010 1100 0111 1001
const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001
const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011 const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011
uint32_t i; uint32_t i;
i = (ht2_function4a >> pickbits2_2 (klowery, 2, 5)) & 1; i = (ht2_function4a >> pickbits2_2(klowery, 2, 5)) & 1;
i |= ((ht2_function4b << 1) >> pickbits1_1_2 (klowery, 8, 12, 14)) & 0x02; 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 << 2) >> pickbits1x4(klowery, 17, 21, 23, 26)) & 0x04;
i |= ((ht2_function4b << 3) >> pickbits2_1_1 (klowery, 28, 31, 33)) & 0x08; i |= ((ht2_function4b << 3) >> pickbits2_1_1(klowery, 28, 31, 33)) & 0x08;
// modified to use reference implementation approach // modified to use reference implementation approach
// orig fc table is 0x7907287B = 0111 1001 0000 0111 0010 1000 0111 1011 // orig fc table is 0x7907287B = 0111 1001 0000 0111 0010 1000 0111 1011
@ -109,8 +106,7 @@ int fnP(uint64_t klowery)
} }
// comparison function for sorting/searching Tklower entries // 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 *Tk1 = (struct Tklower *)v1;
const struct Tklower *Tk2 = (struct Tklower *)v2; const struct Tklower *Tk2 = (struct Tklower *)v2;
@ -148,8 +144,7 @@ int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) {
} }
// function to test if a partial key is valid // 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 kupper;
uint64_t key; uint64_t key;
Hitag_State hstate; Hitag_State hstate;
@ -162,7 +157,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)); normaR = ((revaR >> 24) | ((revaR >> 8) & 0xff00) | ((revaR << 8) & 0xff0000) | (revaR << 24));
// search for remaining 14 bits // search for remaining 14 bits
for (kupper=0; kupper < 0x3fff; kupper++) { for (kupper = 0; kupper < 0x3fff; kupper++) {
key = (kupper << 34) | pkey; key = (kupper << 34) | pkey;
hitag2_init(&hstate, key, uid, nR); hitag2_init(&hstate, key, uid, nR);
b = hitag2_nstep(&hstate, 32); b = hitag2_nstep(&hstate, 32);
@ -170,7 +165,7 @@ int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR
*out = key; *out = key;
return 1; return 1;
} }
} }
return 0; return 0;
} }
@ -205,8 +200,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. // 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; struct threaddata *data = (struct threaddata *)d;
uint64_t uid; uint64_t uid;
struct nRaR *TnRaR; struct nRaR *TnRaR;
@ -249,11 +243,11 @@ void *crack(void *d)
} }
// find keys // 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); printf("trying klower = 0x%05"PRIx64"\n", klower);
// build table // build table
count = 0; count = 0;
for (y=0; y<0x40000; y++) { for (y = 0; y < 0x40000; y++) {
// create klowery // create klowery
klowery = (y << 16) | klower; klowery = (y << 16) | klower;
// check for cases where right most bit of fc doesn't matter // check for cases where right most bit of fc doesn't matter
@ -268,9 +262,9 @@ void *crack(void *d)
// insert y into shiftreg and extract keystream, reversed order // insert y into shiftreg and extract keystream, reversed order
b = 0; b = 0;
ytmp = y; ytmp = y;
for (j=0; j<2; j++) { for (j = 0; j < 2; j++) {
hstate.shiftreg = hstate.shiftreg | ((ytmp & 0xffff) << 48); hstate.shiftreg = hstate.shiftreg | ((ytmp & 0xffff) << 48);
for (i=0; i<16; i++) { for (i = 0; i < 16; i++) {
hstate.shiftreg = hstate.shiftreg >> 1; hstate.shiftreg = hstate.shiftreg >> 1;
bit = hitag2_crypt(hstate.shiftreg); bit = hitag2_crypt(hstate.shiftreg);
b = (b >> 1) | (bit << 31); b = (b >> 1) | (bit << 31);
@ -295,11 +289,11 @@ void *crack(void *d)
qsort(Tk, count, sizeof(struct Tklower), Tk_cmp); qsort(Tk, count, sizeof(struct Tklower), Tk_cmp);
// look for matches // look for matches
for (kmiddle=0; kmiddle<0x40000; kmiddle++) { for (kmiddle = 0; kmiddle < 0x40000; kmiddle++) {
// loop over nRaR pairs // loop over nRaR pairs
badguess = 0; badguess = 0;
found = 0; found = 0;
for (i=0; (i<numnrar) && (!badguess); i++) { for (i = 0; (i < numnrar) && (!badguess); i++) {
z = kmiddle ^ (TnRaR[i].nR & 0x3ffff); z = kmiddle ^ (TnRaR[i].nR & 0x3ffff);
ret = is_kmiddle_badguess(z, Tk, count, TnRaR[i].aR & 0x1); ret = is_kmiddle_badguess(z, Tk, count, TnRaR[i].aR & 0x1);
if (ret == 1) { if (ret == 1) {
@ -311,10 +305,10 @@ void *crack(void *d)
if ((found) && (!badguess)) { if ((found) && (!badguess)) {
// brute // brute
printf("possible partial key found: 0x%012lx\n", ((uint64_t)kmiddle << 16) | klower); printf("possible partial key found: 0x%012"PRIx64"\n", ((uint64_t)kmiddle << 16) | klower);
if (testkey(&foundkey, uid, (kmiddle << 16 | klower), TnRaR[0].nR, TnRaR[0].aR) && 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 // normalise foundkey
revkey = rev64(foundkey); revkey = rev64(foundkey);
foundkey = ((revkey >> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000); foundkey = ((revkey >> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000);
@ -331,8 +325,7 @@ void *crack(void *d)
return NULL; return NULL;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
FILE *fp; FILE *fp;
int i; int i;
pthread_t threads[NUM_THREADS]; pthread_t threads[NUM_THREADS];
@ -389,20 +382,20 @@ int main(int argc, char *argv[])
while (getline(&buf, &lenbuf, fp) > 0) { while (getline(&buf, &lenbuf, fp) > 0) {
buft1 = strchr(buf, ' '); buft1 = strchr(buf, ' ');
if (!buft1) { if (!buft1) {
printf("invalid file input on line %d\n", numnrar + 1); printf("invalid file input on line %u\n", numnrar + 1);
exit(1); exit(1);
} }
*buft1 = 0x00; *buft1 = 0x00;
buft1++; buft1++;
buft2 = strchr(buft1, '\n'); buft2 = strchr(buft1, '\n');
if (!buft2) { if (!buft2) {
printf("no CR on line %d\n", numnrar + 1); printf("no CR on line %u\n", numnrar + 1);
exit(1); exit(1);
} }
*buft2 = 0x00; *buft2 = 0x00;
if (!strncmp(buf, "0x", 2)) { if (!strncmp(buf, "0x", 2)) {
TnRaR[numnrar].nR = rev32(hexreversetoulong(buf+2)); TnRaR[numnrar].nR = rev32(hexreversetoulong(buf + 2));
TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1+2)); TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1 + 2));
} else { } else {
TnRaR[numnrar].nR = rev32(hexreversetoulong(buf)); TnRaR[numnrar].nR = rev32(hexreversetoulong(buf));
TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1)); TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1));
@ -414,7 +407,7 @@ int main(int argc, char *argv[])
fclose(fp); fclose(fp);
fp = NULL; fp = NULL;
printf("Loaded %d NrAr pairs\n", numnrar); printf("Loaded %u NrAr pairs\n", numnrar);
// create table of thread data // create table of thread data
tdata = (struct threaddata *)malloc(sizeof(struct threaddata) * NUM_THREADS); tdata = (struct threaddata *)malloc(sizeof(struct threaddata) * NUM_THREADS);
@ -423,7 +416,7 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
for (i=0; i<NUM_THREADS; i++) { for (i = 0; i < NUM_THREADS; i++) {
tdata[i].uid = uid; tdata[i].uid = uid;
tdata[i].TnRaR = TnRaR; tdata[i].TnRaR = TnRaR;
tdata[i].numnrar = numnrar; tdata[i].numnrar = numnrar;
@ -437,7 +430,7 @@ int main(int argc, char *argv[])
crack(tdata); crack(tdata);
} else { } else {
// run full threaded mode // 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))) { if (pthread_create(&(threads[i]), NULL, crack, (void *)(tdata + i))) {
printf("cannot start thread %d\n", i); printf("cannot start thread %d\n", i);
exit(1); exit(1);
@ -446,7 +439,7 @@ int main(int argc, char *argv[])
} }
// wait for threads to finish // 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)) { if (pthread_join(threads[i], &status)) {
printf("cannot join thread %d\n", i); printf("cannot join thread %d\n", i);
exit(1); exit(1);

View file

@ -9,8 +9,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
Hitag_State hstate; Hitag_State hstate;
FILE *fp; FILE *fp;
char *line = NULL; char *line = NULL;
@ -51,7 +50,7 @@ int main(int argc, char *argv[])
ar = strchr(line, ' '); ar = strchr(line, ' ');
*ar = 0x00; *ar = 0x00;
ar++; ar++;
ar[strlen(ar)-1] = 0x00; ar[strlen(ar) - 1] = 0x00;
if (!strncmp(line, "0x", 2)) { if (!strncmp(line, "0x", 2)) {
nr = line + 2; nr = line + 2;
} else { } else {

View file

@ -336,7 +336,7 @@ extern rtccDate RTC_date; // date structure
#define TAG_TYPE_AWID_26 17 #define TAG_TYPE_AWID_26 17
#define TAG_TYPE_EM4X05 18 #define TAG_TYPE_EM4X05 18
#define TAG_TYPE_TAMAGOTCHI 19 #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 // various

View file

@ -142,19 +142,17 @@ rtccTime RTC_time; // time structure
rtccDate RTC_date; // date structure rtccDate RTC_date; // date structure
// convert byte-reversed 8 digit hex to unsigned long // convert byte-reversed 8 digit hex to unsigned long
unsigned long hexreversetoulong(BYTE *hex) unsigned long hexreversetoulong(BYTE *hex) {
{ unsigned long ret = 0L;
unsigned long ret= 0L;
unsigned int x; unsigned int x;
BYTE i; BYTE i;
if(strlen(hex) != 8) if (strlen(hex) != 8)
return 0L; return 0L;
for(i= 0 ; i < 4 ; ++i) for (i = 0 ; i < 4 ; ++i) {
{ if (sscanf(hex, "%2X", &x) != 1)
if(sscanf(hex, "%2X", &x) != 1) return 0L;
return 0L;
ret += ((unsigned long) x) << i * 8; ret += ((unsigned long) x) << i * 8;
hex += 2; hex += 2;
} }
@ -162,18 +160,17 @@ unsigned long hexreversetoulong(BYTE *hex)
} }
// convert byte-reversed 12 digit hex to unsigned long // convert byte-reversed 12 digit hex to unsigned long
unsigned long long hexreversetoulonglong(BYTE *hex) unsigned long long hexreversetoulonglong(BYTE *hex) {
{ unsigned long long ret = 0LL;
unsigned long long ret= 0LL;
BYTE tmp[9]; 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! // breaking direct conversion!
tmp[8]= '\0'; tmp[8] = '\0';
memset(tmp + 4, '0', 4); memset(tmp + 4, '0', 4);
memcpy(tmp, hex + 8, 4); memcpy(tmp, hex + 8, 4);
ret= hexreversetoulong(tmp); ret = hexreversetoulong(tmp);
ret <<= 32; ret <<= 32;
memcpy(tmp, hex, 8); memcpy(tmp, hex, 8);
ret += hexreversetoulong(tmp); ret += hexreversetoulong(tmp);

Some files were not shown because too many files have changed in this diff Show more