Merge pull request #28 from RfidResearchGroup/master

Update from master
This commit is contained in:
mwalker33 2020-04-05 10:54:13 +10:00 committed by GitHub
commit c424a5f36c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
217 changed files with 10191 additions and 9155 deletions

1
.gitignore vendored
View file

@ -10,6 +10,7 @@
.profile
*.log
*.eml
*.html
*.o
*.a
*.d

View file

@ -41,6 +41,16 @@ addons:
- qt5
- RfidResearchGroup/proxmark3/arm-none-eabi-gcc
taps: RfidResearchGroup/proxmark3
# update trick to fix https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/14
update: true
before_install:
# bug?
# homebrew update replaced python2.7 by python3.7 but
# python3 link failed while python@2 still present, so let's do it again:
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
brew link --overwrite python;
fi
install:
if ! arm-none-eabi-gcc -v; then

View file

@ -3,6 +3,51 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Change `hf search` - now continue to search in case of dual tech cards (@iceman1001) Thanks to @ikarus23 for the suggestion!
- Added `hf topas info` - old reader command, now also prints NDEF (@iceman1001)
- Change `hf topaz reader` - now only prints lighter info, like UID. (@iceman1001)
- Change `hf iclass readtagfile` - improved param handling (@iceman1001)
- Change `hf mfu ndef` - text record now correctly decode language code and test (@iceman1001) Thanks to @bettse!
- Updated the helptexts for `hf iclass` commands (@iceman1001)
- Fix NDEF TLV lock / memory parsed correct (@merlokk)
- Change `mem spiffs` commands now parse h param correct (@iceman1001)
- Add colour to `hf mf chk` and `hf mf fchk` (@dunderhay)
- Change - updated public keys info (@bkerler)
- Change - mfc default keys removed dublicates (@iceman1001)
. Change - mfc default keys got new entries found on TagInfo app (@bkerler)
- Added `hf mfu ndef` - read and decode NDEF Type2 messages (@iceman1001)
- Added `data ndef` - decode NDEF messages (@iceman1001)
- Change - usb write's now waits for shiftregisters (@pwpiwi)
- Change - NDEF supports more signatures now (@iceman1001)
- OSX Makefile now supports `make style` and `make checks` (@Pizza_4u)
- Added `HF_LEGIC` standalone mode to read and simulate a Legic prime tag (@Pizza_4u)
- Added keri MS decode/encode and update 'lf keri clone' to support MS fc/cid cloning. (@mwalker33)
- 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 `lf keri demod` - adjusted the internal id. (@mwalker33)
- Added seamless integration with cryptohelper (@iceman1001)
- Change `lf hid brute` - new params for direction (UP/DOWN); textual and main loop actually exit. (@capnkrunchy and @iceman1001)
- Fix `lf hid brute` - made it work again (@capnkrunchy)
- Fix standalone mode HF_MATTYRUN - correct logic when all keys found in printing. partial fix (@iceman1001)
- Change static nonce detection got tighter (@iceman1001)
- Improved termux notes (@msoose)
- Fix `hf mf autopwn` - works on debian 10 *nix. Bad exit commands in hardnested (@iceman1001)
- Fix `hf mf hardnested` - bad mutex strategies (@msoose)
- Change `lf hitag` - now obeys `lf config` (@iceman1001)
- Ported all python 2 scripts to python 3 (@doegox and @sigwinch28)
- Removed undefined exit behaviour from `analyzesize` tool: it now exits with code 2 when called with wrong args (@sigwinch28)
- Replaced shebangs in scripts with more portable versions which use `/usr/bin/env` (@sigwinch28)
- Added `hf lto restore` - restore LTO cartridge memory from dump file [.bin|.eml] (@Kevin-Nakamoto)
- Added `LF_ICEHID` standalone mode which searches for lf HID credentials and store to RDV4 flashmem (@iceman1001)
- Added `HF_14ASNIFF` standalone mode with storing trace to RDV4 flashmem (@micolous)
@ -12,7 +57,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fix compilation under openSUSE (@hsanjuan)
- Added `lf nexwatch sim` - use raw hex to simulate (@iceman1001)
- Fix `lf indala read` - long id 224bits preamble identification less strict (@iceman1001)
- Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman100) Thanks to @xtigmh @uzlonewolf for their solutions.
- Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman1001) Thanks to @xtigmh @uzlonewolf for their solutions.
- Added `hf plot` (@pwpiwi)
- Fix `lf config` - when called with no params, it no longer mess up all device lf config settings. (@iceman1001)
- Change `lf indala clone` - new option `--Q5` writes to q5/T5555 tags. (@iceman1001)
@ -21,7 +66,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `commands.md` - document with all proxmark client commands. Generated with XX_internal_command_dump_markdown_XX. (@iceman1001)
- Change `lf pac clone` - new option `c <card id>` to allow cloning PAC/Stanley tag from card ID (@danshuk)
- Change `lf pac read` - decoded PAC/Stanley card ID (@danshuk)
- Change mifare classic keytable output refactored and uses colors (@iceman1001)
- Change mifare classic keytable output refactored and uses colors (@iceman1001)
- Fix `hf mf nested` - now writes the correct blockno (@iceman1001)
- Change `lf t55xx dump` - now supports saving to JSON (@iceman1001)
- Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi)
@ -417,6 +462,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 `script run luxeodump` (@0xdrrb)
- Fix `lf hitag reader 02` - print all bytes (@bosb)
- Fix hitag S simulation (still not working), write, add example HITAG S 256 (@bosb)
### Fixed
@ -591,8 +637,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Updated the Reveng 1.31 sourcecode to 1.40 from Reveng project homepage (@iceman1001)
- Added possibility to write direct to a Legic Prime Tag (MIM256/1024) without using values from the `BigBuffer` -> `hf legic writeRaw <addr> <value>` (@icsom)
- Added possibility to decrease DCF values at address 0x05 & 0x06 on a Legic Prime Tag
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
write the DCF-Values (both at once) with `hf legic write 0x05 0x02` (@icsom)
- Added script `legic.lua` for display and edit Data of Legic-Prime Tags (@icsom)
- Added the experimental HITAG_S support (@spenneb)

View file

@ -210,13 +210,20 @@ style:
# Detecting weird codepages and tabs.
checks:
# Make sure recode is installed
@which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 )
@echo "Files with suspicious chars:"
@find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \
-exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \;
@echo "Files with tabs:"
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
ifeq ($(platform),Darwin)
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
-exec egrep -l '\t' {} \;
else
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
-exec grep -lP '\t' {} \;
endif
# @echo "Files with printf \\\\t:"
# @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
# -exec grep -lP '\\t' {} \;

View file

@ -11,16 +11,16 @@
| FAQ's & Updates | Installation | Use of the Proxmark |
| ------------------- |:-------------------:| -------------------:|
|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|[Proxmark3 GUI](#proxmark3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|[What has changed?](#what-has-changed) | **[Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md)** | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|[Development](#development) | **[Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md)** | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|[Proxmark3 GUI](#proxmark3-gui)|**[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)**|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) |[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|
|[Notes on UART](/doc/uart_notes.md)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)|
|[Notes on frame format](/doc/new_frame_format.md)||[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
|[Notes on external flash](/doc/ext_flash_notes.md)||[EMV](/doc/emv_notes.md)|
|[Notes on Termux / Android](/doc/termux_notes.md)||[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)|
|[Notes on wireshark / tracedata](/doc/trace_wireshark_notes.md)||[JTAG](/doc/jtag_notes.md)|
|[Notes on tracedata / wireshark](/doc/trace_notes.md)||[JTAG](/doc/jtag_notes.md)|
|[Notes on loclass](/doc/loclass_notes.md)||[Complete client command set](/doc/commands.md)|
|[Notes on paths](/doc/path_notes.md)|||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
@ -47,9 +47,9 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
> ⚠ **Note**: This is a bleeding edge repository. The maintainers actively is working out of this repository and will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**.
This repo compiles nicely on
- Proxspace v3.2
- Proxspace v3.x
- Windows/mingw environment with Qt5.6.1 & GCC 4.8
- Ubuntu 1404, 1510, 1604, 1804, 1904
- Ubuntu 1604, 1804, 1904
- Mac OS X / Homebrew
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora
- WSL, WSL2 (Windows subsystem linux) on Windows 10
@ -67,7 +67,7 @@ We usually merge your contributions fast since we do like the idea of getting a
- notes on [external flash](/doc/ext_flash_notes.md)
- notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)
- notes on [Termux / Android](/doc/termux_notes.md)
- notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md)
- notes on [tracedata / Wireshark](/doc/trace_notes.md)
- notes on [loclass](/doc/loclass_notes.md)
- notes on [EMV](/doc/emv_notes.md)
- notes on [Paths](/doc/path_notes.md)

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"
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:
- ps: >-
Write-Host "Removing ProxSpace..." -NoNewLine
@ -409,4 +409,4 @@ on_success:
on_failure:
- ps: Write-Host "Build error." -ForegroundColor Red
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

@ -5,7 +5,7 @@
//-----------------------------------------------------------------------------
// LCD code
//-----------------------------------------------------------------------------
#include "LCD.h"
#include "LCD_disabled.h"
void LCDSend(unsigned int data) {
// 9th bit set for data, clear for command

View file

@ -41,10 +41,19 @@ define KNOWN_STANDALONE_DEFINITIONS
| LF_ICEHID | LF HID collector to flashmem |
| (RDV4 only) | |
+----------------------------------------------------------+
| LF_EM4100EMUL | Simulate predefined em4100 tags only |
| | |
+----------------------------------------------------------+
| LF_EM4100RWC | Read/simulate em4100 tags & clone it |
| | to T555x tags |
+----------------------------------------------------------+
| HF_LEGIC | Read/simulate Legic Prime tags |
| | storing in flashmem |
+----------------------------------------------------------+
endef
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID LF_EM4100EMUL LF_EM4100RWC
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF HF_LEGIC
STANDALONE_MODES_REQ_SMARTCARD :=
STANDALONE_MODES_REQ_FLASH := HF_COLIN HF_BOG HF_14ASNIFF LF_ICEHID
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)

View file

@ -40,4 +40,16 @@ endif
# WITH_STANDALONE_LF_ICEHID
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icehid.c
endif
endif
# WITH_STANDALONE_LF_EM4100EMUL
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100emul.c
endif
# WITH_STANDALONE_LF_EM4100RWC
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
SRC_STANDALONE = lf_em4100rwc.c
endif
# WITH_STANDALONE_HF_LEGIC
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
SRC_STANDALONE = hf_legic.c
endif

View file

@ -45,7 +45,7 @@
* This module emits debug strings during normal operation -- so try it out in
* the lab connected to PM3 client before taking it into the field.
*
* To delete the trace data from flash:
* To delete the trace data from flash:
*
* Caveats / notes:
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
@ -97,7 +97,7 @@ void RunMod() {
if (trace_len > 0) {
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
uint8_t* trace_buffer = BigBuf_get_addr();
uint8_t *trace_buffer = BigBuf_get_addr();
if (!exists_in_spiffs(HF_14ASNIFF_LOGFILE)) {
rdv40_spiffs_write(
HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
@ -117,7 +117,7 @@ void RunMod() {
SpinErr(LED_A, 200, 5);
SpinDelay(100);
LEDsoff();
SpinDelay(300);
DownloadTraceInstructions();

View file

@ -0,0 +1,173 @@
//-----------------------------------------------------------------------------
// (c) Stefanie Hofmann, 2020
// (c) Uli Heilmeier, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for Legic Prime read/sim
//-----------------------------------------------------------------------------
#include "standalone.h"
#include "proxmark3_arm.h"
#include "BigBuf.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "util.h"
#include "dbprint.h"
#include "ticks.h"
#include "legicrf.h"
#include "legicrfsim.h"
#include "legic.h" // legic_card_select_t struct
#include "spiffs.h" // flashmem
/*
* To list all dump files from flash:
*
* 1. mem spiffs tree
*
*
* To retrieve dump files from flash:
*
* 1. mem spiffs dump o hf-legic-XXYYZZWW-dump.bin f hf-legic-XXYYZZWW-dump.bin
* Copies log file from flash to your client.
*
*
* This module emits debug strings during normal operation -- so try it out in
* the lab connected to PM3 client before taking it into the field.
*
* To delete a dump file from flash:
*
* 1. mem spiffs remove hf-legic-XXYYZZWW-dump.bin
*
*/
void DownloadLogInstructions() {
Dbprintf("");
Dbprintf("[=] List all dumps from flash:");
Dbprintf("[=] " _YELLOW_("-") "mem spiffs tree");
Dbprintf("");
Dbprintf("[=] To save a dump file from flash to client:");
Dbprintf("[=] " _YELLOW_("-") "mem spiffs dump o hf-legic-UID-dump.bin f hf-legic-UID-dump.bin");
}
void save_dump_to_file(legic_card_select_t *p_card) {
#ifdef WITH_FLASH
// legic functions puts it memory in Emulator reserved memory.
uint8_t *mem = BigBuf_get_EM_addr();
char *preferredName = (char*)BigBuf_malloc(30);
if (preferredName == NULL) {
goto OUT;
}
sprintf(preferredName, "hf-legic-%02X%02X%02X%02X-dump", p_card->uid[0], p_card->uid[1], p_card->uid[2], p_card->uid[3]);
uint16_t preferredNameLen = strlen(preferredName);
char *filename = (char*)BigBuf_malloc(preferredNameLen + 4 + 1 + 10);
if (filename == NULL) {
goto OUT;
}
sprintf(filename, "%.*s%s", preferredNameLen, preferredName, ".bin");
uint16_t num = 1;
while (exists_in_spiffs(filename)) {
sprintf(filename, "%.*s-%d%s", preferredNameLen, preferredName, num, ".bin");
num++;
}
rdv40_spiffs_write(filename, mem, p_card->cardsize, RDV40_SPIFFS_SAFETY_SAFE);
Dbprintf("[=] saved card dump to flashmem::" _YELLOW_("%s"), filename);
OUT:
BigBuf_free_keep_EM();
#endif
}
void ModInfo(void) {
DbpString(" HF Legic Prime standalone");
}
// Searching for Legic card until found and read.
// Simulating recorded Legic Prime card.
// C = Searching
// A, B, C = Reading
// A, D = Simulating
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
Dbprintf("[=] >> HF Legic Prime Read/Simulate Started <<");
DbpString("[=] press and HOLD button to exit standalone mode");
for (;;) {
WDT_HIT();
//exit from hf_legic, send usbcommand
if (data_available()) break;
//Was our button held down or pressed?
int button_pressed = BUTTON_HELD(280);
if (button_pressed == BUTTON_HOLD) {
break;
}
LEDsoff();
LED_C_ON();
DbpString("[=] looking for tags");
int read_success = PM3_ESOFT;
//search for legic card until reading successfull or button pressed
do {
LED_C_ON();
SpinDelay(500);
// We don't care if we read a MIM256, MIM512 or MIM1024
// we just read 1024 bytes
read_success = LegicRfReaderEx(0, 1024, 0x55);
} while (read_success == PM3_ESOFT && !BUTTON_PRESS());
LEDsoff();
//simulate if read successfully
if (read_success != PM3_ESOFT) {
legic_card_select_t *p_card;
p_card = getLegicCardInfo();
if (p_card->cardsize == 0)
continue;
save_dump_to_file(p_card);
LED_D_ON();
uint8_t ct;
switch(p_card->tagtype) {
case 0x0D:
ct = 0;
break;
case 0x1D:
ct = 1;
break;
case 0x3D:
ct = 2;
break;
default:
continue;
}
// The read data is migrated to a MIM1024 card
LegicRfSimulate(ct);
}
}
LEDsoff();
#ifdef WITH_FLASH
DownloadLogInstructions();
#endif
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}

View file

@ -323,7 +323,7 @@ void RunMod() {
Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt);
int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64);
if (key == -1) {
LED(LED_RED, 50); //red
LED(LED_RED, 50);
Dbprintf("\t✕ Key not found for this sector!");
allKeysFound = false;
// break;
@ -348,21 +348,24 @@ void RunMod() {
TODO:
- Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman)
*/
if (!allKeysFound && keyFound) {
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
LED_C_ON(); //red
LED_A_ON(); //yellow
// no room to run nested attack on device (iceman)
// Do nested attack, set allKeysFound = true;
// allKeysFound = true;
if (allKeysFound) {
Dbprintf("\t✓ All keys found");
} else {
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
LED_C_ON(); //red
if (keyFound) {
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
LED_C_ON(); //red
LED_A_ON(); //yellow
// no room to run nested attack on device (iceman)
// Do nested attack, set allKeysFound = true;
// allKeysFound = true;
} else {
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
LED_C_ON(); //red
}
}
/*
If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
*/
// If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
if ((transferToEml) && (allKeysFound)) {
emlClearMem();

View file

@ -0,0 +1,100 @@
//-----------------------------------------------------------------------------
// Artyom Gnatyuk, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LF emul - Very simple mode. Simulate only predefined in low[] IDs
// Short click - select next slot and start simulation
//-----------------------------------------------------------------------------
#include "standalone.h"
#include "proxmark3_arm.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "lfops.h"
#include "util.h"
#include "dbprint.h"
#include "ticks.h"
#include "string.h"
#include "BigBuf.h"
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
#define CLOCK 64 //for 125kHz
// low & high - array for storage IDs. Its length must be equal.
// Predefined IDs must be stored in low[].
// In high[] must be nulls
uint64_t low[] = {0x565A1140BE, 0x365A398149, 0x5555555555, 0xFFFFFFFFFF};
uint32_t high[] = {0, 0, 0, 0};
uint8_t *bba, slots_count;
int buflen;
void ModInfo(void) {
DbpString(" LF EM4100 simulator standalone mode");
}
uint64_t ReversQuads(uint64_t bits) {
uint64_t result = 0;
for (int i = 0; i < 16; i++) {
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
}
return result >> 24;
}
void FillBuff(uint8_t bit) {
memset(bba + buflen, bit, CLOCK / 2);
buflen += (CLOCK / 2);
memset(bba + buflen, bit ^ 1, CLOCK / 2);
buflen += (CLOCK / 2);
}
void ConstructEM410xEmulBuf(uint64_t id) {
int i, j, binary[4], parity[4];
buflen = 0;
for (i = 0; i < 9; i++)
FillBuff(1);
parity[0] = parity[1] = parity[2] = parity[3] = 0;
for (i = 0; i < 10; i++) {
for (j = 3; j >= 0; j--, id /= 2)
binary[j] = id % 2;
for (j = 0; j < 4; j++)
FillBuff(binary[j]);
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
for (j = 0; j < 4; j++)
parity[j] ^= binary[j];
}
for (j = 0; j < 4; j++)
FillBuff(parity[j]);
FillBuff(0);
}
void LED_Slot(int i) {
LEDsoff();
if (slots_count > 4) {
LED(i % MAX_IND, 0); //binary indication for slots_count > 4
} else {
LED(1 << i, 0); //simple indication for slots_count <=4
}
}
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
Dbprintf("[=] >> LF EM4100 simulator started <<");
int selected = 0; //selected slot after start
slots_count = sizeof(low) / sizeof(low[0]);
bba = BigBuf_get_addr();
for (;;) {
WDT_HIT();
if (data_available()) break;
SpinDelay(100);
SpinUp(100);
LED_Slot(selected);
ConstructEM410xEmulBuf(ReversQuads(low[selected]));
SimulateTagLowFrequency(buflen, 0, true);
selected = (selected + 1) % slots_count;
}
}

View file

@ -0,0 +1,204 @@
//-----------------------------------------------------------------------------
// Artyom Gnatyuk, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LF rwc - This mode can simulate ID from selected slot, read ID to
// selected slot, write from selected slot to T5555 tag and store
// readed ID to flash (only RDV4). Also you can set predefined IDs
// in any slot.
// To recall stored ID from flash execute:
// mem spifss dump o emdump p
// or:
// mem spifss dump o emdump f emdump
// then from shell:
// hexdump emdump -e '5/1 "%02X" /0 "\n"'
//-----------------------------------------------------------------------------
#include "standalone.h"
#include "proxmark3_arm.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "lfops.h"
#include "util.h"
#include "dbprint.h"
#include "ticks.h"
#include "string.h"
#include "BigBuf.h"
#include "spiffs.h"
#ifdef WITH_FLASH
#include "flashmem.h"
#endif
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
#define CLOCK 64 //for 125kHz
// low & high - array for storage IDs. Its length must be equal.
// Predefined IDs must be stored in low[].
// In high[] must be nulls
uint64_t low[] = {0x565AF781C7, 0x540053E4E2, 0x1234567890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t high[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t *bba, slots_count;
int buflen;
void ModInfo(void) {
DbpString(" LF EM4100 read/write/clone mode");
}
uint64_t ReversQuads(uint64_t bits) {
uint64_t result = 0;
for (int i = 0; i < 16; i++) {
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
}
return result >> 24;
}
void FillBuff(uint8_t bit) {
memset(bba + buflen, bit, CLOCK / 2);
buflen += (CLOCK / 2);
memset(bba + buflen, bit ^ 1, CLOCK / 2);
buflen += (CLOCK / 2);
}
void ConstructEM410xEmulBuf(uint64_t id) {
int i, j, binary[4], parity[4];
buflen = 0;
for (i = 0; i < 9; i++)
FillBuff(1);
parity[0] = parity[1] = parity[2] = parity[3] = 0;
for (i = 0; i < 10; i++) {
for (j = 3; j >= 0; j--, id /= 2)
binary[j] = id % 2;
for (j = 0; j < 4; j++)
FillBuff(binary[j]);
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
for (j = 0; j < 4; j++)
parity[j] ^= binary[j];
}
for (j = 0; j < 4; j++)
FillBuff(parity[j]);
FillBuff(0);
}
void LED_Slot(int i) {
LEDsoff();
if (slots_count > 4) {
LED(i % MAX_IND, 0); //binary indication, usefully for slots_count > 4
} else {
LED(1 << i, 0); //simple indication for slots_count <=4
}
}
void FlashLEDs(uint32_t speed, uint8_t times) {
for (int i = 0; i < times * 2; i++) {
LED_A_INV();
LED_B_INV();
LED_C_INV();
LED_D_INV();
SpinDelay(speed);
}
}
#ifdef WITH_FLASH
void SaveIDtoFlash(int addr, uint64_t id) {
uint8_t bt[5];
char *filename = "emdump";
rdv40_spiffs_mount();
for (int i = 0; i < 5; i++) {
bt[4 - i] = (uint8_t)(id >> 8 * i & 0xff);
}
if (exists_in_spiffs(filename) == false) {
rdv40_spiffs_write(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL);
} else {
rdv40_spiffs_append(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL);
}
}
#endif
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
Dbprintf("[=] >> LF EM4100 read/write/clone started <<");
int selected = 0;
//state 0 - select slot
// 1 - read tag to selected slot,
// 2 - simulate tag from selected slot
// 3 - write to T5555 tag
uint8_t state = 0;
slots_count = sizeof(low) / sizeof(low[0]);
bba = BigBuf_get_addr();
LED_Slot(selected);
for (;;) {
WDT_HIT();
if (data_available()) break;
int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
switch (state) {
case 0:
// Select mode
if (button_pressed == 1) {
// Long press - switch to simulate mode
SpinUp(100);
LED_Slot(selected);
state = 2;
} else if (button_pressed < 0) {
// Click - switch to next slot
selected = (selected + 1) % slots_count;
LED_Slot(selected);
}
break;
case 1:
// Read mode.
if (button_pressed > 0) {
// Long press - switch to read mode
SpinUp(100);
LED_Slot(selected);
state = 3;
} else if (button_pressed < 0) {
// Click - exit to select mode
CmdEM410xdemod(1, &high[selected], &low[selected], 0);
FlashLEDs(100, 5);
#ifdef WITH_FLASH
SaveIDtoFlash(selected, low[selected]);
#endif
state = 0;
}
break;
case 2:
// Simulate mode
if (button_pressed > 0) {
// Long press - switch to read mode
SpinDown(100);
LED_Slot(selected);
state = 1;
} else if (button_pressed < 0) {
// Click - start simulating. Click again to exit from simulate mode
LED_Slot(selected);
ConstructEM410xEmulBuf(ReversQuads(low[selected]));
FlashLEDs(100, 5);
SimulateTagLowFrequency(buflen, 0, 1);
LED_Slot(selected);
state = 0; // Switch to select mode
}
break;
case 3:
// Write tag mode
if (button_pressed > 0) {
// Long press - switch to select mode
SpinDown(100);
LED_Slot(selected);
state = 0;
} else if (button_pressed < 0) {
// Click - write ID to tag
WriteEM410x(0, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff));
LED_Slot(selected);
state = 0; // Switch to select mode
}
break;
}
}
}

View file

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

View file

@ -42,6 +42,7 @@
#include "Standalone/standalone.h"
#include "util.h"
#include "ticks.h"
#include "commonutil.h"
#ifdef WITH_LCD
#include "LCD.h"
@ -548,7 +549,7 @@ void ListenReaderField(uint8_t limit) {
// iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader.
hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40);
#else
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
#endif
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
hf_baseline = hf_av;
@ -721,12 +722,20 @@ static void PacketReceived(PacketCommandNG *packet) {
setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes);
break;
}
case CMD_LF_SAMPLING_GET_CONFIG: {
case CMD_LF_SAMPLING_PRINT_CONFIG: {
printConfig();
break;
}
case CMD_LF_SAMPLING_GET_CONFIG: {
sample_config *config = getSamplingConfig();
reply_ng(CMD_LF_SAMPLING_GET_CONFIG, PM3_SUCCESS, (uint8_t *)config, sizeof(sample_config));
break;
}
case CMD_LF_SAMPLING_SET_CONFIG: {
setSamplingConfig((sample_config *) packet->data.asBytes);
sample_config c;
memcpy(&c, packet->data.asBytes, sizeof(sample_config));
setSamplingConfig(&c);
// setSamplingConfig((sample_config *) packet->data.asBytes);
break;
}
case CMD_LF_ACQ_RAW_ADC: {
@ -1239,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) {
// SniffMifare(packet->oldarg[0]);
// break;
// }
case CMD_HF_MIFARE_PERSONALIZE_UID: {
struct p {
uint8_t keytype;
uint8_t pers_option;
uint8_t key[6];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
uint64_t authkey = bytes_to_num(payload->key, 6);
MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey);
break;
}
case CMD_HF_MIFARE_SETMOD: {
MifareSetMod(packet->data.asBytes);
break;

View file

@ -1,4 +1,4 @@
#include "buzzer.h"
#include "buzzer_disabled.h"
void Ring_BEE_ONCE(uint16_t music_note) {
BEE_ON();

View file

@ -26,9 +26,7 @@
* May 2005
*/
#include <string.h>
#include "desfire_crypto.h"
#include "desfire_crypto_disabled.h"
#include "crc32.h"
#include "printf.h"
#include "desfire.h"

View file

@ -6,7 +6,7 @@
// Fonts for the LCD
//-----------------------------------------------------------------------------
#include "fonts.h"
#include "fonts_disabled.h"
const char FONT6x8[97][8] = {
{0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // columns, rows, bytes per char

View file

@ -20,6 +20,8 @@
// Anon, 2019
// Doegox, 2020
#define DBG if (DBGLEVEL >= DBG_EXTENDED)
#include "hitag2.h"
#include "hitag2_crypto.h"
#include "string.h"
@ -92,7 +94,7 @@ uint8_t nonce[4];
bool key_no;
static uint64_t cipher_state;
size_t blocknr;
int16_t blocknr;
size_t flipped_bit = 0;
uint32_t byte_value = 0;
@ -305,6 +307,9 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
break;
}
// LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false);
// LogTrace(tx, nbytes(txlen), 0, 0, NULL, true);
if (tag.crypto_active) {
hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8);
}
@ -337,12 +342,12 @@ static uint32_t hitag_reader_send_bit(int bit) {
lf_wait_periods(HITAG_T_1 - HITAG_T_LOW); // wait for 26-32 times the carrier period
wait += HITAG_T_1 - HITAG_T_LOW;
}
/*lf_wait_periods(10);*/
LED_A_OFF();
return wait;
}
// reader/writer
// reader / writer commands
static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) {
uint32_t wait = 0;
@ -403,7 +408,7 @@ void fix_ac_decoding(uint8_t *input, size_t len) {
*/
// looks at number of received bits.
// looks at number of received bits.
// 0 = collision?
// 32 = good response
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
@ -539,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
} else if (bSelecting) {
// Initiate auth
tx[0] = 0xa0 | key_no >> 4; // WRCPAGE
tx[0] = 0xa0 | (key_no); // WRCPAGE
tx[1] = blocknr << 4;
crc = hitag_crc(tx, 12);
tx[1] |= crc >> 4;
@ -577,14 +582,15 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t
Dbhexdump(4, logdata_1, false);
bSuccessful = true;
return false;
// read next page of card until done
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
tx[1] = blocknr << 4;
crc = hitag_crc(tx, 12);
tx[1] |= crc >> 4;
tx[2] = crc << 4;
*txlen = 20;
/*
// read next page of card until done
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
tx[1] = blocknr << 4;
crc = hitag_crc(tx, 12);
tx[1] |= crc >> 4;
tx[2] = crc << 4;
*txlen = 20;
*/
}
}
break;
@ -953,17 +959,18 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
memcpy(tag.sectors[blocknr], rx, 4);
blocknr++;
Dbhexdump(4, rx, false);
DBG Dbhexdump(4, rx, false);
}
if (blocknr > 0) {
DBG DbpString("Read successful!");
bSuccessful = true;
return false;
return true;
}
}
break;
// Unexpected response
default: {
Dbprintf("Unknown frame length: %d", rxlen);
DBG Dbprintf("Unknown frame length: %d", rxlen);
return false;
}
break;
@ -1017,7 +1024,7 @@ void SniffHitag2(void) {
// Receive frame, watch for at most T0*EOF periods
lf_reset_counter();
// lf_reset_counter();
// Wait "infinite" for reader modulation
periods = lf_detect_gap(20000);
@ -1071,8 +1078,6 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
DbpString("Starting Hitag2 simulation");
LED_D_ON();
// hitag2 state machine?
hitag2_init();
@ -1086,7 +1091,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
uint32_t block = 0;
for (size_t i = 0; i < 12; i++) {
// num2bytes?
// num2bytes?
for (size_t j = 0; j < 4; j++) {
block <<= 8;
block |= tag.sectors[i][j];
@ -1094,31 +1099,36 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
Dbprintf("| %d | %08x |", i, block);
}
uint8_t tag_modulation;
uint8_t reader_modulation;
size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5;
uint8_t nrz_samples[max_nrzs];
size_t nrzs = 0, periods = 0;
// uint32_t command_start = 0, command_duration = 0;
// int16_t checked = 0;
int16_t checked = 0;
// SIMULATE
while (!BUTTON_PRESS()) {
loop1:
LED_D_ON();
// lf_reset_counter();
LED_A_OFF();
WDT_HIT();
// only every 1000th times, in order to save time when collecting samples.
if (checked == 100) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
/*
// only every 1000th times, in order to save time when collecting samples.
if (checked == 100) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
*/
rxlen = 0;
@ -1126,10 +1136,10 @@ loop1:
bool waiting_for_first_edge = true;
// Did we detected any modulaiton at all
bool detected_tag_modulation = false;
bool detected_modulation = false;
// Use the current modulation state as starting point
tag_modulation = lf_get_tag_modulation();
reader_modulation = lf_get_reader_modulation();
// Receive frame, watch for at most max_nrzs periods
// Reset the number of NRZ samples and use edge detection to detect them
@ -1141,7 +1151,7 @@ loop1:
// Just break out of loop after an initial time-out (tag is probably not available)
// The function lf_count_edge_periods() returns 0 when a time-out occurs
if (periods == 0) {
goto loop1; //break;
break;
}
LED_A_ON();
@ -1159,32 +1169,36 @@ loop1:
periods = 16;
// We have received more than 0 periods, so we have detected a tag response
detected_tag_modulation = true;
detected_modulation = true;
}
// Evaluate the number of periods before the next edge
if (periods > 24 && periods <= 64) {
// Detected two sequential equal bits and a modulation switch
// NRZ modulation: (11 => --|) or (11 __|)
nrz_samples[nrzs++] = tag_modulation;
nrz_samples[nrzs++] = tag_modulation;
nrz_samples[nrzs++] = reader_modulation;
nrz_samples[nrzs++] = reader_modulation;
// Invert tag modulation state
tag_modulation ^= 1;
reader_modulation ^= 1;
} else if (periods > 0 && periods <= 24) {
// Detected one bit and a modulation switch
// NRZ modulation: (1 => -|) or (0 _|)
nrz_samples[nrzs++] = tag_modulation;
tag_modulation ^= 1;
nrz_samples[nrzs++] = reader_modulation;
reader_modulation ^= 1;
} else {
tag_modulation ^= 1;
reader_modulation ^= 1;
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
Dbprintf("Detected unexpected period count: %d", periods);
break;
}
}
LED_D_OFF();
// If there is no response, just repeat the loop
if (!detected_tag_modulation) continue;
if (!detected_modulation) continue;
LED_A_OFF();
// Make sure we always have an even number of samples. This fixes the problem
// of ending the manchester decoding with a zero. See the example below where
@ -1194,7 +1208,7 @@ loop1:
// The last modulation change of a zero is not detected, but we should take
// the half period in account, otherwise the demodulator will fail.
if ((nrzs % 2) != 0) {
nrz_samples[nrzs++] = tag_modulation;
nrz_samples[nrzs++] = reader_modulation;
}
LED_B_ON();
@ -1206,8 +1220,8 @@ loop1:
if (nrzs < 5) {
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
continue;
} else {
for (size_t i = 0; i < 5; i++){
} else {
for (size_t i = 0; i < 5; i++) {
if (nrz_samples[i] != 1) {
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one", i);
}
@ -1215,7 +1229,7 @@ loop1:
}
// Pack the response into a byte array
for (size_t i = 5; i < 37; i++){
for (size_t i = 5; i < 37; i++) {
uint8_t bit = nrz_samples[i];
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
rxlen++;
@ -1233,8 +1247,8 @@ loop1:
// not that since the clock counts since the rising edge, but T_Wait1 is
// with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low)
// periods. The gap time T_Low varies (4..10). All timer values are in
// terms of T0 units
lf_wait_periods(200);
// terms of T0 units (HITAG_T_WAIT_1_MIN - HITAG_T_LOW )
lf_wait_periods(HITAG_T_WAIT_1_MIN);
// Send and store the tag answer (if there is any)
if (txlen) {
@ -1266,19 +1280,19 @@ loop1:
void ReaderHitag(hitag_function htf, hitag_data *htd) {
uint32_t command_start = 0;
uint32_t command_duration = 0;
uint32_t response_start = 0;
uint32_t response_duration = 0;
uint32_t command_start = 0, command_duration = 0;
uint32_t response_start = 0, response_duration = 0;
uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
uint8_t txbuf[HITAG_FRAME_LEN];
uint8_t *tx = txbuf;
size_t txlen = 0;
int t_wait_1;
int t_wait_1 = 204;
int t_wait_1_guard = 8;
int t_wait_2;
size_t tag_size;
int t_wait_2 = 128;
size_t tag_size = 48;
bool bStop = false;
// Raw demodulation/decoding by sampling edge periods
@ -1292,19 +1306,17 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
set_tracing(true);
clear_trace();
DbpString("Starting Hitag reader family");
// Check configuration
switch (htf) {
case RHT1F_PLAIN: {
Dbprintf("Read public blocks in plain mode");
DBG Dbprintf("Read public blocks in plain mode");
// this part will be unreadable
memset(tag.sectors + 2, 0x0, 30);
blocknr = 0;
break;
}
case RHT1F_AUTHENTICATE: {
Dbprintf("Read all blocks in authed mode");
DBG Dbprintf("Read all blocks in authed mode");
memcpy(nonce, htd->ht1auth.nonce, 4);
memcpy(key, htd->ht1auth.key, 4);
memcpy(logdata_0, htd->ht1auth.logdata_0, 4);
@ -1314,19 +1326,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
memset(logdata_1, 0x00, 4);
byte_value = 0;
key_no = htd->ht1auth.key_no;
Dbprintf("Authenticating using key #%d:", key_no);
Dbhexdump(4, key, false);
DbpString("Nonce:");
Dbhexdump(4, nonce, false);
DbpString("Logdata_0:");
Dbhexdump(4, logdata_0, false);
DbpString("Logdata_1:");
Dbhexdump(4, logdata_1, false);
DBG Dbprintf("Authenticating using key #%d:", key_no);
DBG Dbhexdump(4, key, false);
DBG DbpString("Nonce:");
DBG Dbhexdump(4, nonce, false);
DBG DbpString("Logdata_0:");
DBG Dbhexdump(4, logdata_0, false);
DBG DbpString("Logdata_1:");
DBG Dbhexdump(4, logdata_1, false);
blocknr = 0;
break;
}
case RHT2F_PASSWORD: {
Dbprintf("List identifier in password mode");
DBG Dbprintf("List identifier in password mode");
if (memcmp(htd->pwd.password, "\x00\x00\x00\x00", 4) == 0)
memcpy(password, tag.sectors[1], sizeof(password));
else
@ -1338,19 +1350,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
break;
}
case RHT2F_AUTHENTICATE: {
DbpString("Authenticating using nr,ar pair:");
DBG DbpString("Authenticating using nr,ar pair:");
memcpy(NrAr, htd->auth.NrAr, 8);
Dbhexdump(8, NrAr, false);
DBG Dbhexdump(8, NrAr, false);
bCrypto = false;
bAuthenticating = false;
break;
}
case RHT2F_CRYPTO: {
DbpString("Authenticating using key:");
DBG DbpString("Authenticating using key:");
memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code.
Dbhexdump(6, key, false);
DbpString("Nonce:");
Dbhexdump(4, nonce, false);
DBG Dbhexdump(6, key, false);
DBG DbpString("Nonce:");
DBG Dbhexdump(4, nonce, false);
memcpy(nonce, htd->crypto.data, 4);
blocknr = 0;
bCrypto = false;
@ -1358,7 +1370,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
break;
}
case RHT2F_TEST_AUTH_ATTEMPTS: {
Dbprintf("Testing %d authentication attempts", (auth_table_len / 8));
DBG Dbprintf("Testing %d authentication attempts", (auth_table_len / 8));
auth_table_pos = 0;
memcpy(NrAr, auth_table, 8);
bCrypto = false;
@ -1371,7 +1383,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
break;
}
default: {
Dbprintf("Error, unknown function: %d", htf);
DBG Dbprintf("Error, unknown function: %d", htf);
set_tracing(false);
return;
}
@ -1382,9 +1394,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
// hitag2 state machine?
hitag2_init();
// init as reader
lf_init(true, false);
uint8_t attempt_count = 0;
// Tag specific configuration settings (sof, timings, etc.)
@ -1392,41 +1401,40 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
// hitagS settings
t_wait_1 = 204;
t_wait_2 = 128;
/*tag_size = 256;*/
flipped_bit = 0;
tag_size = 8;
DbpString("Configured for hitagS reader");
DBG DbpString("Configured for hitagS reader");
} else if (htf < 20) {
// hitag1 settings
t_wait_1 = 204;
t_wait_2 = 128;
tag_size = 256;
flipped_bit = 0;
DbpString("Configured for hitag1 reader");
DBG DbpString("Configured for hitag1 reader");
} else if (htf < 30) {
// hitag2 settings
t_wait_1 = HITAG_T_WAIT_1_MIN;
t_wait_2 = HITAG_T_WAIT_2_MIN;
tag_size = 48;
DbpString("Configured for hitag2 reader");
} else {
Dbprintf("Error, unknown hitag reader type: %d", htf);
return;
DBG DbpString("Configured for hitag2 reader");
}
// init as reader
lf_init(true, false);
uint8_t tag_modulation;
size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit
uint8_t nrz_samples[max_nrzs];
size_t nrzs = 0;
int16_t checked = 0;
while (!bStop) {
while (!bStop && !BUTTON_PRESS()) {
WDT_HIT();
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (BUTTON_PRESS() || data_available()) {
if (data_available()) {
checked = -1;
break;
} else {
@ -1471,7 +1479,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
break;
}
default: {
Dbprintf("Error, unknown function: %d", htf);
DBG Dbprintf("Error, unknown function: %d", htf);
goto out;
}
}
@ -1531,7 +1539,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
} else {
// The function lf_count_edge_periods() returns 0 when a time-out occurs
if (periods == 0) {
//Dbprintf("Detected timeout after [%d] nrz samples", nrzs);
DBG Dbprintf("Detected timeout after [%d] nrz samples", nrzs);
break;
}
}
@ -1552,7 +1560,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
tag_modulation ^= 1;
} else {
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
//Dbprintf("Detected unexpected period count: %d", periods);
DBG Dbprintf("Detected unexpected period count: %d", periods);
break;
}
}
@ -1591,13 +1599,13 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
// Verify if the header consists of five consecutive ones
if (nrzs < 5) {
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
DBG Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
break;
} else {
size_t i;
for (i = 0; i < 5; i++) {
if (nrz_samples[i] != 1) {
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i);
DBG Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i);
break;
}
}
@ -1608,7 +1616,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
for (size_t i = 5; i < nrzs; i++) {
uint8_t bit = nrz_samples[i];
if (bit > 1) { // When Manchester detects impossible symbol it writes "7"
Dbprintf("Error in Manchester decoding, abort");
DBG Dbprintf("Error in Manchester decoding, abort");
break;
}
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
@ -1648,16 +1656,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
uint32_t command_start = 0;
uint32_t command_duration = 0;
uint32_t response_start = 0;
uint32_t response_duration = 0;
uint32_t response_duration = 0;
uint8_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
uint8_t txbuf[HITAG_FRAME_LEN];
uint8_t *tx = txbuf;
size_t txlen = 0;
int t_wait_1;
int t_wait_1 = 204;
int t_wait_1_guard = 8;
int t_wait_2;
size_t tag_size;
int t_wait_2 = 128;
size_t tag_size = 48;
bool bStop = false;
// Raw demodulation/decoding by sampling edge periods
@ -1671,8 +1681,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
set_tracing(true);
clear_trace();
DbpString("Starting Hitag writer family");
// Check configuration
switch (htf) {
case WHT2F_CRYPTO: {
@ -1710,7 +1719,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
// init as reader
lf_init(true, false);
// Tag specific configuration settings (sof, timings, etc.)
if (htf < 10) {
// hitagS settings
@ -1721,21 +1730,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
tag_size = 8;
DbpString("Configured for hitagS writer");
} else if (htf < 20) {
// hitag1 settings
// hitag1 settings
t_wait_1 = 204;
t_wait_2 = 128;
tag_size = 256;
flipped_bit = 0;
DbpString("Configured for hitag1 writer");
} else if (htf < 30) {
// hitag2 settings
// hitag2 settings
t_wait_1 = HITAG_T_WAIT_1_MIN;
t_wait_2 = HITAG_T_WAIT_2_MIN;
tag_size = 48;
DbpString("Configured for hitag2 writer");
} else {
Dbprintf("Error, unknown hitag writer type: %d", htf);
return;
}
uint8_t tag_modulation;
@ -1744,11 +1750,11 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
size_t nrzs = 0;
int16_t checked = 0;
while (!bStop) {
while (!bStop && !BUTTON_PRESS()) {
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (BUTTON_PRESS() || data_available()) {
if (data_available()) {
checked = -1;
break;
} else {
@ -1776,7 +1782,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
}
}
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
lf_wait_periods(t_wait_2);
command_start += t_wait_2;

View file

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

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_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_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 hitag2crack_send_auth(uint8_t *nrar);

View file

@ -10,6 +10,7 @@
//-----------------------------------------------------------------------------
// Some code was copied from Hitag2.c
//-----------------------------------------------------------------------------
// bosb 2020
#include "hitagS.h"
@ -23,6 +24,7 @@
#include "string.h"
#include "commonutil.h"
#include "hitag2_crypto.h"
#include "lfadc.h"
#define CRC_PRESET 0xFF
#define CRC_POLYNOM 0x1D
@ -50,6 +52,22 @@ size_t blocknr;
bool end = false;
//#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_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))))
@ -86,7 +104,7 @@ bool end = false;
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
#define DEBUG 0
#define DBGLEVEL 0
/*
* 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) {
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
for (size_t i = 0; i < sof_bits; i++) {
hitag_send_bit(1);
@ -299,6 +333,25 @@ static int check_select(uint8_t *rx, uint32_t uid) {
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
*/
@ -318,20 +371,28 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
switch (rxlen) {
case 5: {
//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.tstate = HT_NO_OP;
if ((rx[0] & 0xf0) == 0x30) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_STANDARD");
tag.mode = HT_STANDARD;
sof_bits = 1;
m = AC2K;
}
if ((rx[0] & 0xf0) == 0xc0) {
tag.mode = HT_ADVANCED;
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_ADVANCED");
sof_bits = 3;
m = AC2K;
}
if ((rx[0] & 0xf0) == 0xd0) {
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("HT_FAST_ADVANCED");
tag.mode = HT_FAST_ADVANCED;
sof_bits = 3;
m = AC4K;
@ -344,29 +405,18 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
break;
case 45: {
//select command from reader received
if (DBGLEVEL >= DBG_EXTENDED)
DbpString("SELECT");
if (check_select(rx, tag.uid) == 1) {
if (DBGLEVEL >= DBG_EXTENDED)
DbpString("SELECT match");
//if the right tag was selected
*txlen = 32;
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;
}
hitagS_set_frame_modulation();
//send configuration
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;
if (tag.mode != HT_STANDARD) {
*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}",
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
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;
}
hitagS_set_frame_modulation();
for (int i = 0; i < 4; i++)
_hitag2_byte(&state);
@ -438,7 +473,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
}
*/
}
break;
case 40:
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("WRITE");
//data received to be written
if (tag.tstate == HT_WRITING_PAGE_DATA) {
tag.tstate = HT_NO_OP;
@ -448,44 +486,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
*txlen = 2;
tx[0] = 0x40;
page_to_be_written = 0;
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;
}
hitagS_set_frame_modulation();
} else if (tag.tstate == HT_WRITING_BLOCK_DATA) {
tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0]
<< 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3];
//send ack
*txlen = 2;
tx[0] = 0x40;
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;
}
hitagS_set_frame_modulation();
page_to_be_written++;
block_data_left--;
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
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
*txlen = 32;
tx[0] = (tag.pages[page / 4][page % 4]) & 0xff;
tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff;
tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff;
tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff;
tx[0] = tag.pages[page][0];
tx[1] = tag.pages[page][1];
tx[2] = tag.pages[page][2];
tx[3] = tag.pages[page][3];
if (tag.LKP && page == 1)
tx[3] = 0xff;
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;
}
hitagS_set_frame_modulation();
if (tag.mode != HT_STANDARD) {
//add crc8
@ -543,29 +536,13 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
*txlen = 32 * 4;
//send page,...,page+3 data
for (int i = 0; i < 4; i++) {
tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff;
tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff;
tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff;
tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff;
page++;
tx[0 + i * 4] = tag.pages[page + 0 + i * 4][0];
tx[1 + i * 4] = tag.pages[page + 1 + i * 4][1];
tx[2 + i * 4] = tag.pages[page + 2 + i * 4][2];
tx[3 + i * 4] = tag.pages[page + 3 + i * 4][3];
}
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;
}
hitagS_set_frame_modulation();
if (tag.mode != HT_STANDARD) {
//add crc8
@ -576,29 +553,12 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
tx[16] = crc;
}
if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) {
if ((page) % 4 != 0 || (tag.LKP && (page) == 0)) {
sof_bits = 0;
*txlen = 0;
}
} else if ((rx[0] & 0xf0) == 0x80) { //write page
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)
|| (tag.LKP && (page == 2 || page == 3))) {
//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
uint8_t page = ((rx[0] & 0x0f) * 6) + ((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;
}
hitagS_set_frame_modulation();
if (page % 4 != 0 || page == 0) {
//deny
*txlen = 0;
@ -644,7 +589,8 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
}
break;
default:
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]);
break;
}
}
@ -722,7 +668,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
| (uid[30] << 1)
| uid[31];
if (DEBUG)
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4);
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.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]);
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[6] = auth_ks[2];
tx[7] = auth_ks[3];
if (DEBUG)
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0],
tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]);
} else if (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[2] & 0x0f) * 16 + ((rx[3] & 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("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);
}
if (DEBUG)
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1);
//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.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
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...");
memcpy((uint8_t *)tag.pages, data, 4 * 64);
} else {
// use the last read tag
}
tag.uid = (uint32_t)tag.pages[0];
tag.key = (intptr_t)tag.pages[3];
tag.uid = ((tag.pages[0][3]) << 24) | ((tag.pages[0][2]) << 16) | ((tag.pages[0][1]) << 8) | tag.pages[0][0];
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 += ((tag.pages[2][0]) << 8) + tag.pages[2][1];
tag.pwdl0 = tag.pages[2][3];
tag.pwdl1 = tag.pages[2][2];
tag.pwdh0 = tag.pages[1][0];
tag.key += ((tag.pages[2][3]) << 8) + tag.pages[2][2];
tag.pwdl0 = tag.pages[2][0];
tag.pwdl1 = tag.pages[2][1];
tag.pwdh0 = tag.pages[1][3];
//con0
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;
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;
if (DBGLEVEL >= DBG_EXTENDED)
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);
//con1
tag.auth = 0;
if ((tag.pages[1][2] & 0x80) == 0x80)
if ((tag.pages[1][1] & 0x80) == 0x80)
tag.auth = 1;
tag.LCON = 0;
if ((tag.pages[1][2] & 0x2) == 0x02)
if ((tag.pages[1][1] & 0x2) == 0x02)
tag.LCON = 1;
tag.LKP = 0;
if ((tag.pages[1][2] & 0x1) == 0x01)
if ((tag.pages[1][1] & 0x1) == 0x01)
tag.LKP = 1;
//con2
//0=read write 1=read only
tag.LCK7 = 0;
if ((tag.pages[1][1] & 0x80) == 0x80)
if ((tag.pages[1][2] & 0x80) == 0x80)
tag.LCK7 = 1;
tag.LCK6 = 0;
if ((tag.pages[1][1] & 0x40) == 0x040)
if ((tag.pages[1][2] & 0x40) == 0x040)
tag.LCK6 = 1;
tag.LCK5 = 0;
if ((tag.pages[1][1] & 0x20) == 0x20)
if ((tag.pages[1][2] & 0x20) == 0x20)
tag.LCK5 = 1;
tag.LCK4 = 0;
if ((tag.pages[1][1] & 0x10) == 0x10)
if ((tag.pages[1][2] & 0x10) == 0x10)
tag.LCK4 = 1;
tag.LCK3 = 0;
if ((tag.pages[1][1] & 0x8) == 0x08)
if ((tag.pages[1][2] & 0x8) == 0x08)
tag.LCK3 = 1;
tag.LCK2 = 0;
if ((tag.pages[1][1] & 0x4) == 0x04)
if ((tag.pages[1][2] & 0x4) == 0x04)
tag.LCK2 = 1;
tag.LCK1 = 0;
if ((tag.pages[1][1] & 0x2) == 0x02)
if ((tag.pages[1][2] & 0x2) == 0x02)
tag.LCK1 = 1;
tag.LCK0 = 0;
if ((tag.pages[1][1] & 0x1) == 0x01)
if ((tag.pages[1][2] & 0x1) == 0x01)
tag.LCK0 = 1;
// Set up simulator mode, frequency divisor which will drive the FPGA
// and analog mux selection.
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,
// external trigger rising edge, load RA on rising edge of TIOA.
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
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);
}
// 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
memset(rx, 0x00, sizeof(rx));
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();
}
// Reset the frame length
@ -1114,22 +1064,92 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
overflow += (AT91C_BASE_TC1->TC_CV / T0);
// Reset the timer to restart while-loop that receives frames
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
}
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
lf_finalize();
// release allocated memory from BigBuff.
BigBuf_free();
StartTicks();
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.
* 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;
size_t txlen = 0;
int lastbit = 1;
int reset_sof = 1;
int t_wait = HITAG_T_WAIT_MAX;
bool bStop = false;
int pageNum = 0;
@ -1164,6 +1183,9 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
uint64_t NrAr = 0;
uint8_t key_[6];
tag.pstate = HT_READY;
tag.tstate = HT_NO_OP;
switch (htf) {
case RHTSF_CHALLENGE: {
DbpString("Authenticating using nr,ar pair:");
@ -1238,10 +1260,8 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
// Reset the received frame, frame count and timing info
t_wait = 200;
while (!bStop && !BUTTON_PRESS() && !data_available()) {
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);
}
// Reset values for receiving frames
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;
}
}
hitagS_receive_frame(rx, &rxlen, &response);
}
end = false;
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
StartTicks();
lf_finalize();
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;
size_t txlen = 0;
int lastbit;
int reset_sof;
int t_wait = HITAG_T_WAIT_MAX;
bool bStop;
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;
// 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.
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
| 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
lastbit = 1;
bStop = false;
reset_sof = 1;
t_wait = 200;
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);
}
// Reset values for receiving frames
memset(rx, 0x00, sizeof(rx));
rxlen = 0;
lastbit = 1;
bool bSkip = true;
int tag_sof = reset_sof;
response = 0;
uint32_t errorCount = 0;
hitagS_receive_frame(rx, &rxlen, &response);
// 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;
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
StartTicks();
lf_finalize();
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;
uint8_t txbuf[HITAG_FRAME_LEN];
int t_wait = HITAG_T_WAIT_MAX;
int lastbit, reset_sof, STATE = 0;;
int lastbit, STATE = 0;;
bool bStop;
int response_bit[200];
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
lastbit = 1;
bStop = false;
reset_sof = 1;
t_wait = 200;
if (file_given) {
@ -1952,11 +1823,11 @@ void check_challenges(bool file_given, uint8_t *data) {
u1++;
} else if (STATE == 2 && rxlen >= 44) {
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
STATE = 0;
}
@ -1984,85 +1855,10 @@ void check_challenges(bool file_given, uint8_t *data) {
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
}
// Reset values for receiving frames
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;
}
}
hitagS_receive_frame(rx, &rxlen, &response);
}
LEDsoff();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
set_tracing(false);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
StartTicks();
lf_finalize();
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
}

View file

@ -709,7 +709,7 @@ void SmartCardAtr(void) {
set_tracing(true);
I2C_Reset_EnterMainProgram();
bool isOK = GetATR(&card);
reply_old(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
set_tracing(false);
LEDsoff();
}
@ -760,7 +760,7 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
}
}
OUT:
reply_old(CMD_ACK, len, 0, 0, resp, len);
reply_mix(CMD_ACK, len, 0, 0, resp, len);
BigBuf_free();
set_tracing(false);
LEDsoff();

View file

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

View file

@ -93,8 +93,6 @@
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
#define sprintUID(target,uid) Iso15693sprintUID((target), (uid))
static void BuildIdentifyRequest(uint8_t *cmdout);
//static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber );
static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid);
@ -946,7 +944,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
WDT_HIT();
if (recvlen >= 12) {
Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2));
Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, buf + 2));
}
// now with AFI
@ -964,7 +962,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
recvlen = SendDataTag(data, datalen, false, speed, buf);
WDT_HIT();
if (recvlen >= 12) {
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2));
Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, buf + 2));
}
aborted = BUTTON_PRESS();

View file

@ -404,6 +404,10 @@ bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) {
//
// Only this functions are public / called from appmain.c
//-----------------------------------------------------------------------------
legic_card_select_t* getLegicCardInfo(void) {
return &card;
}
void LegicRfInfo(void) {
// configure ARM and FPGA
init_reader(false);
@ -441,6 +445,44 @@ OUT:
StopTicks();
}
int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv) {
int res = PM3_SUCCESS;
// configure ARM and FPGA
init_reader(false);
// establish shared secret and detect card type
uint8_t card_type = setup_phase(iv);
if (init_card(card_type, &card) != 0) {
res = PM3_ESOFT;
goto OUT;
}
// do not read beyond card memory
if (len + offset > card.cardsize) {
len = card.cardsize - offset;
}
for (uint16_t i = 0; i < len; ++i) {
int16_t byte = read_byte(offset + i, card.cmdsize);
if (byte == -1) {
res = PM3_EOVFLOW;
goto OUT;
}
legic_mem[i] = byte;
if (i < 4) {
card.uid[i] = byte;
}
}
OUT:
switch_off();
StopTicks();
return res;
}
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
// configure ARM and FPGA
init_reader(false);
@ -464,6 +506,10 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
goto OUT;
}
legic_mem[i] = byte;
if (i < 4) {
card.uid[i] = byte;
}
}
// OK

View file

@ -1,6 +1,7 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2018 AntiCat
// 2020 iceman
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -13,9 +14,12 @@
#define __LEGICRF_H
#include "common.h"
#include "legic.h" /* legic_card_select_t struct */
void LegicRfInfo(void);
int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv);
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv);
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data);
legic_card_select_t* getLegicCardInfo(void);
#endif /* __LEGICRF_H */

View file

@ -460,12 +460,12 @@ void LegicRfSimulate(uint8_t cardtype) {
// verify command line input
if (init_card(cardtype, &card) != 0) {
DbpString("Unknown tagtype.");
DbpString("[!] Unknown tagtype.");
goto OUT;
}
LED_A_ON();
DbpString("Starting Legic emulator, press button to end");
DbpString("[=] Starting Legic emulator, press " _YELLOW_("button") "to end");
while (!BUTTON_PRESS() && !data_available()) {
WDT_HIT();
@ -486,7 +486,7 @@ void LegicRfSimulate(uint8_t cardtype) {
}
OUT:
DbpString("Stopped");
DbpString("[=] Sim stopped");
switch_off();
StopTicks();
}

View file

@ -10,6 +10,7 @@
#include "lfsampling.h"
#include "fpgaloader.h"
#include "ticks.h"
#include "dbprint.h"
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
@ -46,27 +47,43 @@ bool lf_test_periods(size_t expected, size_t count) {
// Low frequency (LF) adc passthrough functionality
//////////////////////////////////////////////////////////////////////////////
uint8_t previous_adc_val = 0;
uint8_t adc_avg = 0;
void lf_sample_mean(void) {
uint8_t periods = 0;
uint32_t adc_sum = 0;
while (periods < 32) {
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
adc_sum += AT91C_BASE_SSC->SSC_RHR;
periods++;
}
}
// division by 32
adc_avg = adc_sum >> 5;
if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("LF ADC average %u", adc_avg);
}
size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
size_t periods = 0;
volatile uint8_t adc_val;
//uint8_t avg_peak = 140, avg_through = 96;
// 140 - 127 - 114
uint8_t avg_peak = 140, avg_through = 106;
int16_t checked = 0;
uint8_t avg_peak = adc_avg + 3, avg_through = adc_avg - 3;
// int16_t checked = 0;
while (!BUTTON_PRESS()) {
// only every 100th times, in order to save time when collecting samples.
if (checked == 1000) {
if (data_available()) {
break;
} else {
checked = 0;
}
}
++checked;
/*
if (checked == 1000) {
if (data_available()) {
break;
} else {
checked = 0;
}
}
++checked;
*/
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
@ -98,8 +115,8 @@ size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
}
}
}
previous_adc_val = adc_val;
if (periods >= max) return 0;
}
}
@ -116,23 +133,26 @@ size_t lf_detect_gap(size_t max) {
}
void lf_reset_counter() {
// TODO: find out the correct reset settings for tag and reader mode
if (reader_mode) {
// Reset values for reader mode
rising_edge = false;
previous_adc_val = 0xFF;
} else {
// Reset values for tag/transponder mode
rising_edge = false;
previous_adc_val = 0xFF;
}
// if (reader_mode) {
// Reset values for reader mode
rising_edge = false;
previous_adc_val = 0xFF;
// } else {
// Reset values for tag/transponder mode
// rising_edge = false;
// previous_adc_val = 0xFF;
// }
}
bool lf_get_tag_modulation() {
return (rising_edge == false);
}
bool lf_get_reader_modulation() {
return rising_edge;
return rising_edge;
}
void lf_wait_periods(size_t periods) {
@ -147,7 +167,11 @@ void lf_init(bool reader, bool simulate) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
sample_config *sc = getSamplingConfig();
sc->decimation = 1;
sc->averaging = 0;
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
if (reader) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
} else {
@ -155,7 +179,8 @@ void lf_init(bool reader, bool simulate) {
// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
else
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
// Sniff
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
}
@ -168,8 +193,8 @@ void lf_init(bool reader, bool simulate) {
// When in reader mode, give the field a bit of time to settle.
// 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered.
if (reader) {
// 50 ms
SpinDelay(50);
// 10 ms
SpinDelay(10);
}
// Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation
@ -195,14 +220,12 @@ void lf_init(bool reader, bool simulate) {
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Prepare data trace
uint32_t bufsize = 20000;
uint32_t bufsize = 10000;
// use malloc
if (logging) initSampleBufferEx(&bufsize, true);
sample_config *sc = getSamplingConfig();
sc->decimation = 1;
sc->averaging = 0;
lf_sample_mean();
}
void lf_finalize() {
@ -218,36 +241,33 @@ void lf_finalize() {
LEDsoff();
sample_config *sc = getSamplingConfig();
sc->decimation = 1;
sc->averaging = 0;
StartTicks();
}
size_t lf_detect_field_drop(size_t max) {
size_t periods = 0;
volatile uint8_t adc_val;
int16_t checked = 0;
// int16_t checked = 0;
while (!BUTTON_PRESS()) {
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
/*
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
*/
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
periods++;
adc_val = AT91C_BASE_SSC->SSC_RHR;
volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
if (logging) logSampleSimple(adc_val);
@ -275,7 +295,7 @@ static void lf_manchester_send_bit(uint8_t bit) {
lf_modulation(bit != 0);
lf_wait_periods(16);
lf_modulation(bit == 0);
lf_wait_periods(16);
lf_wait_periods(32);
}
// simulation

View file

@ -17,6 +17,7 @@
extern bool logging;
void lf_sample_mean(void);
bool lf_test_periods(size_t expected, size_t count);
size_t lf_count_edge_periods(size_t max);
size_t lf_detect_gap(size_t max);

View file

@ -1291,7 +1291,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol)
cardnum = (lo >> 1) & 0x7FFFF;
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,
lo,
(lo >> 1) & 0xFFFF,
@ -2399,13 +2399,13 @@ void SendForward(uint8_t fwd_bit_count) {
TurnReadLF_off(EM_START_GAP);
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
if (((*fwd_write_ptr++) & 1) == 1) {
WaitUS(32 * 8);
} else {
TurnReadLF_off(23 * 8);
TurnReadLFOn(18 * 8);
TurnReadLFOn(32-23 * 8);
}
}
}

View file

@ -81,7 +81,7 @@ void setSamplingConfig(sample_config *sc) {
printConfig();
}
sample_config *getSamplingConfig() {
sample_config *getSamplingConfig(void) {
return &config;
}
@ -117,8 +117,8 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
if (use_malloc) {
if (sample_size == NULL || *sample_size == 0 ) {
*sample_size = BigBuf_max_traceLen();
if (sample_size == NULL || *sample_size == 0) {
*sample_size = BigBuf_max_traceLen();
data.buffer = BigBuf_get_addr();
} else {
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
}
} else {
if (sample_size == NULL || *sample_size == 0 ) {
if (sample_size == NULL || *sample_size == 0) {
*sample_size = BigBuf_max_traceLen();
}
data.buffer = BigBuf_get_addr();
@ -221,7 +221,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 50ms for the resonant antenna to settle.
if (reader_field)
SpinDelay(50);
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
@ -253,11 +253,11 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
uint32_t cancel_counter = 0;
int16_t checked = 0;
while (true) {
while (!BUTTON_PRESS()) {
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (BUTTON_PRESS() || data_available()) {
if (data_available()) {
checked = -1;
break;
} else {

View file

@ -82,22 +82,22 @@ void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain) {
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
break;
};
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (DBGLEVEL >= 1) Dbprintf("Auth error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
break;
};
if (mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
if (DBGLEVEL >= 1) Dbprintf("Read block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read block error");
break;
};
if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
break;
};
@ -243,25 +243,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
isOK = 1;
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = 0;
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
}
if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = 0;
if (DBGLEVEL >= 1) Dbprintf("Auth error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
isOK = 0;
if (DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
break;
}
}
if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
}
if (DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
@ -409,22 +409,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
break;
};
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
if (DBGLEVEL >= 1) Dbprintf("Auth error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
break;
};
if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
break;
};
if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
break;
};
@ -460,18 +460,18 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
};
if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(0);
return; };
if(mifare_ultra_halt()) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
OnError(0);
return;
};
@ -506,7 +506,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
set_tracing(true);
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
};
@ -534,13 +534,13 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
}
if (mifare_ultra_writeblock(blockNo, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(0);
return;
};
if (mifare_ultra_halt()) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
OnError(0);
return;
};
@ -569,7 +569,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
set_tracing(true);
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
};
@ -579,7 +579,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[2] = pwd[5];
blockdata[3] = pwd[4];
if (mifare_ultra_writeblock(44, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(44);
return;
};
@ -589,7 +589,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[2] = pwd[1];
blockdata[3] = pwd[0];
if (mifare_ultra_writeblock(45, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(45);
return;
};
@ -599,7 +599,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[2] = pwd[13];
blockdata[3] = pwd[12];
if (mifare_ultra_writeblock(46, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(46);
return;
};
@ -609,13 +609,13 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
blockdata[2] = pwd[9];
blockdata[3] = pwd[8];
if (mifare_ultra_writeblock(47, blockdata)) {
if (DBGLEVEL >= 1) Dbprintf("Write block error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
OnError(47);
return;
};
if (mifare_ultra_halt()) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
OnError(0);
return;
};
@ -674,7 +674,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue;
}
switch (card_info.uidlen) {
@ -693,7 +693,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
continue;
}
}
@ -792,7 +792,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue;
}
switch (card_info.uidlen) {
@ -811,7 +811,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
continue;
}
}
@ -821,7 +821,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
uint32_t nt1;
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth1 error");
continue;
}
@ -832,7 +832,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
CHK_TIMEOUT();
if (len != 4) {
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
continue;
}
@ -1422,7 +1422,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
goto OUT;
}
@ -1470,7 +1470,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
for (uint16_t i = s_point; i < keyCount; ++i) {
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && data_available()) {
if (BUTTON_PRESS() || data_available()) {
goto OUT;
}
@ -1562,7 +1562,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
for (uint16_t i = 0; i < keyCount; i++) {
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && data_available()) break;
if (BUTTON_PRESS() || data_available()) break;
// found all keys?
if (foundkeys == allkeys)
@ -1731,7 +1731,7 @@ void MifareChkKeys(uint8_t *datain) {
if (!have_uid) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)");
--i; // try same key once again
continue;
}
@ -1751,7 +1751,7 @@ void MifareChkKeys(uint8_t *datain) {
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if (!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {
if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)");
--i; // try same key once again
continue;
}
@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) {
#endif
}
//-----------------------------------------------------------------------------
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
//-----------------------------------------------------------------------------
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
uint16_t isOK = PM3_EUNDEF;
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
LED_A_ON();
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
break;
}
uint8_t block_number = 0;
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
break;
}
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
break;;
}
if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
break;
}
isOK = PM3_SUCCESS;
break;
}
crypto1_deinit(pcs);
LED_B_ON();
reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//-----------------------------------------------------------------------------
// Work with emulator memory
//
@ -2229,7 +2286,7 @@ void MifareHasStaticNonce() {
nt = bytes_to_num(rec, 4);
// CHK_TIMEOUT();
CHK_TIMEOUT();
}
OUT:
@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) {
while (true) {
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
break;
}
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) {
if (DBGLEVEL >= 1) Dbprintf("Auth error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
break;
}
int respLen;
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) {
if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
break;
}
if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= 1) Dbprintf("Halt error");
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
break;
}
@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) {
LED_B_ON();
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card?
void MifareHasStaticNonce(); // Has the tag a static nonce?
void MifareSetMod(uint8_t *datain);
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
void OnSuccessMagic();
void OnErrorMagic(uint8_t reason);

View file

@ -14,6 +14,8 @@
#include "crc16.h"
#include "mbedtls/aes.h"
#include "commonutil.h"
#include "util.h"
#include "mifare.h"
#define MAX_APPLICATION_COUNT 28
#define MAX_FILE_COUNT 16
@ -31,8 +33,11 @@ static uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4};
/* PCB CID CMD PAYLOAD */
//static uint8_t __res[MAX_FRAME_SIZE];
bool InitDesfireCard() {
pcb_blocknum = 0;
iso14a_card_select_t card;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -46,28 +51,14 @@ bool InitDesfireCard() {
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) {
/* ARG0 contains flags.
0x01 = init card.
0x02 = Disconnect
0x03
*/
uint8_t flags = arg0;
size_t datalen = arg1;
uint8_t resp[RECEIVE_SIZE];
memset(resp, 0, sizeof(resp));
if (DBGLEVEL >= 4) {
if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf(" flags : %02X", flags);
Dbprintf(" len : %02X", datalen);
print_result(" RX : ", datain, datalen);
@ -77,35 +68,42 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
clear_trace();
if (flags & INIT) {
if (!InitDesfireCard())
if (!InitDesfireCard()) {
return;
}
}
int len = DesfireAPDU(datain, datalen, resp);
if (DBGLEVEL >= 4)
print_result("ERR <--: ", resp, len);
if (DBGLEVEL >= DBG_EXTENDED)
print_result("RESP <--: ", resp, len);
if (!len) {
OnError(2);
return;
}
// reset the pcb_blocknum,
pcb_blocknum = 0;
if (flags & DISCONNECT)
OnSuccess();
reply_old(CMD_ACK, 1, len, 0, resp, len);
reply_mix(CMD_ACK, 1, len, 0, resp, len);
}
void MifareDesfireGetInformation() {
LEDsoff();
int len = 0;
iso14a_card_select_t card;
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
2 = cid 2
@ -122,61 +120,65 @@ void MifareDesfireGetInformation() {
// card select - information
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
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;
}
if (card.uidlen != 7) {
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;
}
memcpy(dataout, card.uid, 7);
// add uid.
memcpy(payload.uid, card.uid, sizeof(payload.uid));
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
uint8_t cmd[] = {GET_VERSION};
uint8_t cmd[] = {GET_VERSION, 0x00, 0x00, 0x00};
size_t cmd_len = sizeof(cmd);
len = DesfireAPDU(cmd, cmd_len, resp);
if (!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;
}
LED_A_OFF();
LED_B_ON();
memcpy(dataout + 7, resp + 3, 7);
memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW));
// ADDITION_FRAME 1
cmd[0] = ADDITIONAL_FRAME;
len = DesfireAPDU(cmd, cmd_len, resp);
if (!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;
}
LED_B_OFF();
LED_C_ON();
memcpy(dataout + 7 + 7, resp + 3, 7);
memcpy(payload.versionSW, resp + 1, sizeof(payload.versionSW));
// ADDITION_FRAME 2
len = DesfireAPDU(cmd, cmd_len, resp);
if (!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;
}
memcpy(dataout + 7 + 7 + 7, resp + 3, 14);
reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout));
memcpy(payload.details, resp + 1, sizeof(payload.details));
LED_B_ON();
reply_ng(CMD_HF_DESFIRE_INFO, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
LED_B_OFF();
// reset the pcb_blocknum,
pcb_blocknum = 0;
OnSuccess();
@ -467,7 +469,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// dekryptera tagnonce.
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
if (DBGLEVEL >= 4) {
if (DBGLEVEL >= DBG_EXTENDED) {
DbpString("mbedtls_aes_setkey_dec failed");
}
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);
uint8_t encBoth[32] = {0x00};
if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) {
if (DBGLEVEL >= 4) {
if (DBGLEVEL >= DBG_EXTENDED) {
DbpString("mbedtls_aes_setkey_enc failed");
}
OnError(7);
@ -517,7 +519,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
}
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)
@ -534,23 +536,23 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) {
wrappedLen = CreateAPDU(cmd, cmd_len, wCmd);
if (DBGLEVEL >= 4)
if (DBGLEVEL >= DBG_EXTENDED)
print_result("WCMD <--: ", wCmd, wrappedLen);
ReaderTransmit(wCmd, wrappedLen, NULL);
len = ReaderReceive(resp, par);
if (!len) {
if (DBGLEVEL >= 4) Dbprintf("fukked");
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("fukked");
return false; //DATA LINK ERROR
}
// if we received an I- or R(ACK)-Block with a block number equal to the
// 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] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
&& (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers
pcb_blocknum ^= 1; //toggle next block
pcb_blocknum ^= 1; //toggle next block
}
memcpy(dataout, resp, len);
@ -565,15 +567,22 @@ size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
uint8_t cmd[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[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);
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);
return cmdlen;
}

View file

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

View file

@ -8,7 +8,7 @@
// Routines to support mifare classic sniffer.
//-----------------------------------------------------------------------------
#include "mifaresniff.h"
#include "mifaresniff_disabled.h"
#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))

View file

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

View file

@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \
bucketsort.c \
flash.c \
wiegand_formats.c \
wiegand_formatutils.c
wiegand_formatutils.c \
cardhelper.c
cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), )

View file

@ -10,22 +10,22 @@
// Data and Graph commands
//-----------------------------------------------------------------------------
#include "cmddata.h"
#include <stdio.h>
#include <string.h>
#include <limits.h> // for CmdNorm INT_MIN && INT_MAX
#include <math.h> // pow
#include <ctype.h> // tolower
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // for command_t
#include "ui.h" // for show graph controls
#include "graph.h" // for graph data
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // for command_t
#include "ui.h" // for show graph controls
#include "graph.h" // for graph data
#include "comms.h"
#include "lfdemod.h" // for demod code
#include "lfdemod.h" // for demod code
#include "loclass/cipherutils.h" // for decimating samples in getsamples
#include "cmdlfem4x.h" // askem410xdecode
#include "fileutils.h" // searchFile
#include "cmdlfem4x.h" // askem410xdecode
#include "fileutils.h" // searchFile
#include "mifare/ndef.h"
#include "cliparser/cliparser.h"
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
size_t DemodBufferLen = 0;
@ -1662,16 +1662,15 @@ int CmdTuneSamples(const char *Cmd) {
#define LF_MARGINAL_V 10000
#define HF_UNUSABLE_V 3000
#define HF_MARGINAL_V 5000
#define ANTENNA_ERROR 1.03 // current algo has 3% error margin.
#define ANTENNA_ERROR 1.00 // current algo has 3% error margin.
// hide demod plot line
DemodBufferLen = 0;
setClockGrid(0, 0);
RepaintGraphWindow();
int timeout = 0;
PrintAndLogEx(INFO, "\nMeasuring antenna characteristics, please wait...");
PrintAndLogEx(INFO, "Measuring antenna characteristics, please wait...");
clearCommandBuffer();
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0);
@ -1691,7 +1690,7 @@ int CmdTuneSamples(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "\n");
PrintAndLogEx(NORMAL, "");
// in mVolt
struct p {
uint32_t v_lf134;
@ -2290,6 +2289,34 @@ static int CmdDataIIR(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdDataNDEF(const char *Cmd) {
#ifndef MAX_NDEF_LEN
#define MAX_NDEF_LEN 2048
#endif
CLIParserInit("data ndef",
"Prints NFC Data Exchange Format (NDEF)",
"Usage:\n\tdata ndef -d 9101085402656e48656c6c6f5101085402656e576f726c64\n");
void *argtable[] = {
arg_param_begin,
arg_strx0("dD", "data", "<hex>", "NDEF data to decode"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
int datalen = 0;
uint8_t data[MAX_NDEF_LEN] = {0};
CLIGetHexWithReturn(1, data, &datalen);
CLIParserFree();
if (datalen == 0)
return PM3_EINVARG;
PrintAndLogEx(INFO, "Parsed NDEF Records");
return NDEFRecordsDecodeAndPrint(data, datalen);
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"},
@ -2328,6 +2355,7 @@ static command_t CommandTable[] = {
{"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"},
{"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
{"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"},
{NULL, NULL, NULL, NULL}
};

View file

@ -18,48 +18,6 @@
static int CmdHelp(const char *Cmd);
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_remove(void) {
PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem");
PrintAndLogEx(NORMAL, " Usage: mem spiffs remove <filename>");
@ -107,16 +65,64 @@ static int usage_flashmemspiffs_load(void) {
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_remove();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_remove();
}
char filename[32] = {0};
bool errors = false;
/*char ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || ctmp == 'h') {
return usage_flashmemspiffs_remove();
}*/
if (param_getstr(Cmd, 0, filename, 32) >= 32) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
@ -134,15 +140,20 @@ static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
static int CmdFlashMemSpiFFSRename(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_rename();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_rename();
}
char srcfilename[32] = {0};
char destfilename[32] = {0};
bool errors = false;
/*char ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || ctmp == 'h') {
return usage_flashmemspiffs_rename();
}*/
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
@ -174,16 +185,21 @@ static int CmdFlashMemSpiFFSRename(const char *Cmd) {
}
static int CmdFlashMemSpiFFSCopy(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_copy();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_copy();
}
char srcfilename[32] = {0};
char destfilename[32] = {0};
bool errors = false;
/*char ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || ctmp == 'h') {
return usage_flashmemspiffs_copy();
}*/
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
@ -315,7 +331,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
}
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
int ret_val = PM3_SUCCESS;
// We want to mount before multiple operation so the lazy writes/append will not
@ -349,7 +365,7 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
bytes_sent += bytes_in_packet;
PacketResponseNG resp;
uint8_t retry = 3;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
@ -377,7 +393,7 @@ out:
// We want to unmount after these to set things back to normal but more than this
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return ret_val;
}
@ -400,8 +416,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
cmdp += 2;
break;
case 'o':
param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32);
if (strlen((char*)destfilename) == 0) {
param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32);
if (strlen((char *)destfilename) == 0) {
PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
errors = true;
}
@ -429,20 +445,19 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
}
res = flashmem_spiffs_load(destfilename, data, datalen);
free(data);
if ( res == PM3_SUCCESS )
if (res == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
return res;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{
"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash,
{"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash,
"Copy a file to another (destructively) in SPIFFS FileSystem in FlashMEM (spiffs)"
},
{"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented Filesystem"},

View file

@ -85,12 +85,14 @@ int CmdHFSearch(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_hf_search();
int res = PM3_ESOFT;
PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
if (IfPm3NfcBarcode()) {
if (infoThinFilm(false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Thinfilm tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -99,7 +101,7 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Iso14443a()) {
if (infoLTO(false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LTO-CM tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -108,7 +110,7 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Iso14443a()) {
if (infoHF14A(false, false, false) > 0) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -117,7 +119,7 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Iso15693()) {
if (readHF15Uid(false)) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -126,16 +128,16 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Legicrf()) {
if (readLegicUid(false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for Topaz tag...");
if (IfPm3Iso14443a()) {
if (readTopazUid() == PM3_SUCCESS) {
if (readTopazUid(false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -144,7 +146,7 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Felica()) {
if (readFelicaUid(false) == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -154,7 +156,7 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Iso14443a()) {
if (readHF14B(false) == 1) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
@ -163,14 +165,18 @@ int CmdHFSearch(const char *Cmd) {
if (IfPm3Iclass()) {
if (readIclass(false, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") "found\n");
return PM3_SUCCESS;
res = PM3_SUCCESS;
}
}
PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found"));
PrintAndLogEx(NORMAL, "");
return PM3_ESOFT;
if (res != PM3_SUCCESS) {
PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found"));
res = PM3_ESOFT;
}
printf("\n");
return res;
}
int CmdHFTune(const char *Cmd) {
@ -178,39 +184,47 @@ int CmdHFTune(const char *Cmd) {
if (cmdp == 'h') return usage_hf_tune();
int iter = param_get32ex(Cmd, 0, 0, 10);
PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit");
PacketResponseNG resp;
PrintAndLogEx(SUCCESS, "Measuring HF antenna," _YELLOW_("click button") " or press" _YELLOW_("Enter") "to exit");
clearCommandBuffer();
uint8_t mode[] = {1};
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF initialization, aborting");
return PM3_ETIMEOUT;
}
mode[0] = 2;
// loop forever (till button pressed) if iter = 0 (default)
for (uint8_t i = 0; iter == 0 || i < iter; i++) {
if (kbd_enter_pressed()) { // abort by keyboard press
if (kbd_enter_pressed()) {
break;
}
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting");
return PM3_ETIMEOUT;
}
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t)))
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) {
break;
}
uint16_t volt = resp.data.asDwords[0] & 0xFFFF;
PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint16_t)(volt / 1000));
PrintAndLogEx(INPLACE, "%u mV / %2u V", volt, (uint16_t)(volt / 1000));
}
mode[0] = 3;
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting");
return PM3_ETIMEOUT;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Done.");
PrintAndLogEx(INFO, "Done.");
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, " v : (Optional) Verbose");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x");
PrintAndLogEx(NORMAL, " 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 11223344 x"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n");
return 0;
}
@ -202,7 +202,7 @@ static int usage_hf_14a_sniff(void) {
PrintAndLogEx(NORMAL, "c - triggered by first data from card");
PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf 14a sniff c r");
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r"));
return 0;
}
static int usage_hf_14a_raw(void) {
@ -230,7 +230,6 @@ static int usage_hf_14a_reader(void) {
static int CmdHF14AList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead");
CmdTraceList("14a");
return 0;
}
@ -261,7 +260,7 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
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, " 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
@ -335,17 +334,17 @@ static int CmdHF14AReader(const char *Cmd) {
if (select_status == 3) {
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();
return 1;
}
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
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]);
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) {
@ -354,14 +353,14 @@ static int CmdHF14AReader(const char *Cmd) {
}
if (disconnectAfter) {
if (!silent) PrintAndLogEx(SUCCESS, "field dropped.");
if (!silent) PrintAndLogEx(INFO, "field dropped.");
}
return 0;
}
static int CmdHF14AInfo(const char *Cmd) {
bool verbose = false;
bool verbose = true;
bool do_nack_test = false;
bool do_aid_search = false;
@ -467,7 +466,7 @@ int CmdHF14ASim(const char *Cmd) {
break;
}
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;
}
cmdp += 2;
@ -485,7 +484,7 @@ int CmdHF14ASim(const char *Cmd) {
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true;
break;
}
@ -511,7 +510,7 @@ int CmdHF14ASim(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation");
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
bool keypress = kbd_enter_pressed();
while (!keypress) {
@ -558,6 +557,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
if (activateField) {
PacketResponseNG resp;
responseNum = 0;
// Anticollision + SELECT card
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
@ -1276,16 +1276,24 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (select_status == 3) {
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();
return select_status;
}
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
if (verbose) {
PrintAndLogEx(SUCCESS, "-- ISO14443-a Information -----------------------------------");
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 isMifareDesfire = false;
bool isMifarePlus = false;
bool isMifareUltralight = false;
switch (card.sak) {
case 0x00:
isMifareClassic = false;
@ -1294,10 +1302,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
DropField();
uint32_t tagT = GetHF14AMfU_Type();
if (tagT != UL_ERROR)
if (tagT != UL_ERROR) {
ul_print_type(tagT, 0);
else
isMifareUltralight = true;
} else {
PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)");
}
// reconnect for further tests
clearCommandBuffer();
@ -1314,49 +1324,55 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
}
break;
case 0x01:
PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP TNP3xxx Activision Game Appliance"));
break;
case 0x04:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE (various !DESFire !DESFire EV1)"));
isMifareClassic = false;
isMifareDesfire = true;
break;
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;
case 0x09:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Mini 0.3k"));
break;
case 0x0A:
PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("FM11RF005SH (Shanghai Metro)"));
break;
case 0x10:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 2k SL2"));
isMifarePlus = true;
break;
case 0x11:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 4k SL2"));
isMifarePlus = true;
break;
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;
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;
isMifareDesfire = true;
isMifarePlus = true;
break;
case 0x24:
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire | DESFire EV1"));
isMifareClassic = false;
isMifareDesfire = true;
break;
case 0x28:
PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("JCOP31 or JCOP41 v2.3.1"));
break;
case 0x38:
PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Nokia 6212 or 6131 MIFARE CLASSIC 4K"));
break;
case 0x88:
PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Infineon MIFARE CLASSIC 1K"));
break;
case 0x98:
PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS");
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Gemplus MPCOS"));
break;
default:
;
@ -1364,7 +1380,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
// Double & triple sized UID, can be mapped to a manufacturer.
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
@ -1385,7 +1401,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (select_status == 2) {
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]);
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);
@ -1461,9 +1477,15 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
switch (card.ats[pos + 2] & 0xf0) {
case 0x10:
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
isMifareDesfire = true;
isMifareClassic = false;
isMifarePlus = false;
break;
case 0x20:
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
isMifarePlus = true;
isMifareDesfire = false;
isMifareClassic = false;
break;
}
switch (card.ats[pos + 2] & 0x0f) {
@ -1590,22 +1612,32 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (isMifareClassic) {
int res = detect_classic_prng();
if (res == 1)
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("WEAK"));
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak"));
else if (res == 0)
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("HARD"));
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
else
PrintAndLogEx(FAILED, "prng detection: " _RED_("Fail"));
PrintAndLogEx(FAILED, "prng detection: " _RED_("fail"));
if (do_nack_test)
detect_classic_nackbug(!verbose);
detect_classic_nackbug(false);
res = detect_classic_static_nonce();
if (res == 1)
PrintAndLogEx(SUCCESS, "Static nonce detected");
PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes") );
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;
}

View file

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

View file

@ -23,16 +23,13 @@
// the client. Signal Processing & decoding is done on the pc. This is the slowest
// variant, but offers the possibility to analyze the waveforms directly.
#include "cmdhf15.h"
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN
#include "comms.h" // clearCommandBuffer
#include "cmdtrace.h"
#include "iso15693tools.h"
#include "crypto/libpcrypto.h"
#include "graph.h"
#include "crc16.h" // iso15 crc
#include "cmddata.h" // getsamples
@ -53,9 +50,11 @@
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
#endif
#ifndef sprintUID
# define sprintUID(target, uid) Iso15693sprintUID((target), (uid))
#endif
typedef struct {
uint8_t lock;
uint8_t block[4];
} t15memory_t;
// structure and database for uid -> tagtype lookups
typedef struct {
uint64_t uid;
@ -63,6 +62,7 @@ typedef struct {
const char *desc;
} productName;
const productName uidmapping[] = {
// UID, #significant Bits, "Vendor(+Product)"
@ -208,18 +208,90 @@ const productName uidmapping[] = {
{ 0, 0, "no tag-info available" } // must be the last entry
};
uint8_t nxp_public_keys[][33] = {
// ICODE SLIX2 / DNA
{
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
},
};
static int CmdHF15Help(const char *Cmd);
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
#define PUBLIC_ECDA_KEYLEN 33
const ecdsa_publickey_t nxp_15693_public_keys[] = {
{"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
{"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
{"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
};
/*
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
// ICODE SLIX2 / DNA
{
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
},
// unknown. Needs identification
{
0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
},
// unknown. Needs identification
{
0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
},
// manufacturer public key
{
0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
},
// MIKRON public key.
{
0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
}
};
*/
uint8_t i;
int res;
bool is_valid = false;
for (i = 0; i< ARRAYLEN(nxp_15693_public_keys); i++) {
int dl = 0;
uint8_t key[PUBLIC_ECDA_KEYLEN];
param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false);
is_valid = (res == 0);
if (is_valid)
break;
}
PrintAndLogEx(NORMAL, "");
if (is_valid == false) {
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc);
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value);
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 32));
PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
return PM3_SUCCESS;
}
// fast method to just read the UID of a tag (collision detection not supported)
// *buf should be large enough to fit the 64bit uid
// returns 1 if succeeded
@ -399,7 +471,7 @@ static int usage_15_restore(void) {
{"-2", "use slower '1 out of 256' mode"},
{"-o", "set OPTION Flag (needed for TI)"},
{"r <NUM>", "numbers of retries on error, default is 3"},
{"u <UID>", "load hf-15-dump-<UID>.bin"},
{"u <UID>", "load hf-15-<UID>-dump.bin"},
{"f <filename>", "load <filename>"},
{"b <block size>", "block size, default is 4"}
};
@ -517,7 +589,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
return false;
}
memcpy(&req[tmpreqlen], uid, sizeof(uid));
PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, "Detected UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
tmpreqlen += sizeof(uid);
break;
default:
@ -530,7 +602,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
uid[7 - i] = temp & 0xff;
}
PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, "Using UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
memcpy(&req[tmpreqlen], uid, sizeof(uid));
tmpreqlen += sizeof(uid);
break;
@ -796,16 +868,8 @@ static int NxpSysInfo(uint8_t *uid) {
uint8_t signature[32] = {0x00};
memcpy(signature, recv + 1, 32);
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false);
bool is_valid = (res == 0);
nxp_15693_print_signature(uid, signature);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Tag Signature");
PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA");
PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33));
PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1");
PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32));
PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
}
}
@ -818,8 +882,8 @@ static int NxpSysInfo(uint8_t *uid) {
*/
static int CmdHF15Info(const char *Cmd) {
char cmdp = param_getchar(Cmd, 0);
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_info();
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_info();
PacketResponseNG resp;
uint8_t *recv;
@ -838,11 +902,8 @@ static int CmdHF15Info(const char *Cmd) {
AddCrc15(req, reqlen);
reqlen += 2;
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "iso15693 card select failed");
DropField();
@ -866,11 +927,12 @@ static int CmdHF15Info(const char *Cmd) {
}
memcpy(uid, recv + 2, sizeof(uid));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2));
PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2));
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(recv + 2));
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(recv, status - 2));
// DSFID
if (recv[1] & 0x01)
@ -901,12 +963,12 @@ static int CmdHF15Info(const char *Cmd) {
}
// Check if SLIX2 and attempt to get NXP System Information
PrintAndLogEx(DEBUG, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", recv[4], recv[7], recv[8]);
if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) {
return NxpSysInfo(uid);
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
@ -941,7 +1003,7 @@ static int CmdHF15Sim(const char *Cmd) {
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)));
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8);
@ -1011,7 +1073,7 @@ static int CmdHF15WriteAfi(const char *Cmd) {
AddCrc15(req, reqlen);
reqlen += 2;
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
// PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
@ -1070,7 +1132,7 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
AddCrc15(req, reqlen);
reqlen += 2;
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
// PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
clearCommandBuffer();
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
@ -1096,11 +1158,6 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
return PM3_SUCCESS;
}
typedef struct {
uint8_t lock;
uint8_t block[4];
} t15memory;
// Reads all memory pages
// need to write to file
static int CmdHF15Dump(const char *Cmd) {
@ -1144,13 +1201,13 @@ static int CmdHF15Dump(const char *Cmd) {
}
// detect blocksize from card :)
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
int blocknum = 0;
uint8_t *recv = NULL;
// memory.
t15memory mem[256];
t15memory_t mem[256];
uint8_t data[256 * 4] = {0};
memset(data, 0, sizeof(data));
@ -1214,14 +1271,14 @@ static int CmdHF15Dump(const char *Cmd) {
PrintAndLogEx(NORMAL, "\n");
size_t datalen = blocknum * 4;
saveFile(filename, ".bin", data, datalen);
saveFileEML(filename, data, datalen, 4);
saveFile(filename, ".bin", data, datalen);
saveFileJSON(filename, jsf15, data, datalen);
return PM3_SUCCESS;
}
static int CmdHF15List(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
//PrintAndLogEx(WARNING, "Deprecated command, use 'hf list 15' instead");
CmdTraceList("15");
return PM3_SUCCESS;
}
@ -1348,7 +1405,7 @@ static int CmdHF15Readmulti(const char *Cmd) {
pagenum = param_get8ex(cmd, 0, 0, 10);
pagecount = param_get8ex(cmd, 1, 0, 10);
//PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount);
// PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount);
// 0 means 1 page,
// 1 means 2 pages, ...
@ -1388,7 +1445,8 @@ static int CmdHF15Readmulti(const char *Cmd) {
return PM3_EWRONGANSVER;
}
int start = 1; // skip status byte
// skip status byte
int start = 1;
int stop = (pagecount + 1) * 5;
int currblock = pagenum;
// print response
@ -1603,7 +1661,7 @@ static int CmdHF15Restore(const char *Cmd) {
case 'u':
param_getstr(Cmd, cmdp + 1, buff, FILE_PATH_SIZE);
cmdp++;
snprintf(filename, sizeof(filename), "hf-15-dump-%s-bin", buff);
snprintf(filename, sizeof(filename), "hf-15-%s-dump.bin", buff);
break;
case 'h':
return usage_15_restore();
@ -1622,6 +1680,7 @@ static int CmdHF15Restore(const char *Cmd) {
}
if ((f = fopen(filename, "rb")) == NULL) {
PrintAndLogEx(WARNING, "Could not find file %s", filename);
return PM3_EFILE;
}
@ -1703,7 +1762,7 @@ static int CmdHF15CSetUID(const char *Cmd) {
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid)));
PrintAndLogEx(SUCCESS, "Input new UID | " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
if (!getUID(oldUid)) {
PrintAndLogEx(FAILED, "Can't get old/current UID.");
@ -1774,31 +1833,33 @@ static int CmdHF15CSetUID(const char *Cmd) {
PrintAndLogEx(FAILED, "Setting UID on tag failed.");
return PM3_ESOFT;
} else {
PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]);
PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]);
PrintAndLogEx(SUCCESS, "Old: %s", iso15693_sprintUID(NULL, oldUid));
PrintAndLogEx(SUCCESS, "New: " _GREEN_("%s"), iso15693_sprintUID(NULL, newUid));
return PM3_SUCCESS;
}
}
static command_t CommandTable[] = {
{"help", CmdHF15Help, AlwaysAvailable, "This help"},
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
{"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"},
{"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"},
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
{"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"},
{"read", CmdHF15Read, IfPm3Iso15693, "Read a block"},
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
{"-----------", CmdHF15Help, IfPm3Iso15693, ""},
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},
{"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO15693 tag"},
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
{"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"},
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
{"read", CmdHF15Read, IfPm3Iso15693, "Read a block"},
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
{"-----------", CmdHF15Help, IfPm3Iso15693, ""},
{"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic Chinese card"},
{NULL, NULL, NULL, NULL}
};
@ -1816,13 +1877,13 @@ int CmdHF15(const char *Cmd) {
// used with 'hf search'
bool readHF15Uid(bool verbose) {
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t uid[8] = {0};
if (!getUID(uid)) {
if (verbose) PrintAndLogEx(WARNING, "No tag found.");
return false;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid));
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(uid));
return true;
}

File diff suppressed because it is too large Load diff

View file

@ -25,8 +25,8 @@ static int CmdHelp(const char *Cmd);
static int usage_legic_calccrc(void) {
PrintAndLogEx(NORMAL, "Calculates the legic crc8/crc16 on the given data.");
PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.");
PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d <data> u <uidcrc> c <8|16>");
PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.\n");
PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d <data> u <uidcrc> c <8|16>\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to calculate crc over");
@ -34,29 +34,29 @@ static int usage_legic_calccrc(void) {
PrintAndLogEx(NORMAL, " c <8|16> : Crc type");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic crc d deadbeef1122");
PrintAndLogEx(NORMAL, " hf legic crc d deadbeef1122 u 9A c 16");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122 u 9A c 16"));
return PM3_SUCCESS;
}
static int usage_legic_rdmem(void) {
PrintAndLogEx(NORMAL, "Read data from a legic tag.");
PrintAndLogEx(NORMAL, "Usage: hf legic rdmem [h] <offset> <length> <IV>");
static int usage_legic_rdbl(void) {
PrintAndLogEx(NORMAL, "Read data from a LEGIC Prime tag\n");
PrintAndLogEx(NORMAL, "Usage: hf legic rdbl [h] [o <offset>] [l <length>] [iv <IV>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <offset> : (hex) offset in data array to start download from");
PrintAndLogEx(NORMAL, " <length> : (hex) number of bytes to read");
PrintAndLogEx(NORMAL, " <IV> : (hex) (optional) Initialization vector to use. Must be odd and 7bits max");
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start download from");
PrintAndLogEx(NORMAL, " l <length> : (hex) number of bytes to read");
PrintAndLogEx(NORMAL, " i <IV> : (hex) (optional) Initialization vector to use. Must be odd and 7bits max");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic rdmem 0 16 - reads from byte[0] 0x16 bytes(system header)");
PrintAndLogEx(NORMAL, " hf legic rdmem 0 4 55 - reads from byte[0] 0x4 bytes with IV 0x55");
PrintAndLogEx(NORMAL, " hf legic rdmem 0 100 55 - reads 0x100 bytes with IV 0x55");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 16 - reads from byte[0] 0x16 bytes(system header)"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 4 iv 55 - reads from byte[0] 0x4 bytes with IV 0x55"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 100 iv 55 - reads 0x100 bytes with IV 0x55"));
return PM3_SUCCESS;
}
static int usage_legic_sim(void) {
PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated");
PrintAndLogEx(NORMAL, "Use ELOAD/ESAVE to upload a dump into emulator memory");
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>");
PrintAndLogEx(NORMAL, "Use " _YELLOW_("`hf legic eload`") "to upload a dump into emulator memory\n");
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " <tagtype> : 0 = MIM22");
@ -64,12 +64,12 @@ static int usage_legic_sim(void) {
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic sim 2");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic sim 2"));
return PM3_SUCCESS;
}
static int usage_legic_write(void) {
PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size");
PrintAndLogEx(NORMAL, "Usage: hf legic write [h] o <offset> d <data (hex symbols)>");
static int usage_legic_wrbl(void) {
PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size\n");
PrintAndLogEx(NORMAL, "Usage: hf legic wrbl [h] [o <offset>] [d <data (hex symbols)>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start writing");
@ -77,94 +77,121 @@ static int usage_legic_write(void) {
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to write ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic write o 10 d 11223344 - Write 0x11223344 starting from offset 0x10");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wrbl o 10 d 11223344 - Write 0x11223344 starting from offset 0x10"));
return PM3_SUCCESS;
}
static int usage_legic_reader(void) {
PrintAndLogEx(NORMAL, "Read UID and type information from a legic tag.");
PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]");
PrintAndLogEx(NORMAL, "Read UID and type information from a LEGIC Prime tag\n");
PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic reader");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic reader"));
return PM3_SUCCESS;
}
static int usage_legic_info(void) {
PrintAndLogEx(NORMAL, "Reads information from a legic prime tag.");
PrintAndLogEx(NORMAL, "Shows systemarea, user areas etc");
PrintAndLogEx(NORMAL, "Usage: hf legic info [h]");
PrintAndLogEx(NORMAL, "Reads information from a LEGIC Prime tag like systemarea, user areas etc\n");
PrintAndLogEx(NORMAL, "Usage: hf legic info [h]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic info");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic info"));
return PM3_SUCCESS;
}
static int usage_legic_dump(void) {
PrintAndLogEx(NORMAL, "Reads all pages from LEGIC Prime MIM22, MIM256, MIM1024");
PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`");
PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024");
PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file");
PrintAndLogEx(NORMAL, "It autodetects card type.\n");
PrintAndLogEx(NORMAL, "Usage: hf legic dump [h] o <filename w/o .bin>");
PrintAndLogEx(NORMAL, "Usage: hf legic dump [h] [x] [f <filename w/o .bin>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " o <filename> : filename w/o '.bin' to dump bytes");
PrintAndLogEx(NORMAL, " f <filename> : filename w/o '.bin' to dump bytes");
PrintAndLogEx(NORMAL, " x : deobfuscate dump data (xor with MCC)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic dump");
PrintAndLogEx(NORMAL, " hf legic dump o myfile");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump -- uses UID as filename"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump f myfile"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump x"));
return PM3_SUCCESS;
}
static int usage_legic_restore(void) {
PrintAndLogEx(NORMAL, "Reads binary file and it autodetects card type and verifies that the file has the same size");
PrintAndLogEx(NORMAL, "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]\n");
PrintAndLogEx(NORMAL, "Usage: hf legic restore [h] i <filename w/o .bin>");
PrintAndLogEx(NORMAL, "Usage: hf legic restore [h] [x] [f <filename w/o .bin>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " i <filename> : filename w/o '.bin' to restore bytes on to card from");
PrintAndLogEx(NORMAL, " f <filename> : filename w/o '.bin' to restore bytes on to card from");
PrintAndLogEx(NORMAL, " x : obfuscate dump data (xor with MCC)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic restore i myfile");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic restore f myfile"));
return PM3_SUCCESS;
}
static int usage_legic_eload(void) {
PrintAndLogEx(NORMAL, "It loads binary dump from the file `filename.bin`");
PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] <file name w/o `.bin`>");
PrintAndLogEx(NORMAL, "It loads a binary dump into emulator memory\n");
PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] [f <file name w/o `.bin`>]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, " <filename> : filename w/o .bin to load");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, " f <filename> : filename w/o .bin to load");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic eload 2 myfile");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic eload 2 myfile"));
return PM3_SUCCESS;
}
static int usage_legic_esave(void) {
PrintAndLogEx(NORMAL, "It saves binary dump into the file `filename.bin` or `cardID.bin`");
PrintAndLogEx(NORMAL, " Usage: hf legic esave [h] [card memory] [file name w/o `.bin`]");
PrintAndLogEx(NORMAL, "It saves bin/eml/json dump file of emulator memory\n");
PrintAndLogEx(NORMAL, "Usage: hf legic esave [h] [card memory] f <file name w/o `.bin`>\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, " <filename> : filename w/o .bin to load");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
PrintAndLogEx(NORMAL, " f <filename> : filename w/o .bin to load");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic esave 2 myfile");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 -- uses UID as filename"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 f myfile"));
return PM3_SUCCESS;
}
static int usage_legic_wipe(void) {
PrintAndLogEx(NORMAL, "Fills a legic tag memory with zeros. From byte7 and to the end.");
PrintAndLogEx(NORMAL, " Usage: hf legic wipe [h]");
PrintAndLogEx(NORMAL, "Fills a LEGIC Prime tags memory with zeros. From byte7 and to the end");
PrintAndLogEx(NORMAL, "It autodetects card type\n");
PrintAndLogEx(NORMAL, "Usage: hf legic wipe [h]\n");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf legic wipe");
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wipe"));
return PM3_SUCCESS;
}
static bool legic_xor(uint8_t *data, uint16_t cardsize) {
if (cardsize <= 22) {
PrintAndLogEx(INFO, "No obsfuscation such small dump");
return false;
}
uint8_t crc = data[4];
uint32_t calc_crc = CRC8Legic(data, 4);
if (crc != calc_crc) {
PrintAndLogEx(INFO, "Crc mismatch, obsfuscation not possible");
return false;
}
for(uint16_t i = 22; i < cardsize; i++) {
data[i] ^= crc;
}
PrintAndLogEx(SUCCESS, "(De)Obsfuscation done");
return true;
}
/*
* Output BigBuf and deobfuscate LEGIC RF tag data.
* This is based on information given in the talk held
@ -495,14 +522,35 @@ out:
// params:
// offset in data memory
// number of bytes to read
static int CmdLegicRdmem(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_legic_rdmem();
static int CmdLegicRdbl(const char *Cmd) {
uint32_t offset = 0, len = 0, iv = 1;
uint16_t datalen = 0;
sscanf(Cmd, "%x %x %x", &offset, &len, &iv);
bool errors = false;
uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h' :
return usage_legic_rdbl();
case 'o' :
offset = param_get32ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2;
break;
case 'l' :
len = param_get32ex(Cmd, cmdp + 1, 0, 16);
cmdp += 2;
break;
case 'i' :
iv = param_get32ex(Cmd, cmdp + 1, 1, 16);
cmdp += 2;
break;
default :
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || strlen(Cmd) == 0) return usage_legic_rdbl();
// sanity checks
if (len + offset >= MAX_LENGTH) {
@ -519,6 +567,7 @@ static int CmdLegicRdmem(const char *Cmd) {
return PM3_EMALLOC;
}
uint16_t datalen = 0;
int status = legic_read_mem(offset, len, iv, data, &datalen);
if (status == PM3_SUCCESS) {
PrintAndLogEx(NORMAL, "\n ## | 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F");
@ -529,8 +578,7 @@ static int CmdLegicRdmem(const char *Cmd) {
return status;
}
static int CmdLegicRfSim(const char *Cmd) {
static int CmdLegicSim(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_legic_sim();
@ -541,7 +589,7 @@ static int CmdLegicRfSim(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdLegicRfWrite(const char *Cmd) {
static int CmdLegicWrbl(const char *Cmd) {
uint8_t *data = NULL;
uint8_t cmdp = 0;
@ -551,7 +599,7 @@ static int CmdLegicRfWrite(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'd':
case 'd': {
// peek at length of the input string so we can
// figure out how many elements to malloc in "data"
bg = en = 0;
@ -595,24 +643,28 @@ static int CmdLegicRfWrite(const char *Cmd) {
len >>= 1;
cmdp += 2;
break;
case 'o':
}
case 'o': {
offset = param_get32ex(Cmd, cmdp + 1, 4, 16);
cmdp += 2;
break;
case 'h':
}
case 'h': {
errors = true;
break;
default:
}
default: {
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
}
//Validations
if (errors || cmdp == 0) {
if (data)
free(data);
return usage_legic_write();
return usage_legic_wrbl();
}
// tagtype
@ -865,28 +917,29 @@ static int CmdLegicReader(const char *Cmd) {
static int CmdLegicDump(const char *Cmd) {
FILE *f;
int fileNameLen = 0;
char filename[FILE_PATH_SIZE] = {0x00};
char *fnameptr = filename;
size_t fileNlen = 0;
bool errors = false;
char *fptr = filename;
bool errors = false, shall_deobsfuscate = false;
uint16_t dumplen;
uint8_t cmdp = 0;
memset(filename, 0, sizeof(filename));
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_legic_dump();
case 'o':
fileNlen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (!fileNlen)
case 'f':
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (!fileNameLen)
errors = true;
if (fileNlen > FILE_PATH_SIZE - 5)
fileNlen = FILE_PATH_SIZE - 5;
if (fileNameLen > FILE_PATH_SIZE - 5)
fileNameLen = FILE_PATH_SIZE - 5;
cmdp += 2;
break;
case 'x':
shall_deobsfuscate = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -947,34 +1000,30 @@ static int CmdLegicDump(const char *Cmd) {
}
// user supplied filename?
if (fileNlen < 1)
sprintf(fnameptr, "%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
else
sprintf(fnameptr + fileNlen, ".bin");
f = fopen(filename, "wb");
if (!f) {
PrintAndLogEx(WARNING, "Could not create file name %s", filename);
if (data)
free(data);
return PM3_EFILE;
if (fileNameLen < 1) {
PrintAndLogEx(INFO, "Using UID as filename");
fptr += sprintf(fptr, "hf-legic-");
FillFileNameByUID(fptr, data, "-dump", 4);
}
fwrite(data, 1, readlen, f);
fflush(f);
fclose(f);
free(data);
PrintAndLogEx(SUCCESS, "Wrote %d bytes to %s", readlen, filename);
if (shall_deobsfuscate) {
// Deobfuscate the whole dump. Unused data (after the last sector) will be MCC since
// 0x00 ^ MCC = MCC. Finding the end of used data is not part of this function.
legic_xor(data, dumplen);
}
saveFile(filename, ".bin", data, readlen);
saveFileEML(filename, data, readlen, 8);
saveFileJSON(filename, jsfLegic, data, readlen);
return PM3_SUCCESS;
}
static int CmdLegicRestore(const char *Cmd) {
FILE *f;
char filename[FILE_PATH_SIZE] = {0x00};
char *fnameptr = filename;
size_t fileNlen = 0;
bool errors = false;
uint16_t numofbytes;
bool errors = false, shall_obsfuscate = false;
size_t numofbytes;
uint8_t cmdp = 0;
memset(filename, 0, sizeof(filename));
@ -984,7 +1033,7 @@ static int CmdLegicRestore(const char *Cmd) {
case 'h':
errors = true;
break;
case 'i':
case 'f':
fileNlen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (!fileNlen)
errors = true;
@ -993,6 +1042,10 @@ static int CmdLegicRestore(const char *Cmd) {
fileNlen = FILE_PATH_SIZE - 5;
cmdp += 2;
break;
case 'x':
shall_obsfuscate = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -1008,48 +1061,30 @@ static int CmdLegicRestore(const char *Cmd) {
PrintAndLogEx(WARNING, "Failed to identify tagtype");
return PM3_ESOFT;
}
numofbytes = card.cardsize;
legic_print_type(card.cardsize, 0);
// set up buffer
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
if (!data) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
legic_print_type(numofbytes, 0);
if (loadFile_safe(filename, ".bin", (void **)&data, &numofbytes) != PM3_SUCCESS) {
free(data);
PrintAndLogEx(WARNING, "Error, reading file");
return PM3_EFILE;
}
// set up file
fnameptr += fileNlen;
sprintf(fnameptr, ".bin");
f = fopen(filename, "rb");
if (!f) {
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
if (card.cardsize != numofbytes) {
PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%zu != %u]", card.cardsize, numofbytes);
free(data);
return PM3_EFILE;
}
// verify size of dumpfile is the same as card.
fseek(f, 0, SEEK_END); // seek to end of file
size_t filesize = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file
if (filesize != numofbytes) {
PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%zu != %u]", filesize, numofbytes);
free(data);
fclose(f);
return PM3_EFILE;
}
// load file
size_t bytes_read = fread(data, 1, numofbytes, f);
fclose(f);
if (bytes_read == 0) {
PrintAndLogEx(ERR, "File reading error");
free(data);
return PM3_EFILE;
if (shall_obsfuscate){
legic_xor(data, card.cardsize);
}
PrintAndLogEx(SUCCESS, "Restoring to card");
@ -1092,37 +1127,54 @@ static int CmdLegicRestore(const char *Cmd) {
}
free(data);
PrintAndLogEx(SUCCESS, "\nWrote %d bytes to card from file %s", numofbytes, filename);
PrintAndLogEx(SUCCESS, "Done");
return PM3_SUCCESS;
}
static int CmdLegicELoad(const char *Cmd) {
FILE *f;
char filename[FILE_PATH_SIZE];
char *fnameptr = filename;
int len, numofbytes;
int nameParamNo = 1;
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 0x00)
return usage_legic_eload();
size_t numofbytes = 256;
int fileNameLen = 0;
char filename[FILE_PATH_SIZE] = {0x00};
bool errors = false, shall_obsfuscate = false;
uint8_t cmdp = 0;
switch (cmdp) {
case '0' :
numofbytes = 22;
break;
case '1' :
case '\0':
numofbytes = 256;
break;
case '2' :
numofbytes = 1024;
break;
default :
numofbytes = 256;
nameParamNo = 0;
break;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h' :
return usage_legic_eload();
case 'f' :
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (!fileNameLen)
errors = true;
if (fileNameLen > FILE_PATH_SIZE - 5)
fileNameLen = FILE_PATH_SIZE - 5;
cmdp += 2;
break;
case 'x':
shall_obsfuscate = true;
cmdp++;
break;
case '0' :
numofbytes = 22;
cmdp++;
break;
case '1' :
numofbytes = 256;
cmdp++;
break;
case '2' :
numofbytes = 1024;
cmdp++;
break;
default :
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || strlen(Cmd) == 0) return usage_legic_eload();
// set up buffer
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
@ -1131,75 +1183,68 @@ static int CmdLegicELoad(const char *Cmd) {
return PM3_EMALLOC;
}
// set up file
len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
if (len > FILE_PATH_SIZE - 5)
len = FILE_PATH_SIZE - 5;
fnameptr += len;
sprintf(fnameptr, ".bin");
// open file
f = fopen(filename, "rb");
if (!f) {
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
if (loadFile_safe(filename, ".bin", (void **)&data, &numofbytes) != PM3_SUCCESS) {
free(data);
PrintAndLogEx(WARNING, "Error, reading file");
return PM3_EFILE;
}
// load file
size_t bytes_read = fread(data, 1, numofbytes, f);
if (bytes_read == 0) {
PrintAndLogEx(ERR, "File reading error");
free(data);
fclose(f);
f = NULL;
return PM3_EFILE;
if (shall_obsfuscate) {
legic_xor(data, numofbytes);
}
fclose(f);
f = NULL;
// transfer to device
PrintAndLogEx(SUCCESS, "Uploading to emulator memory");
legic_seteml(data, 0, numofbytes);
free(data);
PrintAndLogEx(SUCCESS, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename);
PrintAndLogEx(SUCCESS, "Done");
return PM3_SUCCESS;
}
static int CmdLegicESave(const char *Cmd) {
char filename[FILE_PATH_SIZE];
char *fnameptr = filename;
int fileNlen, numofbytes, nameParamNo = 1;
memset(filename, 0, sizeof(filename));
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h' || cmdp == 0x00)
return usage_legic_esave();
switch (cmdp) {
case '0' :
numofbytes = 22;
break;
case '1' :
case '\0':
numofbytes = 256;
break;
case '2' :
numofbytes = 1024;
break;
default :
numofbytes = 256;
nameParamNo = 0;
break;
char filename[FILE_PATH_SIZE] = {0};
char *fptr = filename;
int fileNameLen = 0;
size_t numofbytes = 256;
bool errors = false, shall_deobsfuscate = false;
uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h' :
return usage_legic_esave();
case 'f' :
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (!fileNameLen)
errors = true;
if (fileNameLen > FILE_PATH_SIZE - 5)
fileNameLen = FILE_PATH_SIZE - 5;
cmdp += 2;
break;
case 'x':
shall_deobsfuscate = true;
cmdp++;
break;
case '0' :
numofbytes = 22;
cmdp++;
break;
case '1' :
numofbytes = 256;
cmdp++;
break;
case '2' :
numofbytes = 1024;
cmdp++;
break;
default :
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
fileNlen = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
if (fileNlen > FILE_PATH_SIZE - 5)
fileNlen = FILE_PATH_SIZE - 5;
//Validations
if (errors || strlen(Cmd) == 0) return usage_legic_esave();
// set up buffer
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
@ -1215,14 +1260,21 @@ static int CmdLegicESave(const char *Cmd) {
free(data);
return PM3_ETIMEOUT;
}
// user supplied filename?
if (fileNlen < 1)
sprintf(fnameptr, "%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
else
sprintf(fnameptr + fileNlen, ".bin");
saveFileEML(filename, data, numofbytes, 8);
// user supplied filename?
if (fileNameLen < 1) {
PrintAndLogEx(INFO, "Using UID as filename");
fptr += sprintf(fptr, "hf-legic-");
FillFileNameByUID(fptr, data, "-dump", 4);
}
if (shall_deobsfuscate) {
legic_xor(data, numofbytes);
}
saveFile(filename, ".bin", data, numofbytes);
saveFileEML(filename, data, numofbytes, 8);
saveFileJSON(filename, jsfLegic, data, numofbytes);
return PM3_SUCCESS;
}
@ -1299,17 +1351,17 @@ static int CmdLegicList(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
{"reader", CmdLegicReader, IfPm3Legicrf, "LEGIC Prime Reader UID and tag info"},
{"info", CmdLegicInfo, IfPm3Legicrf, "Display deobfuscated and decoded LEGIC Prime tag data"},
{"dump", CmdLegicDump, IfPm3Legicrf, "Dump LEGIC Prime tag to binary file"},
{"restore", CmdLegicRestore, IfPm3Legicrf, "Restore a dump file onto a LEGIC Prime tag"},
{"rdmem", CmdLegicRdmem, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
{"sim", CmdLegicRfSim, IfPm3Legicrf, "Start tag simulator"},
{"write", CmdLegicRfWrite, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
{"rdbl", CmdLegicRdbl, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
{"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"},
{"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
{"wipe", CmdLegicWipe, IfPm3Legicrf, "Wipe a LEGIC Prime tag"},
{NULL, NULL, NULL, NULL}
};

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

View file

@ -248,10 +248,10 @@ static int usage_hf14_chk(void) {
PrintAndLogEx(NORMAL, " t write keys to emulator memory\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf chk 0 A 1234567890ab -- target block 0, Key A using key 1234567890ab");
PrintAndLogEx(NORMAL, " hf mf chk 0 A mfc_default_keys.dic -- target block 0, Key A using default dictionary file");
PrintAndLogEx(NORMAL, " hf mf chk *1 ? t -- target all blocks, all keys, 1K, write to emulator memory");
PrintAndLogEx(NORMAL, " hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A 1234567890ab")" -- target block 0, Key A using key 1234567890ab");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A mfc_default_keys.dic")" -- target block 0, Key A using default dictionary file");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? t")" -- target all blocks, all keys, 1K, write to emulator memory");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? d")" -- target all blocks, all keys, 1K, write to file");
return PM3_SUCCESS;
}
static int usage_hf14_chk_fast(void) {
@ -269,12 +269,12 @@ static int usage_hf14_chk_fast(void) {
PrintAndLogEx(NORMAL, " m use dictionary from flashmemory\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf fchk 1 1234567890ab -- target 1K using key 1234567890ab");
PrintAndLogEx(NORMAL, " hf mf fchk 1 mfc_default_keys.dic -- target 1K using default dictionary file");
PrintAndLogEx(NORMAL, " hf mf fchk 1 t -- target 1K, write to emulator memory");
PrintAndLogEx(NORMAL, " hf mf fchk 1 d -- target 1K, write to file");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 1234567890ab")" -- target 1K using key 1234567890ab");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 mfc_default_keys.dic")" -- target 1K using default dictionary file");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 t")" -- target 1K, write to emulator memory");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 d")" -- target 1K, write to file");
if (IfPm3Flash())
PrintAndLogEx(NORMAL, " hf mf fchk 1 m -- target 1K, use dictionary from flashmemory");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 m")" -- target 1K, use dictionary from flashmemory");
return PM3_SUCCESS;
}
/*
@ -300,15 +300,15 @@ static int usage_hf14_restore(void) {
PrintAndLogEx(NORMAL, "Usage: hf mf restore [card memory] u <UID> k <name> f <name>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
PrintAndLogEx(NORMAL, " u <UID> : uid, try to restore from hf-mf-<UID>-key.bin and hf-mf-<UID>-data.bin");
PrintAndLogEx(NORMAL, " u <UID> : uid, try to restore from hf-mf-<UID>-key.bin and hf-mf-<UID>-dump.bin");
PrintAndLogEx(NORMAL, " k <name> : key filename, specific the full filename of key file");
PrintAndLogEx(NORMAL, " f <name> : data filename, specific the full filename of data file");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf restore -- read the UID from tag first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin");
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-data.bin");
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-data.bin");
PrintAndLogEx(NORMAL, " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin");
PrintAndLogEx(NORMAL, " hf mf restore -- read the UID from tag first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-dump.bin");
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-dump.bin");
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-dump.bin");
PrintAndLogEx(NORMAL, " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-dump.bin");
return PM3_SUCCESS;
}
static int usage_hf14_decryptbytes(void) {
@ -1064,7 +1064,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
if (strlen(dataFilename) < 1) {
fptr = GenerateFilename("hf-mf-", "-data");
fptr = GenerateFilename("hf-mf-", "-dump");
if (fptr == NULL)
return PM3_ESOFT;
@ -1103,7 +1103,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
if (keyFilename[0] == 0x00)
snprintf(keyFilename, FILE_PATH_SIZE, "hf-mf-%s-key.bin", szTemp);
if (dataFilename[0] == 0x00)
snprintf(dataFilename, FILE_PATH_SIZE, "hf-mf-%s-data.bin", szTemp);
snprintf(dataFilename, FILE_PATH_SIZE, "hf-mf-%s-dump.bin", szTemp);
cmdp += 2;
break;
case 'k':
@ -1161,7 +1161,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
fclose(fkeys);
if (dataFilename[0] == 0x00) {
fptr = GenerateFilename("hf-mf-", "-data.bin");
fptr = GenerateFilename("hf-mf-", "-dump.bin");
if (fptr == NULL)
return 1;
@ -1279,7 +1279,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
}
// check if tag doesn't have static nonce
if (detect_classic_static_nonce() != 0) {
if (detect_classic_static_nonce() == 1) {
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf staticnested`"));
return PM3_EOPABORTED;
@ -1447,7 +1447,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
jumptoend:
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "found keys:");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
//print them
printKeyTable(SectorsCnt, e_sector);
@ -1652,7 +1652,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
jumptoend:
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "found keys:");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
//print them
printKeyTable(SectorsCnt, e_sector);
@ -1839,7 +1839,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
if (!know_target_key && nonce_file_read == false) {
// check if tag doesn't have static nonce
if (detect_classic_static_nonce() != 0) {
if (detect_classic_static_nonce() == 1) {
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
PrintAndLogEx(INFO, "\t Try use `" _YELLOW_("hf mf staticnested") "`");
return PM3_EOPABORTED;
@ -2463,7 +2463,7 @@ all_found:
// Show the results to the user
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "found keys:");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
printKeyTable(sectors_cnt, e_sector);
@ -2507,7 +2507,7 @@ all_found:
return PM3_ETIMEOUT;
}
fnameptr = GenerateFilename("hf-mf-", "-data");
fnameptr = GenerateFilename("hf-mf-", "-dump");
if (fnameptr == NULL) {
free(dump);
free(e_sector);
@ -2715,7 +2715,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
// strategys. 1= deep first on sector 0 AB, 2= width first on all sectors
for (uint8_t strategy = 1; strategy < 3; strategy++) {
PrintAndLogEx(SUCCESS, "Running strategy %u", strategy);
PrintAndLogEx(INFO, "Running strategy %u", strategy);
// main keychunk loop
for (i = 0; i < keycnt; i += chunksize) {
@ -2746,7 +2746,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
}
out:
t1 = msclock() - t1;
PrintAndLogEx(SUCCESS, "Time in checkkeys (fast): %.1fs\n", (float)(t1 / 1000.0));
PrintAndLogEx(INFO, "Time in checkkeys (fast): %.1fs\n", (float)(t1 / 1000.0));
// check..
uint8_t found_keys = 0;
@ -2764,7 +2764,7 @@ out:
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "found keys:");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
printKeyTable(sectorsCnt, e_sector);
@ -3027,7 +3027,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
}
}
t1 = msclock() - t1;
PrintAndLogEx(SUCCESS, "\nTime in checkkeys: %.0f seconds\n", (float)t1 / 1000.0);
PrintAndLogEx(INFO, "\nTime in checkkeys: %.0f seconds\n", (float)t1 / 1000.0);
// 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
@ -3075,7 +3075,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
out:
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "found keys:");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
//print keys
if (SectorsCnt == 1)
@ -3129,7 +3129,7 @@ out:
}
sector_t *k_sector = NULL;
uint8_t k_sectorsCount = 16;
uint8_t k_sectorsCount = 40;
void showSectorTable() {
if (k_sector != NULL) {
@ -3217,18 +3217,22 @@ static int CmdHF14AMfSim(const char *Cmd) {
case 0:
flags |= FLAG_MF_MINI;
sprintf(csize, "MINI");
k_sectorsCount = MIFARE_MINI_MAXSECTOR;
break;
case 1:
flags |= FLAG_MF_1K;
sprintf(csize, "1K");
k_sectorsCount = MIFARE_1K_MAXSECTOR;
break;
case 2:
flags |= FLAG_MF_2K;
sprintf(csize, "2K with RATS");
k_sectorsCount = MIFARE_2K_MAXSECTOR;
break;
case 4:
flags |= FLAG_MF_4K;
sprintf(csize, "4K");
k_sectorsCount = MIFARE_4K_MAXSECTOR;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter for option t");
@ -3342,6 +3346,8 @@ static int CmdHF14AMfSim(const char *Cmd) {
}
showSectorTable();
}
k_sectorsCount = MIFARE_4K_MAXSECTOR;
return PM3_SUCCESS;
}
/*
@ -3543,9 +3549,9 @@ void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) {
void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector) {
char strA[12 + 1] = {0};
char strB[12 + 1] = {0};
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
PrintAndLogEx(NORMAL, "|sec| key A |res| key B |res|");
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
PrintAndLogEx(SUCCESS, "| Sec | key A |res| key B |res|");
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
for (uint8_t i = 0; i < sectorscnt; i++) {
snprintf(strA, sizeof(strA), "------------");
@ -3558,7 +3564,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]);
if (e_sector[i].foundKey[0] > 1) {
PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%c")"| %s | " _YELLOW_("%c")"|"
PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%c")"| " _GREEN_("%s")" | " _YELLOW_("%c")"|"
, i
, strA, e_sector[i].foundKey[0]
, strB, e_sector[i].foundKey[1]
@ -3570,14 +3576,14 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
if (start_sector == 0)
s = i;
PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%d")"| %s | " _YELLOW_("%d")"|"
PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%d")"| " _GREEN_("%s")" | " _YELLOW_("%d")"|"
, s
, strA, e_sector[i].foundKey[0]
, strB, e_sector[i].foundKey[1]
);
}
}
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
if (e_sector[0].foundKey[0] > 1) {
PrintAndLogEx(INFO, "( "
@ -3591,7 +3597,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
")"
);
} else {
PrintAndLogEx(INFO, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success)");
PrintAndLogEx(SUCCESS, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success)");
}
}
@ -3745,7 +3751,7 @@ int CmdHF14AMfELoad(const char *Cmd) {
return PM3_SUCCESS;
}
}
PrintAndLogEx(SUCCESS, "Loaded %d blocks from file: " _YELLOW_("%s"), blockNum, filename);
PrintAndLogEx(SUCCESS, "Done");
free(data);
return PM3_SUCCESS;
}
@ -3829,6 +3835,7 @@ static int CmdHF14AMfECFill(const char *Cmd) {
mfc_eload_t payload;
payload.sectorcnt = numSectors;
payload.keytype = keyType;
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload));
return PM3_SUCCESS;
@ -3836,8 +3843,6 @@ static int CmdHF14AMfECFill(const char *Cmd) {
static int CmdHF14AMfEKeyPrn(const char *Cmd) {
char filename[FILE_PATH_SIZE];
char *fptr = filename;
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
uint8_t data[16];
uint8_t uid[4];
@ -3909,6 +3914,8 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
// dump the keys
if (createDumpFile) {
char filename[FILE_PATH_SIZE] = {0};
char *fptr = filename;
fptr += sprintf(fptr, "hf-mf-");
FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid));
@ -3975,8 +3982,8 @@ static int CmdHF14AMfCSetUID(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "old UID:%s", sprint_hex(oldUid, 4));
PrintAndLogEx(SUCCESS, "new UID:%s", sprint_hex(uid, 4));
PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, 4));
PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, 4));
return PM3_SUCCESS;
}
@ -4798,6 +4805,95 @@ static int CmdHFMFNDEF(const char *Cmd) {
return PM3_SUCCESS;
}
int CmdHFMFPersonalize(const char *cmd) {
CLIParserInit("hf mf personalize",
"Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
"Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
"\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
"\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
"\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
"\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
void *argtable[] = {
arg_param_begin,
arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
char keytypestr[2] = "a";
uint8_t keytype = 0x00;
int keytypestr_len;
int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t *)keytypestr, 1, &keytypestr_len);
str_lower(keytypestr);
if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'b')) {
PrintAndLogEx(ERR, "ERROR: not a valid key type. Key type must be A or B");
CLIParserFree();
return PM3_EINVARG;
}
if (keytypestr[0] == 'b') {
keytype = 0x01;
}
uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int key_len;
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
if (res || (!res && key_len > 0 && key_len != 6)) {
PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits");
CLIParserFree();
return PM3_EINVARG;
}
char pers_optionstr[6];
int opt_len;
uint8_t pers_option;
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t *)pers_optionstr, 5, &opt_len);
str_lower(pers_optionstr);
if (res || (!res && opt_len > 0 && opt_len != 5)
|| (strncmp(pers_optionstr, "uidf0", 5) && strncmp(pers_optionstr, "uidf1", 5) && strncmp(pers_optionstr, "uidf2", 5) && strncmp(pers_optionstr, "uidf3", 5))) {
PrintAndLogEx(ERR, "ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
CLIParserFree();
return PM3_EINVARG;
}
if (!strncmp(pers_optionstr, "uidf0", 5)) {
pers_option = MIFARE_EV1_UIDF0;
} else if (!strncmp(pers_optionstr, "uidf1", 5)) {
pers_option = MIFARE_EV1_UIDF1;
} else if (!strncmp(pers_optionstr, "uidf2", 5)) {
pers_option = MIFARE_EV1_UIDF2;
} else {
pers_option = MIFARE_EV1_UIDF3;
}
CLIParserFree();
clearCommandBuffer();
struct {
uint8_t keytype;
uint8_t pers_option;
uint8_t key[6];
} PACKED payload;
payload.keytype = keytype;
payload.pers_option = pers_option;
memcpy(payload.key, key, 6);
SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500)) return PM3_ETIMEOUT;
PrintAndLogEx(SUCCESS, "Personalization %s", resp.status == PM3_SUCCESS ? "SUCCEEDED" : "FAILED");
return PM3_SUCCESS;
}
static int CmdHF14AMfList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
return CmdTraceList("mf");
@ -4817,13 +4913,16 @@ static command_t CommandTable[] = {
{"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"},
{"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"},
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE classic tag to binary file"},
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"},
{"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE classic block"},
{"rdsc", CmdHF14AMfRdSc, IfPm3Iso14443a, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, IfPm3Iso14443a, "Restore MIFARE classic binary file to BLANK tag"},
{"wrbl", CmdHF14AMfWrBl, IfPm3Iso14443a, "Write MIFARE classic block"},
{"setmod", CmdHf14AMfSetMod, IfPm3Iso14443a, "Set MIFARE Classic EV1 load modulation strength"},
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
// {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
{"sim", CmdHF14AMfSim, IfPm3Iso14443a, "Simulate MIFARE card"},
@ -4843,9 +4942,6 @@ static command_t CommandTable[] = {
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"},
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"},
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
{NULL, NULL, NULL, NULL}
};
@ -4860,4 +4956,3 @@ int CmdHFMF(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}

File diff suppressed because it is too large Load diff

View file

@ -19,16 +19,6 @@ char *getProtocolStr(uint8_t id);
char *getVersionStr(uint8_t major, uint8_t minor);
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 DELETE_APPLICATION 0xda
#define GET_APPLICATION_IDS 0x6a

View file

@ -8,7 +8,7 @@
// High frequency MIFARE commands
//-----------------------------------------------------------------------------
#include "cmdhfmfdesfire.h"
#include "cmdhfmfdesfire_disabled.h"
#include "cmdparser.h" // command_t

View file

@ -1390,7 +1390,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
char progress_text[80];
FILE *fnonces = NULL;
PacketResponseNG resp;
num_acquired_nonces = 0;
clearCommandBuffer();
@ -1402,24 +1401,35 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
flags |= field_off ? 0x0004 : 0;
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, key, 6);
if (field_off) break;
if (field_off) {
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
break;
} else {
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, key, 6);
}
if (initialize) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
uint8_t nullkey[6] = {0};
//strange second call (iceman)
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, nullkey, sizeof(nullkey));
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return 1;
}
if (resp.oldarg[0]) return resp.oldarg[0]; // error during nested_hard
// error during nested_hard
if (resp.oldarg[0]) {
clearCommandBuffer();
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return resp.oldarg[0];
}
cuid = resp.oldarg[1];
if (nonce_file_write && fnonces == NULL) {
if ((fnonces = fopen(filename, "wb")) == NULL) {
PrintAndLogEx(WARNING, "Could not create file %s", filename);
clearCommandBuffer();
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return 3;
}
snprintf(progress_text, 80, "Writing acquired nonces to binary file %s", filename);
@ -1486,17 +1496,24 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
}
if (!initialize) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
if (nonce_file_write) {
fclose(fnonces);
}
clearCommandBuffer();
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return 1;
}
// error during nested_hard
if (resp.oldarg[0]) {
if (nonce_file_write) {
fclose(fnonces);
}
return resp.oldarg[0]; // error during nested_hard
clearCommandBuffer();
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
return resp.oldarg[0];
}
}
@ -1513,11 +1530,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
fclose(fnonces);
}
// PrintAndLogEx(NORMAL, "Sampled a total of %d nonces in %d seconds (%0.0f nonces/minute)",
// total_num_nonces,
// time(NULL)-time1,
// (float)total_num_nonces*60.0/(time(NULL)-time1));
return 0;
}
@ -1681,11 +1693,12 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
for (uint8_t remaining_bits = 0; remaining_bits <= (~mask & 0xff); remaining_bits++) {
if (remaining_bits_match(num_common, bytes_diff, state, (state & mask) | remaining_bits, odd_even)) {
#ifdef DEBUG_KEY_ELIMINATION
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even, true)) {
#else
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even)) {
#endif
# ifdef DEBUG_KEY_ELIMINATION
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even, true))
# else
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even))
# endif
{
found_match = true;
break;
}
@ -1694,7 +1707,7 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
if (!found_match) {
#ifdef DEBUG_KEY_ELIMINATION
# ifdef DEBUG_KEY_ELIMINATION
if (known_target_key != -1 && state == test_state[odd_even]) {
PrintAndLogEx(NORMAL, "all_bitflips_match() 1st Byte: %s test state (0x%06x): Eliminated. Bytes = %02x, %02x, Common Bits = %d\n",
odd_even == ODD_STATE ? "odd" : "even",
@ -1706,7 +1719,7 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even");
}
}
#endif
# endif
return false;
}
}
@ -1851,7 +1864,6 @@ static bool TestIfKeyExists(uint64_t key) {
num_keys_tested += count;
hardnested_print_progress(num_acquired_nonces, "(Test: Key NOT found)", 0.0, 0);
crypto1_destroy(pcs);
return false;
}
@ -2019,13 +2031,13 @@ __attribute__((force_align_arg_pointer))
static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
init_statelist_cache();
init_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(&book_of_work_mutex, NULL);
init_statelist_cache();
init_book_of_work();
// create and run worker threads
pthread_t thread_id[NUM_REDUCTION_WORKING_THREADS];
@ -2042,9 +2054,6 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
pthread_join(thread_id[i], NULL);
}
// clean up mutex
pthread_mutex_destroy(&statelist_cache_mutex);
maximum_states = 0;
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE];

View file

@ -39,11 +39,15 @@ static int CmdHFMFPInfo(const char *Cmd) {
if (Cmd && strlen(Cmd) > 0)
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-- Mifare Plus Tag Information ------------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
// info about 14a part
infoHF14A(false, false, false);
// Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
WaitForResponse(CMD_ACK, &resp);
@ -54,61 +58,106 @@ 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
if (select_status == 1 || select_status == 2) {
PrintAndLogEx(NORMAL, "----------------------------------------------");
PrintAndLogEx(NORMAL, "Mifare Plus info:");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, " Fingerprint");
// MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf
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");
if (ATQA == 0x0044) PrintAndLogEx(INFO, "ATQA: Mifare Plus 2k 7bUID");
if (ATQA == 0x0042) PrintAndLogEx(INFO, "ATQA: Mifare Plus 4k 7bUID");
bool isPlus = false;
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;
if (card.sak == 0x08) {
PrintAndLogEx(INFO, "SAK: Mifare Plus 2k 7bUID");
if (select_status == 2) SLmode = 1;
if (isPlus) {
if (card.sak == 0x08) {
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
uint8_t data[250] = {0};
int datalen = 0;
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
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), true, 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) {
SLmode = 0;
}
}
}
if (SLmode != 0xff)
PrintAndLogEx(INFO, "Mifare Plus SL mode: SL%d", SLmode);
// How do we detect SL0 / SL1 / SL2 / SL3 modes?!?
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
PrintAndLogEx(WARNING, "Mifare Plus SL mode: unknown(");
PrintAndLogEx(WARNING, "\tMifare Plus SL mode: " _YELLOW_("unknown"));
} else {
PrintAndLogEx(INFO, "Mifare Plus info not available.");
PrintAndLogEx(INFO, "\tMifare Plus info not available.");
}
DropField();
return PM3_SUCCESS;
}
@ -916,9 +965,9 @@ static int CmdHFMFPChk(const char *Cmd) {
if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) {
if (!printedHeader) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------.");
PrintAndLogEx(INFO, "-------+--------------------------------+---------------------------------");
PrintAndLogEx(INFO, "|sector| key A | key B |");
PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|");
PrintAndLogEx(INFO, "|------+--------------------------------+--------------------------------|");
printedHeader = true;
}
PrintAndLogEx(INFO, "| %02d |%32s|%32s|",
@ -930,7 +979,7 @@ static int CmdHFMFPChk(const char *Cmd) {
if (!printedHeader)
PrintAndLogEx(INFO, "No keys found(");
else
PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n");
PrintAndLogEx(INFO, "'------+--------------------------------+--------------------------------'\n");
// save keys to json
if ((jsonnamelen > 0) && printedHeader) {

File diff suppressed because it is too large Load diff

View file

@ -14,15 +14,14 @@
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "cmdparser.h" // command_t
#include "comms.h"
#include "cmdtrace.h"
#include "cmdhf14a.h"
#include "ui.h"
#include "crc16.h"
#include "protocols.h"
#include "mifare/ndef.h"
#define TOPAZ_STATIC_MEMORY (0x0f * 8) // 15 blocks with 8 Bytes each
@ -35,7 +34,6 @@ typedef struct dynamic_lock_area {
uint16_t bytes_locked_per_bit;
} dynamic_lock_area_t;
static struct {
uint8_t HR01[2];
uint8_t uid[7];
@ -67,7 +65,7 @@ static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint
if (resp.oldarg[0] == *response_len) {
*response_len = resp.oldarg[0];
PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, *response_len));
PrintAndLogEx(DEBUG, "%s", sprint_hex(resp.data.asBytes, *response_len));
if (*response_len > 0) {
memcpy(response, resp.data.asBytes, *response_len);
}
@ -78,7 +76,6 @@ static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint
return PM3_SUCCESS;
}
// calculate CRC bytes and send topaz command, returns the length of the response (0 in case of error)
static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t *response_len, bool verbose) {
if (len > 1) {
@ -91,7 +88,6 @@ static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t
return topaz_send_cmd_raw(cmd, len, response, response_len, verbose);
}
// select a topaz tag. Send WUPA and RID.
static int topaz_select(uint8_t *atqa, uint8_t atqa_len, uint8_t *rid_response, uint8_t rid_len, bool verbose) {
// ToDo: implement anticollision
@ -119,7 +115,6 @@ static int topaz_select(uint8_t *atqa, uint8_t atqa_len, uint8_t *rid_response,
return PM3_SUCCESS;
}
// read all of the static memory of a selected Topaz tag.
static int topaz_rall(uint8_t *uid, uint8_t *response) {
uint16_t resp_len = 0;
@ -134,7 +129,6 @@ static int topaz_rall(uint8_t *uid, uint8_t *response) {
return PM3_SUCCESS;
}
// read a block (8 Bytes) of a selected Topaz tag.
static int topaz_read_block(uint8_t *uid, uint8_t blockno, uint8_t *block_data) {
uint16_t resp_len = 0;
@ -212,7 +206,6 @@ static bool topaz_byte_is_locked(uint16_t byteno) {
}
}
// read and print the Capability Container
static int topaz_print_CC(uint8_t *data) {
if (data[0] != 0xe1) {
@ -233,7 +226,6 @@ static int topaz_print_CC(uint8_t *data) {
return PM3_SUCCESS;
}
// return type, length and value of a TLV, starting at memory position *TLV_ptr
static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) {
*TLV_length = 0;
@ -265,7 +257,6 @@ static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length,
}
}
// lock area TLVs contain no information on the start of the respective lockable area. Lockable areas
// do not include the lock bits and reserved memory. We therefore need to adjust the start of the
// respective lockable areas accordingly
@ -279,7 +270,6 @@ static void adjust_lock_areas(uint16_t block_start, uint16_t block_size) {
}
}
// read and print the lock area and reserved memory TLVs
static void topaz_print_control_TLVs(uint8_t *memory) {
uint8_t *TLV_ptr = memory;
@ -372,7 +362,6 @@ static int topaz_read_dynamic_data(void) {
return PM3_SUCCESS;
}
// read and print the dynamic memory
static void topaz_print_dynamic_data(void) {
if (topaz_tag.size > TOPAZ_STATIC_MEMORY) {
@ -399,79 +388,30 @@ static void topaz_print_lifecycle_state(uint8_t *data) {
// to be done
}
static void topaz_print_NDEF(uint8_t *data) {
// to be done.
static int topaz_print_NDEF(uint8_t *data, size_t maxsize) {
return NDEFDecodeAndPrint(data, maxsize, true);
}
// read a Topaz tag and print some useful information
static int CmdHFTopazReader(const char *Cmd) {
int status;
uint8_t atqa[2];
uint8_t rid_response[8];
uint8_t *uid_echo = &rid_response[2];
uint8_t rall_response[124];
bool verbose = true;
bool verbose = true;
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 's') verbose = false;
status = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), verbose);
return readTopazUid(verbose);
}
if (status == PM3_ESOFT) {
if (verbose) PrintAndLogEx(ERR, "Error: couldn't receive ATQA");
return PM3_ESOFT;
}
// read a Topaz tag and print some useful information
static int CmdHFTopazInfo(const char *Cmd) {
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
if (verbose) PrintAndLogEx(ERR, "Tag doesn't support the Topaz protocol.");
topaz_switch_off_field();
return PM3_ESOFT;
}
bool verbose = true;
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 's') verbose = false;
if (status == PM3_EWRONGANSVER) {
if (verbose) PrintAndLogEx(ERR, "Error: tag didn't answer to RID");
topaz_switch_off_field();
return PM3_ESOFT;
}
int status = readTopazUid(verbose);
if (status != PM3_SUCCESS)
return status;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]);
topaz_tag.HR01[0] = rid_response[0];
topaz_tag.HR01[1] = rid_response[1];
// ToDo: CRC check
PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
rid_response[0],
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]);
status = topaz_rall(uid_echo, rall_response);
if (status == PM3_ESOFT) {
PrintAndLogEx(ERR, "Error: tag didn't answer to RALL");
topaz_switch_off_field();
return PM3_ESOFT;
}
memcpy(topaz_tag.uid, rall_response + 2, 7);
PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x",
topaz_tag.uid[6],
topaz_tag.uid[5],
topaz_tag.uid[4],
topaz_tag.uid[3],
topaz_tag.uid[2],
topaz_tag.uid[1],
topaz_tag.uid[0]);
PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
topaz_tag.uid[6],
getTagInfo(topaz_tag.uid[6]));
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":");
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked");
@ -520,7 +460,7 @@ static int CmdHFTopazReader(const char *Cmd) {
topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]);
topaz_print_NDEF(&topaz_tag.data_blocks[1][0]);
topaz_print_NDEF(&topaz_tag.data_blocks[1][0], TOPAZ_STATIC_MEMORY);
topaz_switch_off_field();
return PM3_SUCCESS;
@ -548,11 +488,12 @@ static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "<UID> -- Simulate Topaz tag"},
{"sniff", CmdHF14ASniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
{"raw", CmdHFTopazCmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
{NULL, NULL, 0, NULL}
};
@ -567,6 +508,71 @@ int CmdHFTopaz(const char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
int readTopazUid(void) {
return CmdHFTopazReader("s");
int readTopazUid(bool verbose) {
uint8_t atqa[2];
uint8_t rid_response[8];
uint8_t *uid_echo = &rid_response[2];
uint8_t rall_response[124];
int status = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), verbose);
if (status == PM3_ESOFT) {
if (verbose) PrintAndLogEx(ERR, "Error: couldn't receive ATQA");
return PM3_ESOFT;
}
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
if (verbose) PrintAndLogEx(ERR, "Tag doesn't support the Topaz protocol.");
topaz_switch_off_field();
return PM3_ESOFT;
}
if (status == PM3_EWRONGANSVER) {
if (verbose) PrintAndLogEx(ERR, "Error: tag didn't answer to RID");
topaz_switch_off_field();
return PM3_ESOFT;
}
status = topaz_rall(uid_echo, rall_response);
if (status == PM3_ESOFT) {
PrintAndLogEx(ERR, "Error: tag didn't answer to RALL");
topaz_switch_off_field();
return PM3_ESOFT;
}
memcpy(topaz_tag.uid, rall_response + 2, 7);
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
// printing
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x",
topaz_tag.uid[6],
topaz_tag.uid[5],
topaz_tag.uid[4],
topaz_tag.uid[3],
topaz_tag.uid[2],
topaz_tag.uid[1],
topaz_tag.uid[0]);
PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
topaz_tag.uid[6],
getTagInfo(topaz_tag.uid[6])
);
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]);
topaz_tag.HR01[0] = rid_response[0];
topaz_tag.HR01[1] = rid_response[1];
// ToDo: CRC check
PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
rid_response[0],
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]);
topaz_switch_off_field();
return PM3_SUCCESS;
}

View file

@ -15,5 +15,5 @@
int CmdHFTopaz(const char *Cmd);
int readTopazUid(void);
int readTopazUid(bool verbose);
#endif

View file

@ -253,34 +253,41 @@ static int CmdLFTune(const char *Cmd) {
//Validations
if (errors) return usage_lf_tune();
PrintAndLogEx(SUCCESS, "Measuring LF antenna at %.2f kHz, click button or press 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};
params[1] = divisor;
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF initialization, aborting");
return PM3_ETIMEOUT;
}
params[0] = 2;
// loop forever (till button pressed) if iter = 0 (default)
for (uint8_t i = 0; iter == 0 || i < iter; i++) {
if (kbd_enter_pressed()) { // abort by keyboard press
if (kbd_enter_pressed()) {
break;
}
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF measure, aborting");
return PM3_ETIMEOUT;
}
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint32_t)))
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint32_t))) {
break;
}
uint32_t volt = resp.data.asDwords[0];
PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint32_t)(volt / 1000));
PrintAndLogEx(INPLACE, "%u mV / %3u V", volt, (uint32_t)(volt / 1000));
}
params[0] = 3;
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
@ -288,11 +295,10 @@ static int CmdLFTune(const char *Cmd) {
return PM3_ETIMEOUT;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Done.");
PrintAndLogEx(INFO, "Done.");
return PM3_SUCCESS;
}
/* send a LF command before reading */
int CmdLFCommandRead(const char *Cmd) {
@ -451,6 +457,24 @@ int CmdFlexdemod(const char *Cmd) {
return PM3_SUCCESS;
}
int lf_getconfig(sample_config *config) {
if (!session.pm3_present) return PM3_ENOTTY;
if (config == NULL)
return PM3_EINVARG;
clearCommandBuffer();
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) {
PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT;
}
memcpy(config, resp.data.asBytes, sizeof(sample_config));
return PM3_SUCCESS;
}
int lf_config(sample_config *config) {
if (!session.pm3_present) return PM3_ENOTTY;
@ -458,7 +482,7 @@ int lf_config(sample_config *config) {
if (config != NULL)
SendCommandNG(CMD_LF_SAMPLING_SET_CONFIG, (uint8_t *)config, sizeof(sample_config));
else
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
SendCommandNG(CMD_LF_SAMPLING_PRINT_CONFIG, NULL, 0);
return PM3_SUCCESS;
}
@ -1165,7 +1189,7 @@ static bool CheckChipType(bool getDeviceData) {
uint32_t word = 0;
if (EM4x05IsBlock0(&word)) {
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;
goto out;
}
@ -1173,7 +1197,7 @@ static bool CheckChipType(bool getDeviceData) {
//check for t55xx chip...
if (tryDetectP1(true)) {
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("T55xx"));
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf t55xx`") "commands");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf t55xx`") "commands");
retval = true;
}
@ -1327,16 +1351,16 @@ static command_t CommandTable[] = {
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
{"hid", CmdLFHID, AlwaysAvailable, "{ HID RFIDs... }"},
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},
{"hitag", CmdLFHitag, AlwaysAvailable, "{ Hitag CHIPs... }"},
{"indala", CmdLFINDALA, AlwaysAvailable, "{ Indala RFIDs... }"},
{"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"},
{"jablotron", CmdLFJablotron, AlwaysAvailable, "{ Jablotron RFIDs... }"},
{"keri", CmdLFKeri, AlwaysAvailable, "{ KERI RFIDs... }"},
{"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"},
{"nedap", CmdLFNedap, AlwaysAvailable, "{ Nedap RFIDs... }"},
{"nexwatch", CmdLFNEXWATCH, AlwaysAvailable, "{ NexWatch RFIDs... }"},
{"noralsy", CmdLFNoralsy, AlwaysAvailable, "{ Noralsy RFIDs... }"},
{"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"},
{"pac", CmdLFPac, AlwaysAvailable, "{ PAC/Stanley RFIDs... }"},
{"paradox", CmdLFParadox, AlwaysAvailable, "{ Paradox RFIDs... }"},
{"pcf7931", CmdLFPCF7931, AlwaysAvailable, "{ PCF7931 CHIPs... }"},

View file

@ -34,5 +34,6 @@ int CmdLFfind(const char *Cmd);
int lf_read(bool verbose, uint32_t samples);
int lf_config(sample_config *config);
int lf_getconfig(sample_config *config);
#endif

View file

@ -422,7 +422,10 @@ static int CmdAWIDClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn);
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 awid read`") "to verify");
return res;
}
static int CmdAWIDBrute(const char *Cmd) {

View file

@ -700,6 +700,8 @@ static int CmdEM410xWrite(const char *Cmd) {
}
SendCommandMIX(CMD_LF_EM410X_WRITE, card, (uint32_t)(id >> 32), (uint32_t)id, NULL, 0);
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") "to verify");
return PM3_SUCCESS;
}
@ -1037,6 +1039,9 @@ static int CmdEM4x50Write(const char *Cmd) {
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_lf_em4x50_write();
PrintAndLogEx(NORMAL, "no implemented yet");
//
// PrintAndLogEx(SUCCESS, "Done");
// PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify");
return PM3_SUCCESS;
}
@ -1344,7 +1349,7 @@ static int CmdEM4x05Dump(const char *Cmd) {
// saveFileEML will add .eml extension to filename
// saveFile (binary) passes in the .bin extension.
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
sprintf(preferredName, "lf-4x05-%08X-data", BSWAP_32(data[1]));
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
saveFile(preferredName, ".bin", data, sizeof(data));
@ -1434,9 +1439,10 @@ static int CmdEM4x05Write(const char *Cmd) {
uint32_t dummy = 0;
int status = demodEM4x05resp(&dummy);
if (status == PM3_SUCCESS)
PrintAndLogEx(NORMAL, "Write " _GREEN_("Verified"));
else
PrintAndLogEx(NORMAL, "Write could " _RED_("not") "be verified");
PrintAndLogEx(SUCCESS, "Success writing to tag");
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify");
return status;
}
static int CmdEM4x05Wipe(const char *Cmd) {

View file

@ -301,7 +301,10 @@ static int CmdFdxClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid);
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 fdx read`") "to verify");
return res;
}
static int CmdFdxSim(const char *Cmd) {

View file

@ -178,7 +178,10 @@ static int CmdGallagherClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Gallagher to T55x7 with raw hex");
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 gallagher read`") "to verify");
return res;
}
static int CmdGallagherSim(const char *Cmd) {

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);
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) {

View file

@ -50,7 +50,7 @@ static int usage_lf_hid_watch(void) {
PrintAndLogEx(NORMAL, "Usage: lf hid watch");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid watch");
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid watch"));
return PM3_SUCCESS;
}
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, " ID - HID id");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid sim 2006ec0c86");
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid sim 2006ec0c86"));
return PM3_SUCCESS;
}
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, "Usage: lf hid clone [h] [l] ID");
PrintAndLogEx(NORMAL, "Options:");
@ -74,8 +74,8 @@ static int usage_lf_hid_clone(void) {
PrintAndLogEx(NORMAL, " l - 84bit ID");
PrintAndLogEx(NORMAL, " ID - HID id");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid clone 2006ec0c86");
PrintAndLogEx(NORMAL, " lf hid clone l 2006ec0c86");
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone 2006ec0c86"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone l 2006ec0c86"));
return PM3_SUCCESS;
}
static int usage_lf_hid_brute(void) {
@ -83,21 +83,23 @@ static int usage_lf_hid_brute(void) {
PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step");
PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w <format> [<field> (decimal)>] {...}");
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w <format> [<field> (decimal)>] [up|down] {...}");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " w <format> : see `wiegand list` for available formats");
PrintAndLogEx(NORMAL, " w <format> : see " _YELLOW_("`wiegand list`") "for available formats");
PrintAndLogEx(NORMAL, " f <facility-code> : facility code");
PrintAndLogEx(NORMAL, " c <cardnumber> : card number to start with");
PrintAndLogEx(NORMAL, " i <issuelevel> : issue level");
PrintAndLogEx(NORMAL, " o <oem> : OEM code");
PrintAndLogEx(NORMAL, " d <delay> : delay betweens attempts in ms. Default 1000ms");
PrintAndLogEx(NORMAL, " v : verbose logging, show all tries");
PrintAndLogEx(NORMAL, " up : direction to increment card number. (default is both directions)");
PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224");
PrintAndLogEx(NORMAL, " 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 w H10301 f 224"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 21 d 2000"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute v w H10301 f 21 c 200 d 2000"));
return PM3_SUCCESS;
}
@ -160,7 +162,7 @@ static int CmdHIDDemod(const char *Cmd) {
uint8_t bits[GraphTraceLen];
size_t size = getFromGraphBuf(bits);
if (size == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples");
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
return PM3_ESOFT;
}
//get binary from fsk wave
@ -169,17 +171,17 @@ static int CmdHIDDemod(const char *Cmd) {
if (idx < 0) {
if (idx == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples");
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
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)
PrintAndLogEx(DEBUG, "DEBUG: Error - HID problem during FSK demod");
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID problem during FSK demod"));
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)
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
PrintAndLogEx(DEBUG, "DEBUG: Error - HID error demoding fsk %d", idx);
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx);
return PM3_ESOFT;
}
@ -188,12 +190,12 @@ static int CmdHIDDemod(const char *Cmd) {
setClockGrid(50, waveIdx + (idx * 50));
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;
}
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
uint8_t fmtLen = 0;
uint32_t cc = 0;
@ -239,14 +241,14 @@ static int CmdHIDDemod(const char *Cmd) {
fc = ((hi & 0xF) << 12) | (lo >> 20);
}
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 {
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);
}
}
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)
printDemodBuff();
@ -266,6 +268,8 @@ static int CmdHIDWatch(const char *Cmd) {
if (ctmp == 'h') return usage_lf_hid_watch();
clearCommandBuffer();
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;
}
@ -286,18 +290,18 @@ static int CmdHIDSim(const char *Cmd) {
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;
} else {
while (sscanf(&Cmd[i++], "%1x", &n) == 1) {
hi = (hi << 4) | (lo >> 28);
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;
}
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
payload.hi2 = hi2;
payload.hi = hi;
@ -329,7 +333,7 @@ static int CmdHIDClone(const char *Cmd) {
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;
} else {
@ -337,13 +341,14 @@ static int CmdHIDClone(const char *Cmd) {
hi = (hi << 4) | (lo >> 28);
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;
}
clearCommandBuffer();
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
PrintAndLogEx(INFO, "Clone command sent. Try "_YELLOW_("'lf hid read'") " to verify");
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") "to verify");
return PM3_SUCCESS;
}
@ -365,14 +370,31 @@ static int CmdHIDClone(const char *Cmd) {
static int CmdHIDBrute(const char *Cmd) {
bool errors = false, verbose = false;
uint32_t delay = 1000;
uint32_t delay = 1000;
uint8_t cmdp = 0;
int format_idx = -1;
int direction = 0;
char format[16] = {0};
wiegand_card_t data;
memset(&data, 0, sizeof(wiegand_card_t));
wiegand_card_t cn_hi, cn_low;
memset(&cn_hi, 0, sizeof(wiegand_card_t));
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
char s[10] = {0};
if (param_getstr(Cmd, cmdp, s, sizeof(s)) > 0) {
if (strlen(s) > 1) {
str_lower((char *)s);
if (str_startswith(s, "up")) {
direction = 1;
} else if (str_startswith(s, "do")) {
direction = 2;
}
cmdp++;
continue;
}
}
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_hid_brute();
@ -380,13 +402,13 @@ static int CmdHIDBrute(const char *Cmd) {
param_getstr(Cmd, cmdp + 1, format, sizeof(format));
format_idx = HIDFindCardFormat(format);
if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: %s", format);
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
errors = true;
}
cmdp += 2;
break;
case 'c':
data.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10);
cn_hi.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'd':
@ -395,15 +417,15 @@ static int CmdHIDBrute(const char *Cmd) {
cmdp += 2;
break;
case 'f':
data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
cn_hi.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'i':
data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
cn_hi.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'o':
data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
cn_hi.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'v':
@ -411,18 +433,51 @@ static int CmdHIDBrute(const char *Cmd) {
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
PrintAndLogEx(WARNING, "Unknown parameter: " _YELLOW_("'%c'"), param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (format_idx == -1) {
PrintAndLogEx(ERR, "You must select a wiegand format. See " _YELLOW_("`wiegand list`") "for available formats\n");
errors = true;
}
if (errors) return usage_lf_hid_brute();
if (verbose) {
PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx);
PrintAndLogEx(INFO, "OEM#............. %u", cn_hi.OEM);
PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel);
PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode);
PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber);
switch (direction) {
case 0:
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH"));
break;
case 1:
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("UP"));
break;
case 2:
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN"));
break;
default:
break;
}
}
PrintAndLogEx(INFO, "Brute-forcing HID reader");
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command");
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or press `enter` to exit");
// copy values to low.
cn_low = cn_hi;
// main loop
for (;;) {
// iceman: could add options for bruteforcing OEM, ISSUE or FC aswell..
bool exitloop = false;
bool fin_hi, fin_low;
fin_hi = fin_low = false;
do {
if (!session.pm3_present) {
PrintAndLogEx(WARNING, "Device offline\n");
@ -434,18 +489,45 @@ static int CmdHIDBrute(const char *Cmd) {
return sendPing();
}
// Do one up
if (data.CardNumber < 0xFFFF) {
data.CardNumber++;
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
// do one up
if (direction != 2) {
if (cn_hi.CardNumber < 0xFFFF) {
cn_hi.CardNumber++;
if (sendTry(format_idx, &cn_hi, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
} else {
fin_hi = true;
}
}
// Do one down (if cardnumber is given)
if (data.CardNumber > 1) {
data.CardNumber--;
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
// do one down
if (direction != 1) {
if (cn_low.CardNumber > 0) {
cn_low.CardNumber--;
if (sendTry(format_idx, &cn_low, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
} else {
fin_low = true;
}
}
}
switch (direction) {
case 0:
if (fin_hi && fin_low) {
exitloop = true;
}
break;
case 1:
exitloop = fin_hi;
break;
case 2:
exitloop = fin_low;
break;
default:
break;
}
} while (exitloop == false);
PrintAndLogEx(INFO, "Brute forcing finished");
return PM3_SUCCESS;
}

View file

@ -28,6 +28,8 @@
#include "protocols.h" // t55 defines
#include "cmdlft55xx.h" // verifywrite
#define INDALA_ARR_LEN 64
static int CmdHelp(const char *Cmd);
//large 224 bit indala formats (different preamble too...)
@ -140,7 +142,7 @@ static void decodeHeden2L(uint8_t *bits) {
if (bits[offset + 7]) cardnumber += 16384;
if (bits[offset + 23]) cardnumber += 32768;
PrintAndLogEx(SUCCESS, "\tHeden-2L | %u", cardnumber);
PrintAndLogEx(SUCCESS, "\tHeden-2L | " _YELLOW_("%u"), cardnumber);
}
// Indala 26 bit decode
@ -192,7 +194,7 @@ static int CmdIndalaDemod(const char *Cmd) {
if (DemodBufferLen == 64) {
PrintAndLogEx(
SUCCESS
, "Indala Found - bitlength %zu, Raw %x%08x"
, "Indala Found - bitlength %zu, Raw " _YELLOW_("%x%08x")
, DemodBufferLen
, uid1
, uid2
@ -244,14 +246,18 @@ static int CmdIndalaDemod(const char *Cmd) {
checksum |= DemodBuffer[63] << 0; // b1
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC " _YELLOW_("%u") ", CN " _YELLOW_("%u") ", checksum " _YELLOW_("%1d%1d")
, fc
, csn
, checksum >> 1 & 0x01
, checksum & 0x01
);
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo);
decodeHeden2L(DemodBuffer);
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01);
} else {
uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32);
@ -499,6 +505,7 @@ static int CmdIndalaSim(const char *Cmd) {
uint8_t hexuid[100];
int len = 0;
param_gethex_ex(Cmd, 0, hexuid, &len);
if (len > 28)
return usage_lf_indala_sim();
@ -542,49 +549,62 @@ static int CmdIndalaSim(const char *Cmd) {
static int CmdIndalaClone(const char *Cmd) {
bool is_long_uid = false, got_cn = false;
bool is_long_uid = false, got_cn = false, got_26 = false;
bool is_t5555 = false;
int32_t cardnumber;
uint32_t blocks[8] = {0};
uint8_t max = 0;
uint8_t data[7 * 4];
int datalen = 0;
uint8_t fc = 0;
uint16_t cn = 0;
CLIParserInit("lf indala clone",
"clone INDALA tag to T55x7 (or to q5/T5555)",
"Examples:\n"
"\tlf indala clone -c 888\n"
"\tlf indala clone --heden 888\n"
"\tlf indala clone --fc 123 --cn 1337\n"
"\tlf indala clone -r a0000000a0002021\n"
"\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
void *argtable[] = {
arg_param_begin,
arg_lit0("lL", "long", "optional - long UID 224 bits"),
arg_int0("cC", "cn", "<decimal>", "Cardnumber for Heden 2L format"),
arg_strx0("rR", "raw", "<hex>", "raw bytes"),
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"),
arg_lit0("lL", "long", "optional - long UID 224 bits"),
arg_int0("cC", "heden", "<decimal>", "Cardnumber for Heden 2L format"),
arg_strx0("rR", "raw", "<hex>", "raw bytes"),
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"),
arg_int0("", "fc", "<decimal>", "Facility Code (26 bit format)"),
arg_int0("", "cn", "<decimal>", "Cardnumber (26 bit format)"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, false);
is_long_uid = arg_get_lit(1);
if (is_long_uid == false) {
cardnumber = arg_get_int_def(2, -1);
got_cn = (cardnumber != -1);
}
if (got_cn == false) {
CLIGetHexWithReturn(3, data, &datalen);
}
// raw param
CLIGetHexWithReturn(3, data, &datalen);
is_t5555 = arg_get_lit(4);
if (is_long_uid == false) {
// Heden param
cardnumber = arg_get_int_def(2, -1);
got_cn = (cardnumber != -1);
// 26b FC/CN param
fc = arg_get_int_def(5, 0);
cn = arg_get_int_def(6, 0);
got_26 = (fc != 0 && cn != 0);
}
CLIParserFree();
if (is_long_uid) {
// 224 BIT UID
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with RawID %s", sprint_hex(data, datalen));
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag");
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
if (is_t5555)
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
@ -602,12 +622,41 @@ static int CmdIndalaClone(const char *Cmd) {
} else {
// 64 BIT UID
if (got_cn) {
PrintAndLogEx(INFO, "Using Indala HEDEN cardnumber %u", cardnumber);
encodeHeden2L(data, cardnumber);
datalen = 8;
} else if (got_26) {
PrintAndLogEx(INFO, "Using Indala 26b FC %u CN %u", fc, cn);
// Used with the 26bit FC/CSN
uint8_t *bits = calloc(INDALA_ARR_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
return PM3_ESOFT;
}
data[0] = bytebits_to_byte(bits, 8);
data[1] = bytebits_to_byte(bits + 8, 8);
data[2] = bytebits_to_byte(bits + 16, 8);
data[3] = bytebits_to_byte(bits + 24, 8);
data[4] = bytebits_to_byte(bits + 32, 8);
data[5] = bytebits_to_byte(bits + 40, 8);
data[6] = bytebits_to_byte(bits + 48, 8);
data[7] = bytebits_to_byte(bits + 56, 8);
datalen = 8;
free(bits);
}
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with RawID %s", sprint_hex(data, datalen));
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag");
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
if (is_t5555)
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);
@ -620,7 +669,10 @@ static int CmdIndalaClone(const char *Cmd) {
}
print_blocks(blocks, max);
return clone_t55xx_tag(blocks, max);
int res = clone_t55xx_tag(blocks, max);
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf indala read`") "to verify");
return res;
}
static command_t CommandTable[] = {
@ -644,6 +696,71 @@ int CmdLFINDALA(const char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits) {
// preamble
// is there a preamble?
bits[0] = 1;
bits[2] = 1;
bits[32] = 1;
// add fc
bits[57] = ((fc >> 7) & 1); // b8
bits[49] = ((fc >> 6) & 1); // b7
bits[44] = ((fc >> 5) & 1); // b6
bits[47] = ((fc >> 4) & 1); // b5
bits[48] = ((fc >> 3) & 1); // b4
bits[53] = ((fc >> 2) & 1); // b3
bits[39] = ((fc >> 1) & 1); // b2
bits[58] = (fc & 1); // b1
// add cn
bits[42] = ((cn >> 15) & 1); // b16
bits[45] = ((cn >> 14) & 1); // b15 - c
bits[43] = ((cn >> 13) & 1); // b14
bits[40] = ((cn >> 12) & 1); // b13 - c
bits[52] = ((cn >> 11) & 1); // b12
bits[36] = ((cn >> 10) & 1); // b11
bits[35] = ((cn >> 9) & 1); // b10 - c
bits[51] = ((cn >> 8) & 1); // b9 - c
bits[46] = ((cn >> 7) & 1); // b8
bits[33] = ((cn >> 6) & 1); // b7 - c
bits[37] = ((cn >> 5) & 1); // b6 - c
bits[54] = ((cn >> 4) & 1); // b5
bits[56] = ((cn >> 3) & 1); // b4
bits[59] = ((cn >> 2) & 1); // b3 - c
bits[50] = ((cn >> 1) & 1); // b2
bits[41] = (cn & 1); // b1 - c
// checksum
uint8_t chk = 0;
//sum(y2, y4, y7, y8, y10, y11, y14, y16
chk += ((cn >> 14) & 1); //y2 == 75 - 30 = 45
chk += ((cn >> 12) & 1); //y4 == 70 - 30 = 40
chk += ((cn >> 9) & 1); //y7 == 65 - 30 = 35
chk += ((cn >> 8) & 1); //y8 == 81 - 30 = 51
chk += ((cn >> 6) & 1); //y10 == 63 - 30 = 33
chk += ((cn >> 5) & 1); //y11 == 67 - 30 = 37
chk += ((cn >> 2) & 1); //y14 == 89 - 30 = 59
chk += (cn & 1); //y16 == 71 - 30 = 41
if ((chk & 1) == 0) {
bits[62] = 0;
bits[63] = 1;
} else {
bits[62] = 1;
bits[63] = 0;
}
// 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
// indala id decoding
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 detectIndala224(uint8_t *bitStream, size_t *size, uint8_t *invert);
int demodIndala(void);
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits);
#endif

View file

@ -275,7 +275,10 @@ static int CmdIOProxClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn);
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 io read`") "to verify");
return res;
}
static command_t CommandTable[] = {

View file

@ -30,13 +30,21 @@ static int CmdHelp(const char *Cmd);
static int usage_lf_keri_clone(void) {
PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 tag.");
PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] <id> <Q5>");
PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t <m|i> [f <fc>] c <cardid> [Q5]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)");
// New format
PrintAndLogEx(NORMAL, " <t> [m|i] : Type. m - MS, i - Internal ID");
PrintAndLogEx(NORMAL, " <f> <fc> : Facility Code");
PrintAndLogEx(NORMAL, " <c> <cn> : Card Number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf keri clone 112233");
PrintAndLogEx(NORMAL, " lf keri clone type ms fc 6 cn 12345");
PrintAndLogEx(NORMAL, " lf keri clone t m f 6 c 12345");
return PM3_SUCCESS;
}
@ -54,6 +62,79 @@ static int usage_lf_keri_sim(void) {
return PM3_SUCCESS;
}
typedef enum {Scramble = 0,Descramble = 1} KeriMSScramble_t;
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
uint8_t CardToID [] = { 255,255,255,255, 13, 12, 20, 5, 16, 6, 21, 17, 8,255, 0, 7,
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, 0,255,255,
255,255, 2,255,255,255, 3,255, 4,255,255,255,255,255, 1,255 };
uint8_t CardIdx; // 0 - 31
bool BitState;
if (Action == Descramble) {
*FC = 0;
*ID = 0;
for (CardIdx = 0; CardIdx < 32; CardIdx++) {
// Get Bit State
BitState = (*CardID >> CardIdx) & 1;
// Card ID
if (CardToID[CardIdx] < 32) {
*ID = *ID | (BitState << CardToID[CardIdx]);
}
// Card FC
if (CardToFC[CardIdx] < 32) {
*FC = *FC | (BitState << CardToFC[CardIdx]);
}
}
}
if (Action == Scramble)
{
*CardID = 0; // set to 0
for (CardIdx = 0; CardIdx < 32; CardIdx++)
{
// Card ID
if (CardToID[CardIdx] < 32) {
if ((*ID & (1 << CardToID[CardIdx])) > 0)
*CardID |= (1 << CardIdx);
}
// Card FC
if (CardToFC[CardIdx] < 32) {
if ((*FC & (1 << CardToFC[CardIdx])) > 0)
*CardID |= (1 << CardIdx);
}
}
// Fixed bits and parity/check bits
/*
Add Parity and Fixed bits
Bit 3 - Note Used/Fixed 1 - TBC
Bit 31 - 1 Fixed Not in check/parity
Bit 0,1 - 2 Bit Parity
*/
*CardID |= (1 << 3);
// Check/Parity Bits
int Parity = 1;
for (CardIdx = 4; CardIdx <= 31; CardIdx += 2) {
Parity = Parity ^ ((*CardID >> CardIdx) & 11);
}
*CardID = *CardID | Parity;
// Bit 31 was fixed but not in check/parity bits
*CardID |= 1UL << 31;
PrintAndLogEx(SUCCESS, "Scrambled MS : FC %d - CN %d to RAW : E0000000%08X",*FC,*ID,*CardID);
}
return PM3_SUCCESS;
}
static int CmdKeriDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
@ -84,7 +165,10 @@ static int CmdKeriDemod(const char *Cmd) {
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
//get internal id
uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
// Due to the 3 sync bits being at the start of the capture
// We can take the last 32bits as the internal ID.
uint32_t ID = raw2;
ID &= 0x7FFFFFFF;
/*
@ -103,6 +187,16 @@ static int CmdKeriDemod(const char *Cmd) {
PrintAndLogEx(SUCCESS, "KERI Tag Found -- Internal ID: %u", ID);
PrintAndLogEx(SUCCESS, "Raw: %08X%08X", raw1, raw2);
/*
Descramble Data.
*/
uint32_t fc = 0;
uint32_t cardid = 0;
// Just need to the low 32 bits without the 111 trailer
CmdKeriMSScramble (Descramble,&fc,&cardid,&raw2);
PrintAndLogEx (SUCCESS,"Descrambled MS : FC %d - CN %d\n",fc,cardid);
if (invert) {
PrintAndLogEx(INFO, "Had to Invert - probably KERI");
@ -121,6 +215,10 @@ static int CmdKeriRead(const char *Cmd) {
static int CmdKeriClone(const char *Cmd) {
uint8_t cmdidx = 0;
char keritype = 'i'; // default to internalid
uint32_t fc = 0;
uint32_t cid = 0;
uint32_t internalid = 0;
uint32_t blocks[3] = {
T55x7_TESTMODE_DISABLED |
@ -138,8 +236,44 @@ static int CmdKeriClone(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone();
internalid = param_get32ex(Cmd, 0, 0, 10);
// Assume old format for backwards compatibility and only parameter is the internal id
cid = param_get32ex(Cmd, 0, 0, 10);
// find other options
while (param_getchar(Cmd, cmdidx) != 0x00) { // && !errors) {
switch (tolower(param_getchar(Cmd, cmdidx))) {
case 'h': // help
return usage_lf_keri_clone();
case 't': // format type
keritype = tolower(param_getchar(Cmd,cmdidx+1));
cmdidx += 2;
break;
case 'f': // fc
fc = param_get32ex(Cmd,cmdidx+1,0,10);
cmdidx += 2;
break;
case 'c': // cardid
cid = param_get32ex(Cmd,cmdidx+1,0,10);
cmdidx += 2;
break;
case 'q': // q5
blocks[0] =
T5555_MODULATION_PSK1 |
T5555_SET_BITRATE(128) |
T5555_PSK_RF_2 |
2 << T5555_MAXBLOCK_SHIFT;
cmdidx++;
break;
default:
// Skip unknown
cmdidx++;
}
}
// this is managed in above code
// internalid = param_get32ex(Cmd, 0, 0, 10);
/*
// Q5 is caught in the while loop
//Q5
if (tolower(param_getchar(Cmd, 1)) == 'q') {
blocks[0] =
@ -148,10 +282,19 @@ static int CmdKeriClone(const char *Cmd) {
T5555_PSK_RF_2 |
2 << T5555_MAXBLOCK_SHIFT;
}
// MSB is ONE
internalid |= 0x80000000;
*/
// Setup card data/build internal id
switch (keritype) {
case 'i' : // Internal ID
// MSB is ONE
internalid = cid | 0x80000000;
break;
case 'm' : // MS
CmdKeriMSScramble (Scramble,&fc,&cid,&internalid);
break;
}
// Prepare and write to card
// 3 LSB is ONE
uint64_t data = ((uint64_t)internalid << 3) + 7;
PrintAndLogEx(INFO, "Preparing to clone KERI to T55x7 with Internal Id: %" PRIx32, internalid);
@ -161,7 +304,10 @@ static int CmdKeriClone(const char *Cmd) {
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 keri read`") "to verify");
return res;
}
static int CmdKeriSim(const char *Cmd) {

View file

@ -177,7 +177,10 @@ static int CmdMotorolaClone(const char *Cmd) {
blocks[2] = bytes_to_num(data + 4, 4);
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 motorola read`") "to verify");
return res;
}
static int CmdMotorolaSim(const char *Cmd) {

View file

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

View file

@ -158,8 +158,10 @@ static int CmdNexWatchClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex");
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 nexwatch read`") "to verify");
return res;
}
static int CmdNexWatchSim(const char *Cmd) {

View file

@ -169,7 +169,10 @@ static int CmdNoralsyClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id);
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 noralsy read`") "to verify");
return res;
}
static int CmdNoralsySim(const char *Cmd) {

View file

@ -239,7 +239,10 @@ static int CmdPacClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex");
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 pac read`") "to verify");
return res;
}
static int CmdPacSim(const char *Cmd) {

View file

@ -36,7 +36,7 @@ static int usage_lf_paradox_clone(void) {
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf paradox clone 0f55555695596a6a9999a59a");
PrintAndLogEx(NORMAL, " lf paradox clone b 0f55555695596a6a9999a59a");
return PM3_SUCCESS;
}
@ -169,7 +169,10 @@ static int CmdParadoxClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex");
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 paradox read`") "to verify");
return res;
}
static int CmdParadoxSim(const char *Cmd) {

View file

@ -11,6 +11,7 @@
#include "cmdlfpcf7931.h"
#include <string.h>
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "comms.h"
@ -36,7 +37,7 @@ int pcf7931_resetConfig() {
configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY;
configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH;
configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION;
return 0;
return PM3_SUCCESS;
}
int pcf7931_printConfig() {
@ -44,7 +45,7 @@ int pcf7931_printConfig() {
PrintAndLogEx(NORMAL, "Tag initialization delay : %d us", configPcf.InitDelay);
PrintAndLogEx(NORMAL, "Offset low pulses width : %d us", configPcf.OffsetWidth);
PrintAndLogEx(NORMAL, "Offset low pulses position : %d us", configPcf.OffsetPosition);
return 0;
return PM3_SUCCESS;
}
static int usage_pcf7931_read() {
@ -54,7 +55,7 @@ static int usage_pcf7931_read() {
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf pcf7931 read");
return 0;
return PM3_SUCCESS;
}
static int usage_pcf7931_write() {
@ -67,7 +68,7 @@ static int usage_pcf7931_write() {
PrintAndLogEx(NORMAL, " data one byte of data (hex)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf pcf7931 write 2 1 FF");
return 0;
return PM3_SUCCESS;
}
static int usage_pcf7931_config() {
@ -87,30 +88,30 @@ static int usage_pcf7931_config() {
PrintAndLogEx(NORMAL, " lf pcf7931 config r");
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 20000");
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 17500 -10 30");
return 0;
return PM3_SUCCESS;
}
static int CmdLFPCF7931Read(const char *Cmd) {
uint8_t ctmp = param_getchar(Cmd, 0);
if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_read();
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_pcf7931_read();
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
PrintAndLogEx(WARNING, "command execution time out");
return 1;
return PM3_ETIMEOUT;
}
return 0;
return PM3_SUCCESS;
}
static int CmdLFPCF7931Config(const char *Cmd) {
uint8_t ctmp = param_getchar(Cmd, 0);
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 0) return pcf7931_printConfig();
if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_config();
if (ctmp == 'R' || ctmp == 'r') return pcf7931_resetConfig();
if (ctmp == 'h') return usage_pcf7931_config();
if (ctmp == 'r') return pcf7931_resetConfig();
if (param_gethex(Cmd, 0, configPcf.Pwd, 14)) return usage_pcf7931_config();
@ -119,13 +120,13 @@ static int CmdLFPCF7931Config(const char *Cmd) {
configPcf.OffsetPosition = (int)(param_get32ex(Cmd, 3, 0, 10) & 0xFFFF);
pcf7931_printConfig();
return 0;
return PM3_SUCCESS;
}
static int CmdLFPCF7931Write(const char *Cmd) {
uint8_t ctmp = param_getchar(Cmd, 0);
if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write();
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || ctmp == 'h') return usage_pcf7931_write();
uint8_t block = 0, bytepos = 0, data = 0;
@ -136,9 +137,9 @@ static int CmdLFPCF7931Write(const char *Cmd) {
data = param_get8ex(Cmd, 2, 0, 16);
PrintAndLogEx(NORMAL, "Writing block: %d", block);
PrintAndLogEx(NORMAL, " pos: %d", bytepos);
PrintAndLogEx(NORMAL, " data: 0x%02X", data);
PrintAndLogEx(INFO, "Writing block: %d", block);
PrintAndLogEx(INFO, " pos: %d", bytepos);
PrintAndLogEx(INFO, " data: 0x%02X", data);
uint32_t buf[10]; // TODO sparse struct, 7 *bytes* then words at offset 4*7!
memcpy(buf, configPcf.Pwd, sizeof(configPcf.Pwd));
@ -147,9 +148,11 @@ static int CmdLFPCF7931Write(const char *Cmd) {
buf[9] = configPcf.InitDelay;
clearCommandBuffer();
SendCommandOLD(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
//no ack?
return 0;
SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 read`") "to verify");
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
@ -163,7 +166,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return 0;
return PM3_SUCCESS;
}
int CmdLFPCF7931(const char *Cmd) {

View file

@ -136,7 +136,10 @@ static int CmdPrescoClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode);
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 presco read`") "to verify");
return res;
}
// takes base 12 ID converts to hex

View file

@ -250,7 +250,10 @@ static int CmdPyramidClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
print_blocks(blocks, ARRAYLEN(blocks));
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") "to verify");
return res;
}
static int CmdPyramidSim(const char *Cmd) {

View file

@ -168,7 +168,10 @@ static int CmdSecurakeyClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex");
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 securakey read`") "to verify");
return res;
}
static int CmdSecurakeySim(const char *Cmd) {

View file

@ -202,7 +202,7 @@ static int usage_t55xx_restore() {
PrintAndLogEx(NORMAL, _YELLOW_(" Assumes lf t55 detect has been run first!"));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf t55xx restore f lf-t55xx-00148040-data.bin");
PrintAndLogEx(NORMAL, " lf t55xx restore f lf-t55xx-00148040-dump.bin");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
@ -482,12 +482,16 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
int res = T55xxReadBlockEx(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, override, password, downlink_mode, false);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed to read block0, use `p` password parameter?");
PrintAndLogEx(WARNING, "Failed to read block0, use " _YELLOW_("`p`") "password parameter?");
return false;
}
if (GetT55xxBlockData(&block0) == false)
if (GetT55xxBlockData(&block0) == false) {
PrintAndLogEx(DEBUG, "ERROR decoded block0 == %08x", block0);
return false;
}
PrintAndLogEx(DEBUG, "OK read block0 == %08x", block0);
bool isPwdBitAlreadySet = (block0 >> (32 - 28) & 1);
if (isPwdBitAlreadySet) {
@ -1028,7 +1032,6 @@ void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
PrintAndLogEx(NORMAL, msg);
}
static int CmdT55xxDetect(const char *Cmd) {
bool errors = false;
@ -2316,7 +2319,7 @@ static int CmdT55xxDump(const char *Cmd) {
else
break;
}
strcat(preferredName, "-data");
strcat(preferredName, "-dump");
}
// Swap endian so the files match the txt display
@ -3680,7 +3683,7 @@ static int CmdT55xxProtect(const char *Cmd) {
// lock
if (t55xxProtect(true, usepwd, override, password, downlink_mode, new_password) == false) {
PrintAndLogEx(WARNING, "Command failed. Did you run `lf t55xx detect` before?");
PrintAndLogEx(WARNING, "Command failed. Did you run " _YELLOW_("`lf t55xx detect`") "before?");
return PM3_ESOFT;
}
return PM3_SUCCESS;

View file

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

View file

@ -121,7 +121,10 @@ static int CmdVerichipClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Verichip to T55x7 with raw hex");
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 verichip read`") "to verify");
return res;
}
static int CmdVerichipSim(const char *Cmd) {

View file

@ -117,6 +117,8 @@ static int CmdVikingClone(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") "to verify");
return resp.status;
}

View file

@ -184,7 +184,10 @@ static int CmdVisa2kClone(const char *Cmd) {
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to T55x7 with CardId: %"PRIu64, id);
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 visa2000 read`") "to verify");
return res;
}
static int CmdVisa2kSim(const char *Cmd) {

View file

@ -36,9 +36,23 @@
#include "cmdwiegand.h" // wiegand commands
#include "ui.h"
#include "util_posix.h"
#include "commonutil.h" // ARRAYLEN
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) {
PrintAndLogEx(NORMAL, "Sleep for given amount of milliseconds");
PrintAndLogEx(NORMAL, "");
@ -78,6 +92,70 @@ static void AppendDate(char *s, size_t slen, char *fmt) {
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) {
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_auto();
@ -90,8 +168,12 @@ static int CmdAuto(const char *Cmd) {
if (ret == PM3_SUCCESS)
return ret;
ret = lf_search_plus("");
if (ret == PM3_SUCCESS)
return ret;
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("");
lf_read(false, 40000);
@ -109,6 +191,33 @@ int CmdRem(const char *Cmd) {
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) {
uint32_t ms = 0;
char ctmp = tolower(param_getchar(Cmd, 0));
@ -149,6 +258,7 @@ static command_t CommandTable[] = {
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
{"", CmdHelp, AlwaysAvailable, ""},
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
{"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"},
{"quit", CmdQuit, AlwaysAvailable, ""},

View file

@ -59,11 +59,13 @@ static int CmdScriptRun(const char *Cmd) {
if ((!str_endswith(preferredName, ".cmd")) && (searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", true) == PM3_SUCCESS)) {
int error;
if (luascriptfile_idx == MAX_NESTED_LUASCRIPT) {
PrintAndLogEx(ERR, "Too many nested scripts, skipping %s\n", script_path);
PrintAndLogEx(ERR, "too many nested scripts, skipping %s\n", script_path);
free(script_path);
return PM3_EMALLOC;
}
PrintAndLogEx(SUCCESS, "Executing Lua script: %s, args '%s'\n", script_path, arguments);
PrintAndLogEx(SUCCESS, "executing lua " _YELLOW_("%s"), script_path);
PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments);
luascriptfile_idx++;
// create new Lua state
@ -94,7 +96,7 @@ static int CmdScriptRun(const char *Cmd) {
if (error) { // if non-0, then an error
// the top of the stack should be the error string
if (!lua_isstring(lua_state, lua_gettop(lua_state)))
PrintAndLogEx(FAILED, "Error - but no error (?!)");
PrintAndLogEx(FAILED, "error - but no error (?!)");
// get the top of the stack as the error and pop it off
const char *str = lua_tostring(lua_state, lua_gettop(lua_state));
@ -106,17 +108,22 @@ static int CmdScriptRun(const char *Cmd) {
// close the Lua state
lua_close(lua_state);
luascriptfile_idx--;
PrintAndLogEx(SUCCESS, "\nFinished %s\n", preferredName);
PrintAndLogEx(SUCCESS, "\nfinished " _YELLOW_("%s"), preferredName);
return PM3_SUCCESS;
}
if ((!str_endswith(preferredName, ".lua")) && (searchFile(&script_path, CMD_SCRIPTS_SUBDIR, preferredName, ".cmd", true) == PM3_SUCCESS)) {
PrintAndLogEx(SUCCESS, "Executing Cmd script: %s, args '%s'\n", script_path, arguments);
PrintAndLogEx(SUCCESS, "executing Cmd " _YELLOW_("%s"), script_path);
PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments);
int ret = push_cmdscriptfile(script_path, true);
if (ret != PM3_SUCCESS)
PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", script_path);
free(script_path);
return ret;
}
// file not found, let's search again to display the error messages
int ret = PM3_EUNDEF;
if (!str_endswith(preferredName, ".cmd")) ret = searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", false);
@ -141,7 +148,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
PrintAndLogEx(NORMAL, "This is a feature to run Lua-scripts. You can place Lua-scripts within the luascripts/-folder. ");
return 0;
return PM3_SUCCESS;
}
/**

View file

@ -216,23 +216,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
bool protocol_T15_present = false;
if (T0 & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
PrintAndLogEx(INFO, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
T1len++;
}
if (T0 & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
PrintAndLogEx(INFO, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
T1len++;
}
if (T0 & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
PrintAndLogEx(INFO, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
T1len++;
}
if (T0 & 0x80) {
uint8_t TD1 = atr[2 + T1len];
PrintAndLogEx(NORMAL, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
PrintAndLogEx(INFO, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
protocol_T0_present = false;
if ((TD1 & 0x0f) == 0) {
protocol_T0_present = true;
@ -244,20 +244,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
T1len++;
if (TD1 & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
PrintAndLogEx(INFO, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++;
}
if (TD1 & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
PrintAndLogEx(INFO, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++;
}
if (TD1 & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
PrintAndLogEx(INFO, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
TD1len++;
}
if (TD1 & 0x80) {
uint8_t TDi = atr[2 + T1len + TD1len];
PrintAndLogEx(NORMAL, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
PrintAndLogEx(INFO, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
if ((TDi & 0x0f) == 0) {
protocol_T0_present = true;
}
@ -271,20 +271,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
while (nextCycle) {
nextCycle = false;
if (TDi & 0x10) {
PrintAndLogEx(NORMAL, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
PrintAndLogEx(INFO, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++;
}
if (TDi & 0x20) {
PrintAndLogEx(NORMAL, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
PrintAndLogEx(INFO, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++;
}
if (TDi & 0x40) {
PrintAndLogEx(NORMAL, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
PrintAndLogEx(INFO, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
TDilen++;
}
if (TDi & 0x80) {
TDi = atr[2 + T1len + TD1len + TDilen];
PrintAndLogEx(NORMAL, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
PrintAndLogEx(INFO, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
TDilen++;
nextCycle = true;
@ -314,7 +314,7 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
if (K > 0)
PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
if (K > 1) {
PrintAndLogEx(INFO, "\tHistorical bytes");
@ -361,7 +361,9 @@ static int smart_responseEx(uint8_t *data, bool silent) {
if (needGetData) {
int len = data[datalen - 1];
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus));
@ -740,10 +742,9 @@ static int CmdSmartInfo(const char *Cmd) {
PrintAndLogEx(INFO, "--- Smartcard Information ---------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
PrintAndLogEx(INFO, "\nhttp://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len));
PrintAndLogEx(INFO, "http://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len));
// print ATR
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "ATR");
PrintATR(card.atr, card.atr_len);
@ -756,14 +757,14 @@ static int CmdSmartInfo(const char *Cmd) {
if (GetATRTA1(card.atr, card.atr_len) == 0x11)
PrintAndLogEx(INFO, "Using default values...");
PrintAndLogEx(NORMAL, "\t- Di %d", Di);
PrintAndLogEx(NORMAL, "\t- Fi %d", Fi);
PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F);
PrintAndLogEx(INFO, "\t- Di %d", Di);
PrintAndLogEx(INFO, "\t- Fi %d", Fi);
PrintAndLogEx(INFO, "\t- F %.1f MHz", F);
if (Di && Fi) {
PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi / Di);
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
PrintAndLogEx(INFO, "\t- Cycles/ETU %d", Fi / Di);
PrintAndLogEx(INFO, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
PrintAndLogEx(INFO, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
} else {
PrintAndLogEx(WARNING, "\t- Di or Fi is RFU.");
};
@ -1156,11 +1157,12 @@ int CmdSmartcard(const char *Cmd) {
return CmdsParse(CommandTable, Cmd);
}
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
*dataoutlen = 0;
if (activateCard)
smart_select(false, NULL);
smart_select(true, NULL);
PrintAndLogEx(DEBUG, "APDU SC");
@ -1168,10 +1170,11 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
if (activateCard) {
flags |= SC_SELECT | SC_CONNECT;
}
clearCommandBuffer();
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
int len = smart_responseEx(dataout, true);
int len = smart_responseEx(dataout, silent);
if (len < 0) {
return 1;
@ -1189,7 +1192,7 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
// something fishy: we have only 5 bytes but we put datainlen in arg1?
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
len = smart_responseEx(dataout, true);
len = smart_responseEx(dataout, silent);
}
*dataoutlen = len;
@ -1204,6 +1207,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
SendCommandNG(CMD_SMART_ATR, NULL, 0);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
return false;
}

View file

@ -17,6 +17,6 @@
int CmdSmartcard(const char *Cmd);
bool smart_select(bool silent, smart_card_atr_t *atr);
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif

View file

@ -671,7 +671,13 @@ void CloseProxmark(void) {
// Clean up our state
sp = NULL;
#ifdef __BIONIC__
if (communication_thread != 0) {
memset(&communication_thread, 0, sizeof(pthread_t));
}
#else
memset(&communication_thread, 0, sizeof(pthread_t));
#endif
session.pm3_present = false;
}

View file

@ -5,7 +5,8 @@
#
ffffffffffff # Defaultkey(firstkeyusedbyprogramifnouserdefinedkey)
000000000000 # Blankkey
a0a1a2a3a4a5 # NFCForumMADkey
a0a1a2a3a4a5 # NFC Forum MADkey
A5A4A3A2A1A0 # MAD access key (reversed)
b0b1b2b3b4b5
c0c1c2c3c4c5
d0d1d2d3d4d5
@ -20,19 +21,49 @@ a0478cc39091
533cb6c723f6
8fd0a4f256e9
#
d2ece8b9395e # lib
d2ece8b9395e # lib / Nat Bieb
# NSCP default key
1494E81663D7
#
# Kiev keys
569369c5a0e5 # kiev
632193be1c3c # kiev
644672bd4afe # kiev
8fe644038790 # kiev
9de89e070277 # kiev
b5ff67cba951 # kiev / ov-chipkaart
eff603e1efe9 # kiev
f14ee7cae863 # kiev
#
# RKF
fc00018778f7 # Västtrafiken KeyA, RKF ÖstgötaTrafiken KeyA
0297927c0f77 # Västtrafiken KeyA
54726176656c # Västtrafiken KeyA
00000ffe2488 # Västtrafiken KeyB
776974687573 # Västtrafiken KeyB
ee0042f88840 # Västtrafiken KeyB
26940b21ff5d # RKF SLKeyA
a64598a77478 # RKF SLKeyA
5c598c9c58b5 # RKF SLKeyB
e4d2770a89be # RKF SLKeyB
722bfcc5375f # RKF RejskortDanmark KeyA
f1d83f964314 # RKF RejskortDanmark KeyB
505249564141 # RKF JOJOPRIVAKeyA
505249564142 # RKF JOJOPRIVAKeyB
47524f555041 # RKF JOJOGROUPKeyA
47524f555042 # RKF JOJOGROUPKeyB
434f4d4d4f41 # RKF JOJOGROUPKeyA
434f4d4d4f42 # RKF JOJOGROUPKeyB
#
4b0b20107ccb # TNP3xxx
#
# more Keys from mfc_default_keys.lua
000000000001
000000000002
00000000000a
00000000000b
00000ffe2488 # VästtrafikenKeyB
010203040506
0123456789ab
0297927c0f77 # VästtrafikenKeyA
100000000000
111111111111
123456789abc
@ -41,72 +72,39 @@ d2ece8b9395e # lib
1999a3554a55
200000000000
222222222222
26940b21ff5d # RKFSLKeyA
27dd91f1fcf1
2BA9621E0A36 # DirectoryandeventlogKeyB
4AF9D7ADEBE4 # DirectoryandeventlogKeyA
333333333333
33f974b42769
34d1df9934c5
434f4d4d4f41 # RKFJOJOGROUPKeyA
434f4d4d4f42 # RKFJOJOGROUPKeyB
43ab19ef5c31
444444444444
47524f555041 # RKFJOJOGROUPKeyA
47524f555042 # RKFJOJOGROUPKeyB
4AF9D7ADEBE4 # DirectoryandeventlogKeyA
4b0b20107ccb # TNP3xxx
505249564141 # RKFJOJOPRIVAKeyA
505249564142 # RKFJOJOPRIVAKeyB
505249565441
505249565442
54726176656c # VästtrafikenKeyA
555555555555
55f5a5dd38c9
569369c5a0e5 # kiev
5c598c9c58b5 # RKFSLKeyB
632193be1c3c # kiev
644672bd4afe # kiev
666666666666
722bfcc5375f # RKFRejskortDanmarkKeyA
776974687573 # VästtrafikenKeyB
777777777777
888888888888
8fe644038790 # kiev
999999999999
99c636334433
9de89e070277 # kiev
a00000000000
a053a292a4af
a64598a77478 # RKFSLKeyA
a94133013401
aaaaaaaaaaaa
abcdef123456 # Keyfromladyada.net
b00000000000
b127c6f41436
b5ff67cba951 # kiev
bbbbbbbbbbbb
bd493a3962b6
c934fe34d934
cccccccccccc
dddddddddddd
e4d2770a89be # RKFSLKeyB
ee0042f88840 # VästtrafikenKeyB
eeeeeeeeeeee
eff603e1efe9 # kiev
f14ee7cae863 # kiev
f1a97341a9fc
f1d83f964314 # RKFRejskortDanmarkKeyB
fc00018778f7 # VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA
44ab09010845 # hotel system
85fed980ea5a # hotel system
314B49474956 # VIGIK1 A
564c505f4d41 # VIGIK1 B
ba5b895da162 # VIGIK1 B
# Vigik mystery Keys Mifare 1k EV1 (S50)
5c8ff9990da2 # 16 A
75ccb59c9bed # 17 A
d01afeeb890a # 16 B
4b791bea7bcc # 17 B
#
43454952534E # ARD (fr) key A
4A2B29111213 # ARD (fr) key B
@ -361,11 +359,29 @@ a56c2df9a26d
#
68d3f7307c89
568c9083f71c # Smart Rider. Western Australian Public Transport Cards
#
#
97F5DA640B18 # Bangkok metro key
A8844B0BCA06 # Metro Valencia key
857464D3AAD1 # HTC Eindhoven key
#
# Vigik Keys
# Various sources :
# * https://github.com/DumpDos/Vigik
# * http://newffr.com/viewtopic.php?&forum=235&topic=11559
# * Own dumps
#
# French VIGIK
314B49474956 # VIGIK1 A
564c505f4d41 # VIGIK1 B
ba5b895da162 # VIGIK1 B
#
# Vigik mystery Keys Mifare 1k EV1 (S50)
5c8ff9990da2 # 16 A
75ccb59c9bed # 17 A
d01afeeb890a # 16 B
4b791bea7bcc # 17 B
#
021209197591 # BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
2ef720f2af76
414c41524f4e
@ -543,11 +559,13 @@ B66AC040203A
2E641D99AD5B
AD4FB33388BF
69FB7B7CD8EE
2A6D9205E7CA
2A6D9205E7CA # Hotel
2a2c13cc242a
27FBC86A00D0
01FA3FC68349
#
13B91C226E56 # Hotel
#
6D44B5AAF464 # Smart Rider. Western Australian Public Transport Cards
1717E34A7A8A # Smart Rider. Western Australian Public Transport Cards
#
@ -1044,42 +1062,59 @@ a2a3cca2a3cc
#
# Granada, ES Transport Card
000000270000
0172066b2f03
0172066b2f33
066b2f230172
0b0172066b2f
0f385ffb6529
172066b2f2f0
2066b2f27017
29173860fc76
2f130172066b
2fca8492f386
385efa542907
3864fcba5937
3b0172066b2f
3f3865fccb69
5c8ff9990da2
6291b3860fc8
63fca9492f38
66b2f1f01720
6b2f1b017206
70172066b2f0
70172066b2f3
72066b2f2b01
863fcb959373
87291f3861fc
913385ffb752
b2f170172066
b385efa64290
c9739233861f
f0f0172066b2
f3864fcca693
f3f0172066b2
fc9839273862
#
# various hotel keys
34D3C568B348
91FF18E63887
4D8B8B95FDEE
354A787087F1
4a306e62e9b6
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
#
5a7a52d5e20d # Bosch Solution 6000
#
# Found in TagInfo app
8A19D40CF2B5 # Hotel key card key
C1E51C63B8F5 # RATB key
1DB710648A65
18F34C92A56E # E-GO card key

View file

@ -25,3 +25,6 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
15141312111009080706050403020100
0f0e0d0c0b0a09080706050403020100
100f0e0d0c0b0a090807060504030201
404142434445464748494a4b4c4d4e4f
303132333435363738393a3b3c3d3e3f

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

@ -662,10 +662,7 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
}
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
const char *qVSDC = "\x26\x00\x00\x00";
if (GenACGPO) {
qVSDC = "\x26\x80\x00\x00";
}
switch (TrType) {
case TT_MSD:
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
@ -675,10 +672,20 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
break;
case TT_QVSDCMCHIP:
TLV_ADD(0x9F66, qVSDC); // qVSDC
// qVSDC
if (GenACGPO) {
TLV_ADD(0x9F66, "\x26\x80\x00\x00");
} else {
TLV_ADD(0x9F66, "\x26\x00\x00\x00");
}
break;
case TT_CDA:
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
// qVSDC (VISA CDA not enabled)
if (GenACGPO) {
TLV_ADD(0x9F66, "\x26\x80\x00\x00");
} else {
TLV_ADD(0x9F66, "\x26\x00\x00\x00");
}
break;
default:
break;

View file

@ -305,7 +305,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea
break;
case ECC_CONTACT:
if (IfPm3Smartcard())
res = ExchangeAPDUSC(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
res = ExchangeAPDUSC(true, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
else
res = 1;
if (res) {

View file

@ -70,7 +70,7 @@ struct wave_info_t {
char tag[4];
uint32_t size;
} PACKED audio_data;
} PACKED wave_info;
} PACKED;
/**
* @brief checks if a file exists
@ -180,7 +180,7 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
fwrite(data, 1, datalen, f);
fflush(f);
fclose(f);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to binary file " _YELLOW_("%s"), datalen, fileName);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to binary file " _YELLOW_("%s"), datalen, fileName);
free(fileName);
return PM3_SUCCESS;
}
@ -223,7 +223,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
}
fflush(f);
fclose(f);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32)" blocks to text file " _YELLOW_("%s"), blocks, fileName);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32) "blocks to text file " _YELLOW_("%s"), blocks, fileName);
out:
free(fileName);
@ -233,6 +233,7 @@ out:
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen) {
if (data == NULL) return PM3_EINVARG;
char *fileName = newfilenamemcopy(preferredName, ".json");
if (fileName == NULL) return PM3_EMALLOC;
@ -368,10 +369,34 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
}
break;
}
case jsf14b:
case jsf15:
case jsfLegic:
case jsfT5555:
case jsf14b: {
JsonSaveStr(root, "FileType", "14b");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
}
case jsf15: {
JsonSaveStr(root, "FileType", "15693");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
}
case jsfLegic: {
JsonSaveStr(root, "FileType", "legic");
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
break;
}
case jsfT5555: {
JsonSaveStr(root, "FileType", "t5555");
uint8_t conf[4] = {0};
memcpy(conf, data, 4);
JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
break;
}
case jsfMfPlusKeys:
JsonSaveStr(root, "FileType", "mfp");
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
@ -455,7 +480,7 @@ int saveFileWAVE(const char *preferredName, int *data, size_t datalen) {
}
fclose(wave_file);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
out:
free(fileName);
@ -482,7 +507,7 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
fflush(f);
fclose(f);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName);
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName);
out:
free(fileName);
@ -581,7 +606,7 @@ int loadFile(const char *preferredName, const char *suffix, void *data, size_t m
memcpy((data), dump, bytes_read);
free(dump);
PrintAndLogEx(SUCCESS, "loaded %zu bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
*datalen = bytes_read;
@ -637,7 +662,7 @@ int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, s
*datalen = bytes_read;
PrintAndLogEx(SUCCESS, "loaded %zu bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
return PM3_SUCCESS;
}
@ -688,7 +713,7 @@ int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
}
}
fclose(f);
PrintAndLogEx(SUCCESS, "loaded %zu bytes from text file " _YELLOW_("%s"), counter, fileName);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from text file " _YELLOW_("%s"), counter, fileName);
if (datalen)
*datalen = counter;

View file

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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Andrei Costin <zveriu@gmail.com>, 2011
# gen_pm3mfsim_script.sh

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