diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index fda790b8..00000000 --- a/.gitattributes +++ /dev/null @@ -1,5 +0,0 @@ -# .gitattributes -# prevent binary files from CRLF handling, diff and merge: -fpga/fpga.bit -crlf -diff -*.bin -crlf -diff -*.z -crlf -diff diff --git a/.gitignore b/.gitignore index 852056a7..a43a00fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ # .gitignore # don't push these files to the repository -.history -*.log -*.eml *.o *.a *.d @@ -11,37 +8,20 @@ *.s19 *.map *.bin -!client/hardnested/*.bin -!client/sc_upgrade_firmware/*.bin *.dll *.moc.cpp -*.z -!client/hardnested/tables/*.z -usb_cmd.lua -version.c -armsrc/fpga_version_info.c -client/ui/ui_overlays.h -*.Td -.DS_Store - *.exe -hardnested_stats.txt -proxmark3 +proxmark flasher -lua -luac -fpga_compress -mfkey32 -mfkey64 +version.c fpga/* -!fpga/tests -!fpga/fpga_lf.bit -!fpga/fpga_hf.bit +!fpga/fpga.bit !fpga/*.v !fpga/Makefile !fpga/fpga.ucf -!fpga/xst_lf.scr -!fpga/xst_hf.scr +!fpga/xst.scr !fpga/go.bat !fpga/sim.tcl + + diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 67b1d537..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,283 +0,0 @@ -# Change Log -All notable changes to this project will be documented in this file. -This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... - -## [unreleased][unreleased] - -### Changed -- Changed hf mfp security. Now it works in all the modes. (drHatson) -- `hf fido` - show/check DER certificate and signatures (Merlok) -- Changed `lf hitag reader 0x ... ` - to select first page to read and tagmode (0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED) -- Accept hitagS con0 tags with memory bits set to 11 and handle like 2048 tag - -### Fixed -- AC-Mode decoding for HitagS -- Wrong UID at HitagS simulation -- `hf 15 sim` now works as expected (piwi) -- `hf mf chk t` save to emulator memory now works as expected (mwalker) -- Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) -- allow files > 512Bytes in 'hf iclass eload' (@Sherhannn79) -- `hf mf nested` now works with fixed nonce tags too (uzlonewolf, piwi) - -### Added -- Added to `hf 14a apdu` print apdu and compose apdu (@merlokk) -- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) -- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) -- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) -- Support Standard Communication Mode in HITAG S -- Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) -- `hf mfp` group of commands (Merlok) -- Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok) -- Added `lf hitag reader 03` - read block (instead of pages) -- Added `lf hitag reader 04` - read block (instead of pages) -- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) -- Added `lf paradox clone` to clone a Paradox card -- Added `emv` commands working for both contactless and smart cards (Merlok) -- Added `hf 15 snoop` (piwi) -- Added support for standard USB Smartcard Readers (piwi) -- Added `hf plot` (piwi) -- Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) -- Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) -- Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) -- Added Legic detection to `hf search` (dnet) -- Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) -- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` -- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password -- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi) -- Added `hf mf personalize` to personalize the UID option of Mifare Classic EV1 cards (piwi) - - -## [v3.1.0][2018-10-10] - -### Changed -- Adjusted `lf cmdread` to respond to client when complete and the client will then automatically call `data samples` -- Improved backdoor detection misbehaving magic s50/1k tag (Fl0-0) -- Deleted wipe functionality from `hf mf csetuid` (Merlok) -- Changed `hf mf nested` logic (Merlok) -- Added `hf mf nested` mode: autosearch keys for attack (from well known keys) (Merlok) -- `hf mf nested` Check keys after they have found (Merlok) -- `hf mf chk` Move main cycle to arm (Merlok) -- Changed proxmark command line parameter `flush` to `-f` or `-flush` (Merlok) -- Changed `hf 14a reader` to just request-anticolission-select sequence (Merlok) -- Changed `hf 14a raw` - works with LED's and some exchange logic (Merlok) -- Changed TLV parser messages to more convenient (Merlok) -- Rewritten Legic Prime reader (`hf legic reader`, `write` and `fill`) - it is using xcorrelation now (AntiCat) -- `hf 14a` commands works via argtable3 commandline parsing library (Merlok) -- HID LF operations on firmware updated for complete native support of long (>37 bit) HID tags (grauerfuchs) -- Changed Legic Prime tag simulator (`hf legic sim`) to run from 212 kHz SSP clock for better reliability (AntiCat) - -### Fixed -- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok) -- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi) -- Changed all command line parsers in `hf emv` commands to argtable (Merlok) -- Implemented AppNap API, fixing #283 and #627 OSX USB comm issues (AntiCat) - -### Added -- Added `sc` smartcard (contact card) commands - reader, info, raw, upgrade, setclock, list (hardware version RDV4.0 only) must turn option on in makefile options (Willok, Iceman, marshmellow) -- Added a bitbang mode to `lf cmdread` if delay is 0 the cmd bits turn off and on the antenna with 0 and 1 respectively (marshmellow) -- Added PAC/Stanley detection to lf search (marshmellow) -- Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow) -- Added hf mf c* commands compatibility for 4k and gen1b backdoor (Fl0-0) -- Added backdoor detection for gen1b magic s70/4k tag (Fl0-0) -- Added data fsktonrz, a fsk cleaning/demodulating routine for weak fsk signal. Note: follow this up with a `data rawdemod nr` to finish demoding your signal. (marshmellow) -- Added lf em 410xbrute, LF EM410x reader bruteforce attack by simulating UIDs from a file (Fl0-0) -- Added `hf mf cwipe` command. It wipes "magic Chinese" card. For 1a generation it uses card's "wipe" command. For gen1a and gen1b it uses a write command. (Merlok) -- Added to `hf mf nested` source key check before attack (Merlok) -- Added to `hf mf nested` after attack it checks all found keys on non-open sectors (Merlok) -- `hf mf chk` Added settings to set iso14443a operations timeout. default timeout set to 500us (Merlok) -- Added to `hf mf nested` parameters `s` and `ss` for checking slow cards (Merlok) -- Added to proxmark command line parameters `w` - wait 20s for serial port (Merlok) -- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (Merlok) -- Added to proxmark ability to execute commands from stdin (pipe) (Merlok) -- Added `hf 14a info` and moved there functionality from `hf 14a reader` (Merlok) -- Added to `hf 14a info` detection of weak prng from Iceman1001 fork (Merlok) -- Added to `hf 14a apdu` - exchange apdu via iso1443-4 (Merlok) -- Added to `hf 14a apdu` - apdu and tlv results parser (Merlok) -- Added `hf emv` group of commands (Merlok) -- Added `hf emv search` `hf emv pse` - commands for selection of EMV application (Merlok) -- Added `hf emv select` - command for select EMV application (Merlok) -- Added `hf emv exec` - command for execute EMV transaction (Merlok) -- Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok) -- Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok) -- Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok) -- Added `hf list mf` - deciphers crypto1 stream and works with first authentication and weak nested authentications (Merlok) -- Added to `hf emv` commands: `gpo`, `readrec`, `genac`, `challenge`, `intauth` - commands working with EMV cards (Merlok) -- Added `lf hid encode` and `lf hid decode` commands to translate printed HID card data to and from the packed data transmitted by a prox tag (grauerfuchs) -- Added `lf hid write` command, which operates as a macro for encode followed by clone operations (grauerfuchs) - -## [3.0.1][2017-06-08] - -### Fixed -- Compiles on OS X -- Compiles with gcc 4.9 -- Compiles for non-Intel CPUs - - -## [3.0.0][2017-06-05] - -### Added -- Added lf hitag write 24, the command writes a block to hitag2 tags in crypto mode (henjo) - -### Added -- Added hf mf hardnested, an attack working for hardened Mifare cards (EV1, Mifare Plus SL1) where hf mf nested fails (piwi) -- Added experimental testmode write option for t55xx (danger) (marshmellow) -- Added t55xx p1detect to `lf search` chip detections (marshmellow) -- Added lf t55xx p1detect, detect page 1 of a t55xx tag based on E015 mfg code (marshmellow) -- Added lf noralsy demod, read, clone, sim commands (iceman) -- Added lf jablotron demod, read, clone, sim commands (iceman) -- Added lf nexwatch read - reads a nexwatch tag from the antenna -- Added lf paradox read - reads a paradox tag from the antenna -- Added lf fdx sim (iceman) -- Added lf fdx clone - clones an fdx-b animal tag to t55x7 or q5 (iceman) -- Added lf fdx read - reads a fdx-b tag from the antenna (iceman) -- Added lf gproxii read - reads a gproxii tag from the antenna (marshmellow) -- Added lf indala read - reads an indala tag from the antenna (marshmellow) -- Added lf visa2000 demod, read, clone, sim commands (iceman) -- Added markers in the graph around found Sequence Terminator after askmandemod. -- Added data mtrim command to trim out samples between start and stop -- Added data setgraphmarkers command to set two extra markers on the graph (marshmellow) -- Added EM4x05/EM4x69 chip detection to lf search (marshmellow) -- Added lf em 4x05dump command to read and output all the blocks of the chip (marshmellow) -- Added lf em 4x05info command to read and display information about the chip (marshmellow) -- Added lf cotag read, and added it to lf search (iceman) -- Added hitag2 read UID only and added that to lf search (marshmellow) -- Added lf pyramid commands (iceman) -- Added lf presco commands - some bits not fully understood... (iceman) -- Added experimental HitagS support (Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg) - see https://media.ccc.de/v/32c3-7166-sicherheit_von_125khz_transpondern_am_beispiel_hitag_s - English video available -- Added a LF ASK Sequence Terminator detection option to the standard ask demod - and applied it to `lf search u`, `lf t55xx detect`, and `data rawdemod am s` (marshmellow) -- `lf t55xx bruteforce [i <*.dic>]` - Simple bruteforce attack to find password - (iceman and others) -- `lf viking clone`- clone viking tag to t55x7 or Q5 from 4byte hex ID input -- `lf viking sim` - sim full viking tag from 4byte hex ID input -- `lf viking read` - read viking tag and output ID -- `lf t55xx wipe` - sets t55xx back to factory defaults -- Added viking demod to `lf search` (marshmellow) -- `lf viking demod` demod viking id tag from graphbuffer (marshmellow) -- `lf t55xx resetread` added reset then read command - should allow determining start of stream transmissions (marshmellow) -- `lf t55xx wakeup` added wake with password (AOR) to allow lf search or standard lf read after (iceman, marshmellow) -- `hf iclass managekeys` to save, load and manage iclass keys. (adjusted most commands to accept a loaded key in memory) (marshmellow) -- `hf iclass readblk` to select, authenticate, and read 1 block from an iclass card (marshmellow) -- `hf iclass writeblk` to select, authenticate, and write 1 block to an iclass card (or picopass) (marshmellow + others) -- `hf iclass clone` to take a saved dump file and clone selected blocks to a new tag (marshmellow + others) -- `hf iclass calcnewkey` - to calculate the div_key change to change a key - (experimental) (marshmellow + others) -- `hf iclass encryptblk` - to encrypt a data block hex to prep for writing that block (marshmellow) -- ISO14443a stand-alone operation with ARM CFLAG="WITH_ISO14443a_StandAlone". This code can read & emulate two banks of 14a tag UIDs and write to "magic" cards (Craig Young) -- AWID26 command context added as 'lf awid' containing realtime demodulation as well as cloning/simulation based on tag numbers (Craig Young) -- Added 'hw status'. This command makes the ARM print out some runtime information. (holiman) -- Added 'hw ping'. This command just sends a usb packets and checks if the pm3 is responsive. Can be used to abort certain operations which supports abort over usb. (holiman) -- Added `data hex2bin` and `data bin2hex` for command line conversion between binary and hexadecimal (holiman) -- Added 'hf snoop'. This command take digitalized signal from FPGA and put in BigBuffer. (pwpiwi + enio) -- Added Topaz (NFC type 1) protocol support ('hf topaz reader', 'hf list topaz', 'hf 14a raw -T', 'hf topaz snoop'). (piwi) -- Added option c to 'hf list' (mark CRC bytes) (piwi) - -### Changed -- Adjusted the lf demods to auto align and set the grid for the graph plot. -- `lf snoop` now automatically gets samples from the device -- `lf read` now accepts [#samples] as arg. && now automatically gets samples from the device -- adjusted lf t5 chip timings to use WaitUS. and adjusted the readblock timings - appears to have more consistent results with more antennas. -- `lf t5 wakeup` has been adjusted to not need the p in front of the pwd arg. -- `data psknexwatchdemod` has been moved to `lf nexwatch demod` (reads from graphbuffer) -- `data fskparadoxdemod` has been moved to `lf paradox demod` (reads from graphbuffer) -- `data fdxdemod` has been moved to `lf fdx demod` (reads from graphbuffer) -- `data askgproxiidemod has been moved to `lf gproxii demod` (reads from graphbuffer) -- `lf indalaclone` has been moved to `lf indala clone` -- `lf indalademod` has been moved to `lf indala altdemod` (reads from graphbuffer) -- `data pskindalademod` has been moved to `lf indala demod` (reads from graphbuffer) -- `data askvikingdemod` has been moved to `lf viking demod` (reads from graphbuffer) -- `data fskpyramiddemod` has been moved to `lf pyramid demod` (reads from graphbuffer) -- `data fskiodemod` has been moved to `lf io demod` (reads from graphbuffer) -- `lf io fskdemod` has been renamed to `lf io read` (reads from antenna) -- `data fskawiddemod` has been moved to `lf awid demod` (reads from graphbuffer) -- `lf awid fskdemod` has been renamed to `lf awid read` (reads from antenna) -- `data fskhiddemod` has been moved to `lf hid demod` (reads from graphbuffer) -- `lf hid demod` has been renamed to `lf hid read` (reads from antenna) -- all em410x demod and print functions moved to cmdlfem4x.c -- `data askem410xdemod` has been moved to `lf em 410xdemod` (reads from graphbuffer) -- `lf em 410xdemod` has been renamed to `lf em 410xread` (reads from antenna) -- hf mf dump - added retry loops to try each read attempt up to 3 times. makes getting a complete dump easier with many antennas. -- small changes to lf psk and fsk demods to improve results when the trace begins with noise or the chip isn't broadcasting yet (marshmellow) -- NOTE CHANGED ALL `lf em4x em*` cmds to simpler `lf em ` - example: `lf em4x em410xdemod` is now `lf em 410xdemod` -- Renamed and rebuilt `lf em readword` && readwordpwd to `lf em 4x05readword` - it now demods and outputs the read block (marshmellow/iceman) -- Renamed and rebuilt `lf em writeword` && writewordpwd to `lf em 4x05writeword` - it now also reads validation output from the tag (marshmellow/iceman) -- Fixed bug in lf sim and continuous demods not turning off antenna when finished -- Fixed bug(s) in hf iclass write -- Fixed bug in lf biphase sim - `lf simask b` (and any tagtype that relies on it - gproxii...) (marshmellow) -- Fixed bug in lf viking clone/sim (iceman) -- Fixed broken `data askedgedetect` (marshmellow) -- Adjusted hf mf sim command (marshmellow) - added auto run mfkey32 to extract all keys - also added f parameter to allow attacking with UIDs from a file (implies x and i parameters) - also added e parameter to allow adding the extracted keys to emulator memory for the next simulation - added 10 byte uid option -- Added `[l] ` option to data printdemodbuffer (marshmellow) -- Adjusted lf awid clone to optionally clone to Q5 tags (marshmellow) -- Adjusted lf t55xx detect to find Q5 tags (t5555) instead of just t55x7 (marshmellow) -- Adjusted all lf NRZ demods - works more accurately and consistently (as long as you have strong signal) (marshmellow) -- Adjusted lf pskindalademod to reduce false positive reads. (marshmellow) -- Small adjustments to psk, nrz, and ask clock detect routines - more reliable. (marshmellow) -- Adjusted lf em410x em410xsim to accept a clock argument (marshmellow) -- Adjusted lf t55xx dump to allow overriding the safety check and warning text (marshmellow) -- Adjusted lf t55xx write input variables (marshmellow) -- Adjusted lf t55xx read with password safety check and warning text and adjusted the input variables (marshmellow & iceman) -- Adjusted LF FSK demod to account for cross threshold fluctuations (898 count waves will adjust the 9 to 8 now...) more accurate. (marshmellow) -- Adjusted timings for t55xx commands. more reliable now. (marshmellow & iceman) -- `lf cmdread` adjusted input methods and added help text (marshmellow & iceman) -- changed `lf config t ` to be 0 - 128 and will trigger on + or - threshold value (marshmellow) -- `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to multiple pages for the larger tags yet) (marshmellow) -- Revised workflow for StandAloneMode14a (Craig Young) -- EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers) -- 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi) -- Added `r` option to iclass functions - allows key to be provided in raw block 3/4 format - -## [2.2.0][2015-07-12] - -### Changed -- Added `hf 14b raw -s` option to auto select a 14b std tag before raw command -- Changed `hf 14b write` to `hf 14b sriwrite` as it only applied to sri tags (marshmellow) -- Added `hf 14b info` to `hf search` (marshmellow) -- Added compression of fpga config and data, *BOOTROM REFLASH REQUIRED* (piwi) -- Implemented better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (piwi) - -### Added -- Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (marshmellow) -- Add PACE replay functionality (frederikmoellers) - -### Fixed -- t55xx write timing (marshmellow) - - -## [2.1.0][2015-06-23] - -### Changed -- Added ultralight/ntag tag type detection to `hf 14a read` (marshmellow) -- Improved ultralight dump command to auto detect tag type, take authentication, and dump full memory (or subset specified) of known tag types (iceman1001 / marshmellow) -- Combined ultralight read/write commands and added authentication (iceman1001) -- Improved LF manchester and biphase demodulation and ask clock detection especially for reads with heavy clipping. (marshmellow) -- Iclass read, `hf iclass read` now also reads tag config and prints configuration. (holiman) -- *bootrom* needs to be flashed, due to new address boundaries between os and fpga, after a size optimization (piwi) - -### Fixed -- Fixed EM4x50 read/demod of the tags broadcasted memory blocks. 'lf em4x em4x50read' (not page read) (marshmellow) -- Fixed issue #19, problems with LF T55xx commands (iceman1001, marshmellow) -- Fixed various problems with iso14443b, issue #103 (piwi, marshmellow) - -### Added -- Added `hf search` - currently tests for 14443a tags, iclass tags, and 15693 tags (marshmellow) -- Added `hf mfu info` Ultralight/NTAG info command - reads tag configuration and info, allows authentication if needed (iceman1001, marshmellow) -- Added Mifare Ultralight C and Ultralight EV1/NTAG authentication. (iceman1001) -- Added changelog - -## [2.0.0] - 2015-03-25 -### Changed -- LF sim operations now abort when new commands arrive over the USB - not required to push the device button anymore. - -### Fixed -- Mifare simulation, `hf mf sim` (was broken a long time) (pwpiwi) -- Major improvements in LF area and data operations. (marshmellow, iceman1001) -- Issues regarding LF simulation (pwpiwi) - -### Added -- iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers don't seem to enforce update. (holiman). -- iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode. diff --git a/CI/.travis.yml b/CI/.travis.yml deleted file mode 100644 index 01dd168a..00000000 --- a/CI/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Travis-CI config -# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3" - -language: c - -compiler: gcc - -# Test on Linux and MacOS -jobs: - include: - - os: osx - osx_image: xcode9.4 # OS X 10.13 - - os: osx - osx_image: xcode10 # OS X 10.13 - - os: osx - osx_image: xcode11 # OS X 10.14 - - os: linux - dist: trusty # Ubuntu 14.04 - - os: linux - dist: xenial # Ubuntu 16.04 - - os: linux - dist: bionic # Ubuntu 18.04 - -git: - depth: false - -before_install: -## Install ARM toolchain on Linux. -## add our homebrew tap for MacOS -## Note: all dependencies on MacOS should be resolved by the brew install command - echo $REPOSITORY_EP; - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sudo apt-get update -qq; - sudo apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi libpcsclite-dev; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update; - if [[ "$REPOSITORY_EP" == "" ]]; then - brew tap --full proxmark/proxmark3; - else - brew tap --full "$REPOSITORY_EP" --env=std; - fi - fi - -install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew info proxmark3; - brew install -v --HEAD proxmark3; - elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - make all; - fi - -before_script: - -script: -## for the time being we are satisfied if it can be build and hf mf hardnested runs - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - proxmark3 /dev/notexists travis_test_commands.scr ; - elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - ./client/proxmark3 /dev/notexists travis_test_commands.scr ; - fi diff --git a/CI/appveyor.yml b/CI/appveyor.yml deleted file mode 100644 index a38ff647..00000000 --- a/CI/appveyor.yml +++ /dev/null @@ -1,321 +0,0 @@ -version: 3.0.1.{build} -image: Visual Studio 2017 -clone_folder: C:\ProxSpace\pm3 -init: -- ps: >- - $psversiontable - - #Get-ChildItem Env: - - - $releasename="" - - $env:APPVEYOR_REPO_COMMIT_SHORT = $env:APPVEYOR_REPO_COMMIT.Substring(0, 8) - - if ($env:appveyor_repo_tag -match "true"){ - $releasename=$env:APPVEYOR_REPO_TAG_NAME + "/" - } - - $releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]" - - - Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow - - 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')) -clone_script: -- ps: >- - Write-Host "Removing ProxSpace..." -NoNewLine - - cd \ - - Remove-Item -Recurse -Force -Path c:\ProxSpace\* - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Git clone ProxSpace..." -NoNewLine - - git clone -q https://github.com/Gator96100/ProxSpace c:\ProxSpace - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Removing pm3 dir..." -NoNewLine - - Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\* - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine - - if(-not $env:appveyor_pull_request_number) { - git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder - cd $env:appveyor_build_folder - git checkout -qf $env:appveyor_repo_commit - } else { - git clone -q https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder - cd $env:appveyor_build_folder - git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge: - git checkout -qf FETCH_HEAD - } - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Fill msys2\etc\fstab file..." -NoNewLine - - New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n" - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Update msys2 packages..." -NoNewLine - - $env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path" - - C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 - - C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 - - Write-Host "[ OK ]" -ForegroundColor Green -install: -- ps: >- - function Exec-External { - param( - [Parameter(Position=0,Mandatory=1)][scriptblock] $command - ) - & $command - if ($LASTEXITCODE -ne 0) { - throw ("Command returned non-zero error-code ${LASTEXITCODE}: $command") - } - } -build_script: -- ps: >- - "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path" - - - $env:MINGW_HOME="C:\ProxSpace\msys2\mingw32" - - $env:MSYS_HOME="C:\ProxSpace\msys2" - - $env:MSYSTEM="MINGW32" - - $env:MINGW_PREFIX="/mingw32" - - $env:SHELL="/bin/bash" - - $env:MSYSTEM_CHOST="i686-w64-mingw32" - - - #make - - bash -c -i 'pwd;make clean;make all' - - - #some checks - - if(!(Test-Path C:\ProxSpace\pm3\client\proxmark3.exe)){ - - throw "Main file proxmark3.exe not exists." - - } - - if(!(Test-Path C:\ProxSpace\pm3\armsrc\obj\fullimage.elf)){ - - throw "ARM file fullimage.elf not exists." - - } - - if(!(Test-Path C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z)){ - - throw "Files in hardnested\tables not exists." - - } - - - #copy - - Write-Host "Copy release files..." -NoNewLine -ForegroundColor Yellow - - New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release - - Copy-Item C:\ProxSpace\pm3\client\*.exe C:\ProxSpace\Release - - New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\arm - - Copy-Item C:\ProxSpace\pm3\armsrc\obj\*.elf C:\ProxSpace\Release\arm - - Copy-Item C:\ProxSpace\pm3\bootrom\obj\*.elf C:\ProxSpace\Release\arm - - New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\scripts - - Copy-Item C:\ProxSpace\pm3\client\scripts\*.lua C:\ProxSpace\Release\scripts - - New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\hardnested\tables - - Copy-Item C:\ProxSpace\pm3\client\hardnested\*.bin C:\ProxSpace\Release\hardnested - - Copy-Item C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z C:\ProxSpace\Release\hardnested\tables - - Write-Host "[ OK ]" -ForegroundColor Green - - - #archive and push - - $releasename="" - - if ($env:appveyor_repo_tag -match "true"){ - - $releasename=$env:APPVEYOR_REPO_TAG_NAME + "/" - - } - - $releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT.Substring(0, 7) + "]" - - - Write-Host "Archive and publish release files ($releasename)..." -NoNewLine -ForegroundColor Yellow - - cd C:\ProxSpace - - 7z a release.zip C:\ProxSpace\Release - - Push-AppveyorArtifact release.zip -DeploymentName "$releasename" - - Write-Host "[ OK ]" -ForegroundColor Green - - - Write-Host "Builded..." -ForegroundColor Yellow -test_script: -- ps: >- - $env:Path = "C:\ProxSpace\msys\bin;$env:Path" - - cd c:\ProxSpace\pm3 - - - $global:TestsPassed=$true - - - Function ExecTest($Name, $File, $Cmd, $CheckResult) { - - #--- begin Job - - $Job = Start-Job -ScriptBlock { - [bool]$res=$false - $TestTime=[System.Environment]::TickCount - $env:Path = "C:\ProxSpace\msys\bin;$env:Path" - Set-Location $using:PWD - - $sb=[scriptblock]::Create("$using:Cmd") - #execute scriptblock - Write-host "Test [$using:Name] job: $using:Cmd" - $Cond=&$sb - - if ($Cond -eq $null){ - } ElseIf($using:CheckResult -ne $null) { - [String]$searchstr="" - if ($Cond -is [Object]){ - ForEach($line in $Cond){ - Write-host $line -ForegroundColor Gray - $searchstr += $line - } - }else{ - Write-host "$Cond" -ForegroundColor Gray - $searchstr = $Cond - } - If($searchstr -like "*$using:CheckResult*") { - $res=$true - } - $Cond="*$using:CheckResult*" - } Else { - If (!($Cond -is [bool] -or $Cond -is [byte] -or $Cond -is [int16] -or $Cond -is [int32] -or $Cond -is [int64] -or $Cond -is [float])){ - if ($Cond -is "String" -and $Cond -like "*passed*"){ - $res= $true - } - if ($Cond -is "String" -and $Cond -like "*true*"){ - $res= $true - } - } Else { - $res=$Cond - } - } - - If ($res) { - Write-host "Result[$using:Name]: $Cond" -ForegroundColor Green - Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" - }Else { - Write-host "Result[$using:Name]: $Cond" -ForegroundColor Red - Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" -ErrorMessage "command:$using:Cmd`nresult:$Cond" - } - return $res - } - - #--- end Job - - [bool]$res=$false - # Wait 120 sec timeout for Job - if(Wait-Job $Job -Timeout 150){ - $Results = $Job | Receive-Job - if($Results -like "true"){ - $res=$true - } - } else { - Write-host "Test [$Name] timeout" -ForegroundColor Red - Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 60000 -ErrorMessage "timeout" - } - Remove-Job -Force $Job - - if(!$res){ - $global:TestsPassed=$false - } - } - - - Write-Host "Running tests..." -ForegroundColor Yellow - - - #file test - - ExecTest "proxmark3 exists" "proxmark3.exe" {Test-Path C:\ProxSpace\Release\proxmark3.exe} - - ExecTest "arm image exists" "\arm\fullimage1.elf" {Test-Path C:\ProxSpace\Release\arm\fullimage.elf} - - ExecTest "bootrom exists" "bootrom.elf" {Test-Path C:\ProxSpace\Release\arm\bootrom.elf} - - ExecTest "hardnested tables exists" "hardnested" {Test-Path C:\ProxSpace\Release\hardnested\tables\*.z} - - ExecTest "release exists" "release.zip" {Test-Path C:\ProxSpace\release.zip} - - - #proxmark logic tests - - ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q Execute && echo Passed || echo Failed'} - - ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'} - - - ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf'"} "at_enc" - - ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:" - - - #proxmark crypto tests - - ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf emv test'"} "Tests ?OK" - - - if ($global:TestsPassed) { - Write-Host "Tests [ OK ]" -ForegroundColor Green - } else { - Write-Host "Tests [ ERROR ]" -ForegroundColor Red - throw "Tests error." - } -on_success: -- ps: Write-Host "Build success..." -ForegroundColor Green -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')) diff --git a/CI/readme.md b/CI/readme.md deleted file mode 100644 index d4159290..00000000 --- a/CI/readme.md +++ /dev/null @@ -1,20 +0,0 @@ -# How to configure continuous integration - -Here 2 CI configuration files: - -1. for [travis](travis-ci.org) -2. for [appveyor](appveyor.com) - -It needs to put files from this directory to repository root and then configure CI from appropriate WEB portal. - -## travis - -- Copy .travis.yml and travis_test_commands.scr files to repository root -- Configure CI from http://travis-ci.org -- It needs to fork https://github.com/Proxmark/homebrew-proxmark3 from your proxmark repository home -- Put to file `proxmark3.rb` in line `head "https://github.com/proxmark/proxmark3.git"` your repository link. As sample: `head "https://github.com/merlokk/proxmark3.git"` - - -## appveyor - -- Just copy appveyor.yml file to root and configure it from http://appveyor.com diff --git a/CI/travis_test_commands.scr b/CI/travis_test_commands.scr deleted file mode 100644 index 2f81c885..00000000 --- a/CI/travis_test_commands.scr +++ /dev/null @@ -1,3 +0,0 @@ -hf mf hardnested t 1 000000000000 -emv test -exit diff --git a/COMPILING.txt b/COMPILING.txt index bd5bef1c..c894f0ff 100644 --- a/COMPILING.txt +++ b/COMPILING.txt @@ -3,7 +3,7 @@ The project compiles on Linux, Mac OS X and Windows (MinGW/MSYS). it requires: - gcc >= 4.4 - libpthread -- GNU libreadline or BSD libedit (editline) +- libreadline - libusb - perl - an ARM cross-compiler to compile the firmware @@ -81,55 +81,7 @@ Download the ProxSpace environment archive and extract it to C:\ = Mac OS X = ============ -Installing from HomeBrew tap ---------------------------- -This method is recommended and tested on macOS Sierra 10.12.3 - -1. Install homebrew if you haven't yet already done so: http://brew.sh/ - -2. Tap proxmark repo: - brew tap proxmark/proxmark3 - -3. Install Proxmark3: - -Stable release - brew install proxmark3 - -Latest non-stable from GitHub (use this if previous command fails) - brew install --HEAD proxmark3 - -For more information go to https://github.com/Proxmark/homebrew-proxmark3 - - -Compilling from source manually (Legacy) ---------------------------- - -Tested on OSX 10.10 Yosemite - -1 - Install Xcode and Xcode Command Line Tools - -2 - Install Homebrew and dependencies - brew install libusb p7zip libusb-compat wget qt5 pkgconfig - -3 - Install DevKitARM for OSX - Option 1: - http://sourceforge.net/projects/devkitpro/files/devkitARM/devkitARM_r44/ - Unpack devkitARM_r44-osx.tar.bz2 to proxmark3 directory. - Option 2: - brew tap nitsky/stm32 - brew install arm-none-eabi-gcc - -4 - Edit proxmark3/client/Makefile adding path qt5 - - LDLIBS = -L/usr/local/opt/qt5/lib -L/opt/local/lib -L/usr/local/lib ../liblua/liblua.a -lreadline -lpthread -lm - CFLAGS = -std=c99 -I/usr/local/opt/qt5/include -I. -I../include -I../common -I../zlib -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 - -5 - Set Environment - - export DEVKITPRO=$HOME/proxmark3/ - export DEVKITARM=$DEVKITPRO/devkitARM - export PATH=${PATH}:${DEVKITARM}/bin - +macport stuff should do ;) ============ = Linux = diff --git a/Makefile b/Makefile index 1ab83f9e..101212b4 100644 --- a/Makefile +++ b/Makefile @@ -1,65 +1,49 @@ -GZIP=gzip -# Windows' echo echos its input verbatim, on Posix there is some -# amount of shell command line parsing going on. echo "" on -# Windows yields literal "", on Linux yields an empty line -ifeq ($(shell echo ""),) -# This is probably a proper system, so we can use uname -DELETE=rm -rf -FLASH_TOOL=client/flasher -platform=$(shell uname) -ifneq (,$(findstring MINGW,$(platform))) -FLASH_PORT=com3 -PATHSEP=\\# -else -FLASH_PORT=/dev/ttyACM0 -PATHSEP=/ -endif -else -# Assume that we are running on native Windows -DELETE=del /q -FLASH_TOOL=client/flasher.exe -platform=Windows -FLASH_PORT=com3 -PATHSEP=\\# -endif +include common/Makefile.common -all clean: %: client/% bootrom/% armsrc/% recovery/% mfkey/% +GZIP=gzip +FLASH_PORT=/dev/ttyACM0 + +all clean: %: bootrom/% armsrc/% client/% recovery/% bootrom/%: FORCE - $(MAKE) -C bootrom $(patsubst bootrom/%, %, $@) + $(MAKE) -C bootrom $(patsubst bootrom/%,%,$@) armsrc/%: FORCE - $(MAKE) -C armsrc $(patsubst armsrc/%, %, $@) + $(MAKE) -C armsrc $(patsubst armsrc/%,%,$@) client/%: FORCE - $(MAKE) -C client $(patsubst client/%, %, $@) + $(MAKE) -C client $(patsubst client/%,%,$@) recovery/%: FORCE - $(MAKE) -C recovery $(patsubst recovery/%, %, $@) -mfkey/%: FORCE - $(MAKE) -C tools/mfkey $(patsubst mfkey/%, %, $@) + $(MAKE) -C recovery $(patsubst recovery/%,%,$@) FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites) -.PHONY: all clean help _test flash-bootrom flash-os flash-all FORCE +.PHONY: all clean help _test flash-bootrom flash-os flash-fpga flash-both flash-all FORCE help: @echo Multi-OS Makefile, you are running on $(DETECTED_OS) @echo Possible targets: @echo + all - Make bootrom, armsrc and the OS-specific host directory @echo + client - Make only the OS-specific host directory @echo + flash-bootrom - Make bootrom and flash it - @echo + flash-os - Make armsrc and flash os \(includes fpga\) - @echo + flash-all - Make bootrom and armsrc and flash bootrom and os image + @echo + flash-os - Make armsrc and flash os + @echo + flash-fpga - Make armsrc and flash fpga + @echo + flash-both - Make armsrc and flash os and fpga image + @echo + flash-all - Make bootrom and armsrc and flash bootrom, os and fpga image @echo + clean - Clean in bootrom, armsrc and the OS-specific host directory client: client/all -mfkey: mfkey/all - flash-bootrom: bootrom/obj/bootrom.elf $(FLASH_TOOL) $(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$<) -flash-os: armsrc/obj/fullimage.elf $(FLASH_TOOL) +flash-os: armsrc/obj/osimage.elf $(FLASH_TOOL) $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<) -flash-all: bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf $(FLASH_TOOL) +flash-fpga: armsrc/obj/fpgaimage.elf $(FLASH_TOOL) + $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$<) + +flash-both: armsrc/obj/osimage.elf armsrc/obj/fpgaimage.elf $(FLASH_TOOL) + $(FLASH_TOOL) $(FLASH_PORT) $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^)) + +flash-all: bootrom/obj/bootrom.elf armsrc/obj/osimage.elf armsrc/obj/fpgaimage.elf $(FLASH_TOOL) $(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$(filter-out $(FLASH_TOOL),$^)) newtarbin: diff --git a/README.md b/README.txt similarity index 56% rename from README.md rename to README.txt index 1ea871c3..ce5eacf4 100644 --- a/README.md +++ b/README.txt @@ -1,43 +1,51 @@ -# proxmark3: the official Proxmark repository! +NOTICE: +(2014-03-26) +This is now the official Proxmark repository! + +INTRODUCTION: The proxmark3 is a powerful general purpose RFID tool, the size of a deck of cards, designed to snoop, listen and emulate everything from -**Low Frequency (125kHz)** to **High Frequency (13.56MHz)** tags. +Low Frequency (125kHz) to High Frequency (13.56MHz) tags. This repository contains enough software, logic (for the FPGA), and design documentation for the hardware that you could, at least in theory, do something useful with a proxmark3. -## Resources +RESOURCES: -* [This repository!](https://github.com/Proxmark/proxmark3) -* [The Wiki](https://github.com/Proxmark/proxmark3/wiki) -* [The GitHub Pages website](http://proxmark.github.io/proxmark3/) -* [The Forum](http://www.proxmark.org/forum) -* The IRC channel: irc.freenode.org #proxmark3 ([chat in your browser](http://webchat.freenode.net/?channels=#proxmark3)) -* [The Homebrew formula repository](https://github.com/Proxmark/homebrew-proxmark3) -* [Proxmark3 community discord server](https://discord.gg/86VcRtS) + * This repository! + https://github.com/Proxmark/proxmark3 + + * The Wiki + https://github.com/Proxmark/proxmark3/wiki + + * The GitHub page + http://proxmark.github.io/proxmark3/ + + * The Forum + http://www.proxmark.org/forum + + * The IRC chanel + irc.freenode.org #proxmark3 + -or- + http://webchat.freenode.net/?channels=#proxmark3 -## Development +DEVELOPMENT: The tools required to build or run the project will vary depending on -your operating system. Please refer to [the wiki](https://github.com/Proxmark/proxmark3/wiki) for details. +your operating system. Please refer to the Wiki for details. -## Obtaining hardware + * https://github.com/Proxmark/proxmark3/wiki -The Proxmark3 is available for purchase (assembled and tested) from the +OBTAINING HARDWARE: + +The Proxmark 3 is available for purcahse (assembled and tested) from the following locations: -| Distributor Name | Warehouse Location | Entity Location | -|------------------|--------------------|-----------------| -| [RyscCorp](https://proxmark3.com/) | USA | USA | -| [Hackerwarehouse](https://hackerwarehouse.com/) | USA | USA | -| [Elechouse](http://www.elechouse.com/) | HK | HK | -| [Lab401](https://lab401.com/) | EU | HK | -| [RFxSecure](http://www.rfxsecure.com/) | CN | SG | -| [Sneaktechnology](https://www.sneaktechnology.com/) | CN | CN | + * http://proxmark3.com/ + * http://www.xfpga.com/ - Most of the ultra-low-volume contract assemblers could put something like this together with a reasonable yield. A run of around a dozen units is probably cost-effective. The BOM includes (possibly- @@ -56,7 +64,7 @@ The printed circuit board artwork is also available, as Gerbers and an Excellon drill file. -## License +LICENSING: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -77,3 +85,4 @@ Jonathan Westhues user jwesthues, at host cq.cx May 2007, Cambridge MA + diff --git a/_Sidebar.md b/_Sidebar.md new file mode 100644 index 00000000..fcffb6c0 --- /dev/null +++ b/_Sidebar.md @@ -0,0 +1,10 @@ +# Proxmark Wiki + * [Home Page](HomePage) + * [Getting Started](GettingStarted) + * [Hardware](Hardware) + * *Software / firmware* + * [Linux (Gentoo)](Gentoo Linux) + * [Windows](Windows) + * *Usage* + * [EM4102 Walk through](EM4102 1.pm3 Walkthrough) + * [Command Reference](commands) \ No newline at end of file diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c deleted file mode 100644 index ce97e41f..00000000 --- a/armsrc/BigBuf.c +++ /dev/null @@ -1,295 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, Aug 2005 -// Gerhard de Koning Gans, April 2008, May 2011 -// -// 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. -//----------------------------------------------------------------------------- -// BigBuf and functions to allocate/free parts of it. -//----------------------------------------------------------------------------- - -#include -#include "proxmark3.h" -#include "apps.h" -#include "string.h" -#include "util.h" - -// BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces. -// Also used to hold various smaller buffers and the Mifare Emulator Memory. - -/* BigBuf memory layout: -Pointer to highest available memory: BigBuf_hi - - high BIGBUF_SIZE - reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, - low 0x00 -*/ - -// declare it as uint32_t to achieve alignment to 4 Byte boundary -static uint32_t BigBuf[BIGBUF_SIZE/sizeof(uint32_t)]; - -// High memory mark -static uint16_t BigBuf_hi = BIGBUF_SIZE; - -// pointer to the emulator memory. -static uint8_t *emulator_memory = NULL; - -// trace related variables -static uint32_t traceLen = 0; -static bool tracing = true; - - -// get the address of BigBuf -uint8_t *BigBuf_get_addr(void) -{ - return (uint8_t *)BigBuf; -} - - -// get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done -uint8_t *BigBuf_get_EM_addr(void) -{ - // not yet allocated - if (emulator_memory == NULL) { - emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); - } - - return emulator_memory; -} - - -// clear ALL of BigBuf -void BigBuf_Clear(void) -{ - BigBuf_Clear_ext(true); -} - - -// clear ALL of BigBuf -void BigBuf_Clear_ext(bool verbose) -{ - memset(BigBuf, 0, BIGBUF_SIZE); - if (verbose) - Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE); -} - - -void BigBuf_Clear_EM(void){ - memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE); -} - - -void BigBuf_Clear_keep_EM(void) -{ - memset(BigBuf, 0, BigBuf_hi); -} - -// allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory -// at the beginning of BigBuf is always for traces/samples -uint8_t *BigBuf_malloc(uint16_t chunksize) -{ - if (BigBuf_hi - chunksize < 0) { - return NULL; // no memory left - } else { - chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 - BigBuf_hi -= chunksize; // aligned to 4 Byte boundary - return (uint8_t *)BigBuf + BigBuf_hi; - } -} - - -// free ALL allocated chunks. The whole BigBuf is available for traces or samples again. -void BigBuf_free(void) -{ - BigBuf_hi = BIGBUF_SIZE; - emulator_memory = NULL; -} - - -// free allocated chunks EXCEPT the emulator memory -void BigBuf_free_keep_EM(void) -{ - if (emulator_memory != NULL) { - BigBuf_hi = emulator_memory - (uint8_t *)BigBuf; - } else { - BigBuf_hi = BIGBUF_SIZE; - } -} - -void BigBuf_print_status(void) -{ - Dbprintf("Memory"); - Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE); - Dbprintf(" Available memory........%d", BigBuf_hi); - Dbprintf("Tracing"); - Dbprintf(" tracing ................%d", tracing); - Dbprintf(" traceLen ...............%d", traceLen); -} - - -// return the maximum trace length (i.e. the unallocated size of BigBuf) -uint16_t BigBuf_max_traceLen(void) -{ - return BigBuf_hi; -} - - -void clear_trace() { - traceLen = 0; -} - - -void set_tracing(bool enable) { - tracing = enable; -} - - -bool get_tracing(void) { - return tracing; -} - - -/** - * Get the number of bytes traced - * @return - */ -uint16_t BigBuf_get_traceLen(void) -{ - return traceLen; -} - - -/** - This is a function to store traces. All protocols can use this generic tracer-function. - The traces produced by calling this function can be fetched on the client-side - by 'hf list raw', alternatively 'hf list ' for protocol-specific - annotation of commands/responses. - -**/ -bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) -{ - if (!tracing) return false; - - uint8_t *trace = BigBuf_get_addr(); - - uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity - uint32_t duration = timestamp_end - timestamp_start; - - // Return when trace is full - uint16_t max_traceLen = BigBuf_max_traceLen(); - - if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= max_traceLen) { - tracing = false; // don't trace any more - return false; - } - // Traceformat: - // 32 bits timestamp (little endian) - // 16 bits duration (little endian) - // 16 bits data length (little endian, Highest Bit used as readerToTag flag) - // y Bytes data - // x Bytes parity (one byte per 8 bytes data) - - // timestamp (start) - trace[traceLen++] = ((timestamp_start >> 0) & 0xff); - trace[traceLen++] = ((timestamp_start >> 8) & 0xff); - trace[traceLen++] = ((timestamp_start >> 16) & 0xff); - trace[traceLen++] = ((timestamp_start >> 24) & 0xff); - - // duration - trace[traceLen++] = ((duration >> 0) & 0xff); - trace[traceLen++] = ((duration >> 8) & 0xff); - - // data length - trace[traceLen++] = ((iLen >> 0) & 0xff); - trace[traceLen++] = ((iLen >> 8) & 0xff); - - // readerToTag flag - if (!readerToTag) { - trace[traceLen - 1] |= 0x80; - } - - // data bytes - if (btBytes != NULL && iLen != 0) { - for (int i = 0; i < iLen; i++) { - trace[traceLen++] = *btBytes++; - } - } - - // parity bytes - if (num_paritybytes != 0) { - if (parity != NULL) { - for (int i = 0; i < num_paritybytes; i++) { - trace[traceLen++] = *parity++; - } - } else { - for (int i = 0; i < num_paritybytes; i++) { - trace[traceLen++] = 0x00; - } - } - } - - return true; -} - - -int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag) -{ - /** - Todo, rewrite the logger to use the generic functionality instead. It should be noted, however, - that this logger takes number of bits as argument, not number of bytes. - **/ - - if (!tracing) return false; - - uint8_t *trace = BigBuf_get_addr(); - uint16_t iLen = nbytes(iBits); - - // Return when trace is full - if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) { - return false; - } - - //Hitag traces appear to use this traceformat: - // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) - // 32 bits parity - // 8 bits size (number of bits in the trace entry, not number of bytes) - // y Bytes data - - - - rsamples += iSamples; - trace[traceLen++] = ((rsamples >> 0) & 0xff); - trace[traceLen++] = ((rsamples >> 8) & 0xff); - trace[traceLen++] = ((rsamples >> 16) & 0xff); - trace[traceLen++] = ((rsamples >> 24) & 0xff); - - if (!readerToTag) { - trace[traceLen - 1] |= 0x80; - } - - trace[traceLen++] = ((dwParity >> 0) & 0xff); - trace[traceLen++] = ((dwParity >> 8) & 0xff); - trace[traceLen++] = ((dwParity >> 16) & 0xff); - trace[traceLen++] = ((dwParity >> 24) & 0xff); - trace[traceLen++] = iBits; - - for (int i = 0; i < iLen; i++) { - trace[traceLen++] = *btBytes++; - } - - return true; -} - - -// Emulator memory -uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){ - uint8_t* mem = BigBuf_get_EM_addr(); - if (offset+length < CARD_MEMORY_SIZE) { - memcpy(mem+offset, data, length); - return 0; - } else { - Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset+length), CARD_MEMORY_SIZE); - return 1; - } -} diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h deleted file mode 100644 index 00d5145f..00000000 --- a/armsrc/BigBuf.h +++ /dev/null @@ -1,44 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, Aug 2005 -// Gerhard de Koning Gans, April 2008, May 2011 -// -// 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. -//----------------------------------------------------------------------------- -// BigBuf and functions to allocate/free parts of it. -//----------------------------------------------------------------------------- - -#ifndef __BIGBUF_H -#define __BIGBUF_H - -#include // for bool -#include "common.h" // for ramfunc - -#define BIGBUF_SIZE 40000 -#define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame -#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8) -#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC -#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these -#define CARD_MEMORY_SIZE 4096 -#define DMA_BUFFER_SIZE 128 - -extern uint8_t *BigBuf_get_addr(void); -extern uint8_t *BigBuf_get_EM_addr(void); -extern uint16_t BigBuf_max_traceLen(void); -extern void BigBuf_Clear(void); -extern void BigBuf_Clear_ext(bool verbose); -extern void BigBuf_Clear_keep_EM(void); -extern void BigBuf_Clear_EM(void); -extern uint8_t *BigBuf_malloc(uint16_t); -extern void BigBuf_free(void); -extern void BigBuf_free_keep_EM(void); -extern void BigBuf_print_status(void); -extern uint16_t BigBuf_get_traceLen(void); -extern void clear_trace(void); -extern void set_tracing(bool enable); -extern bool get_tracing(void); -extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); -extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader); -extern uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length); -#endif /* __BIGBUF_H */ diff --git a/armsrc/Makefile b/armsrc/Makefile index f4ad2ad6..2e5350bb 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -9,136 +9,79 @@ APP_INCLUDES = apps.h #remove one of the following defines and comment out the relevant line -#in the next section to remove that particular feature from compilation -APP_CFLAGS = -DON_DEVICE \ - -fno-strict-aliasing -ffunction-sections -fdata-sections +#in the next section to remove that particular feature from compilation +APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG +#-DWITH_LCD -include ../common/Makefile_Enabled_Options.common +#SRC_LCD = fonts.c LCD.c +SRC_LF = lfops.c hitag2.c +SRC_ISO15693 = iso15693.c iso15693tools.c +SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c +SRC_ISO14443b = iso14443.c +SRC_CRAPTO1 = crapto1.c crypto1.c -ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS))) - SRC_LCD = fonts.c LCD.c -else - SRC_LCD = -endif -SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c -SRC_ISO15693 = iso15693.c -SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c -SRC_ISO14443b = iso14443b.c -SRC_CRAPTO1 = crypto1.c -SRC_DES = platform_util_arm.c des.c -SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c iso15693tools.c -SRC_SMARTCARD = i2c.c - -#the FPGA bitstream files. Note: order matters! -FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit - -#the zlib source files required for decompressing the fpga config at run time -SRC_ZLIB = inflate.c inffast.c inftrees.c adler32.c zutil.c -#additional defines required to compile zlib -ZLIB_CFLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED -APP_CFLAGS += $(ZLIB_CFLAGS) -# zlib includes: -APP_CFLAGS += -I../zlib - -# Compile these in thumb mode (small size) THUMBSRC = start.c \ $(SRC_LCD) \ + $(SRC_ISO15693) \ $(SRC_LF) \ - $(SRC_ZLIB) \ - $(SRC_SMARTCARD) \ - appmain.c \ - printf.c \ + appmain.c printf.c \ util.c \ string.c \ - usb_cdc.c - -# Compile these in thumb mode optimized for speed (still smaller than ARM mode) -THUMBOPTSRC = $(SRC_ISO15693) + usb_cdc.c \ + cmd.c # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ legicrf.c \ - legicrfsim.c \ - legic_prng.c \ + iso14443crc.c \ + crc16.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ - $(SRC_DES) \ - $(SRC_CRC) \ + legic_prng.c \ iclass.c \ - BigBuf.c \ - optimized_cipher.c \ - hfsnoop.c + crc.c -VERSIONSRC = version.c \ - fpga_version_info.c +# stdint.h provided locally until GCC 4.5 becomes C99 compliant +APP_CFLAGS += -I. -# Do not move this inclusion before the definition of {THUMB,THUMBOPT,ASM,ARM}SRC +# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common -OBJS = $(OBJDIR)/fullimage.s19 -FPGA_COMPRESSOR = ../client/fpga_compress +OBJS = $(OBJDIR)/osimage.s19 $(OBJDIR)/fpgaimage.s19 all: $(OBJS) -.DELETE_ON_ERROR: +$(OBJDIR)/fpga.o: fpga.bit + $(OBJCOPY) -O elf32-littlearm -I binary -B arm --redefine-sym _binary____fpga_fpga_bit_start=_binary_fpga_bit_start --redefine-sym _binary____fpga_fpga_bit_end=_binary_fpga_bit_end --prefix-sections=fpga_bit $^ $@ -# version.c and fpga_version_info.c to be remade on every compilation -.PHONY: version.c fpga_version_info.c - -version.c: default_version.c - perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ - -fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@ - -$(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@ - -$(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ - -$(FPGA_COMPRESSOR): - make -C ../client $(notdir $(FPGA_COMPRESSOR)) - -$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(THUMBOPTOBJ) $(ARMOBJ) +$(OBJDIR)/fullimage.elf: $(VERSIONOBJ) $(OBJDIR)/fpga.o $(THUMBOBJ) $(ARMOBJ) $(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS) -$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf - $(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@ +$(OBJDIR)/fpgaimage.elf: $(OBJDIR)/fullimage.elf + $(OBJCOPY) -F elf32-littlearm --only-section .fpgaimage $^ $@ -$(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@ - -$(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf - $(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@ - -$(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR) - $(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ - -$(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z - $(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@ - -$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o - $(CC) $(LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ +$(OBJDIR)/osimage.elf: $(OBJDIR)/fullimage.elf + $(OBJCOPY) -F elf32-littlearm --remove-section .fpgaimage $^ $@ tarbin: $(OBJS) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf) + clean: $(DELETE) $(OBJDIR)$(PATHSEP)*.o $(DELETE) $(OBJDIR)$(PATHSEP)*.elf $(DELETE) $(OBJDIR)$(PATHSEP)*.s19 $(DELETE) $(OBJDIR)$(PATHSEP)*.map $(DELETE) $(OBJDIR)$(PATHSEP)*.d - $(DELETE) $(OBJDIR)$(PATHSEP)*.z - $(DELETE) $(OBJDIR)$(PATHSEP)*.bin - $(DELETE) version.c fpga_version_info.c + $(DELETE) version.c .PHONY: all clean help help: @echo Multi-OS Makefile, you are running on $(DETECTED_OS) @echo Possible targets: - @echo + all - Build the full image $(OBJDIR)/fullimage.s19 - @echo + clean - Clean $(OBJDIR) + @echo + all - Make both: + @echo + $(OBJDIR)/osimage.s19 - The OS image + @echo + $(OBJDIR)/fpgaimage.s19 - The FPGA image + @echo + clean - Clean $(OBJDIR) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 56bf67e0..7af47a51 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -10,41 +10,25 @@ // executes. //----------------------------------------------------------------------------- -#include - #include "usb_cdc.h" +#include "cmd.h" + #include "proxmark3.h" #include "apps.h" -#include "fpga.h" #include "util.h" #include "printf.h" #include "string.h" + +#include + #include "legicrf.h" -#include "legicrfsim.h" -#include "hitag2.h" -#include "hitagS.h" -#include "iclass.h" -#include "iso14443b.h" -#include "iso15693.h" -#include "lfsampling.h" -#include "BigBuf.h" -#include "mifarecmd.h" -#include "mifareutil.h" -#include "mifaresim.h" -#include "pcf7931.h" -#include "i2c.h" -#include "hfsnoop.h" -#include "fpgaloader.h" +#include + #ifdef WITH_LCD - #include "LCD.h" + #include "LCD.h" #endif -static uint32_t hw_capabilities; - -// Craig Young - 14a stand-alone code -#ifdef WITH_ISO14443a - #include "iso14443a.h" -#endif +#define abs(x) ( ((x)<0) ? -(x) : (x) ) //============================================================================= // A buffer where we can queue things up to be sent through the FPGA, for @@ -52,31 +36,38 @@ static uint32_t hw_capabilities; // is the order in which they go out on the wire. //============================================================================= -#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits -uint8_t ToSend[TOSEND_BUFFER_SIZE]; +uint8_t ToSend[512]; int ToSendMax; static int ToSendBit; struct common_area common_area __attribute__((section(".commonarea"))); -void ToSendReset(void) { +void BufferClear(void) +{ + memset(BigBuf,0,sizeof(BigBuf)); + Dbprintf("Buffer cleared (%i bytes)",sizeof(BigBuf)); +} + +void ToSendReset(void) +{ ToSendMax = -1; ToSendBit = 8; } -void ToSendStuffBit(int b) { - if (ToSendBit >= 8) { +void ToSendStuffBit(int b) +{ + if(ToSendBit >= 8) { ToSendMax++; ToSend[ToSendMax] = 0; ToSendBit = 0; } - if (b) { + if(b) { ToSend[ToSendMax] |= (1 << (7 - ToSendBit)); } ToSendBit++; - if (ToSendMax >= sizeof(ToSend)) { + if(ToSendBit >= sizeof(ToSend)) { ToSendBit = 0; DbpString("ToSendStuffBit overflowed!"); } @@ -86,11 +77,47 @@ void ToSendStuffBit(int b) { // Debug print functions, to go out over USB, to the usual PC-side client. //============================================================================= -void DbpString(char *str) { - uint8_t len = strlen(str); - cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(uint8_t*)str,len); +void DbpString(char *str) +{ + byte_t len = strlen(str); + cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len); +// /* this holds up stuff unless we're connected to usb */ +// if (!UsbConnected()) +// return; +// +// UsbCommand c; +// c.cmd = CMD_DEBUG_PRINT_STRING; +// c.arg[0] = strlen(str); +// if(c.arg[0] > sizeof(c.d.asBytes)) { +// c.arg[0] = sizeof(c.d.asBytes); +// } +// memcpy(c.d.asBytes, str, c.arg[0]); +// +// UsbSendPacket((uint8_t *)&c, sizeof(c)); +// // TODO fix USB so stupid things like this aren't req'd +// SpinDelay(50); } +#if 0 +void DbpIntegers(int x1, int x2, int x3) +{ + cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0); +// /* this holds up stuff unless we're connected to usb */ +// if (!UsbConnected()) +// return; +// +// UsbCommand c; +// c.cmd = CMD_DEBUG_PRINT_INTEGERS; +// c.arg[0] = x1; +// c.arg[1] = x2; +// c.arg[2] = x3; +// +// UsbSendPacket((uint8_t *)&c, sizeof(c)); +// // XXX +// SpinDelay(50); +} +#endif + void Dbprintf(const char *fmt, ...) { // should probably limit size here; oh well, let's just use a big buffer char output_string[128]; @@ -107,26 +134,26 @@ void Dbprintf(const char *fmt, ...) { void Dbhexdump(int len, uint8_t *d, bool bAsci) { int l=0,i; char ascii[9]; - + while (len>0) { if (len>8) l=8; else l=len; - + memcpy(ascii,d,l); ascii[l]=0; - + // filter safe ascii - for (i = 0; i < l; i++) - if (ascii[i]<32 || ascii[i]>126) ascii[i] = '.'; - + for (i=0;i126) ascii[i]='.'; + if (bAsci) { - Dbprintf("%-8s %*D",ascii, l, d, " "); + Dbprintf("%-8s %*D",ascii,l,d," "); } else { - Dbprintf("%*D", l, d, " "); + Dbprintf("%*D",l,d," "); } - - len -= 8; - d += 8; + + len-=8; + d+=8; } } @@ -135,31 +162,27 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) { // in ADC units (0 to 1023). Also a routine to average 32 samples and // return that. //----------------------------------------------------------------------------- -static int ReadAdc(int ch) { - // Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value. - // AMPL_HI is a high impedance (10MOhm || 1MOhm) output, the input capacitance of the ADC is 12pF (typical). This results in a time constant - // of RC = (0.91MOhm) * 12pF = 10.9us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged. - // - // The maths are: - // If there is a voltage v_in at the input, the voltage v_cap at the capacitor (this is what we are measuring) will be - // - // v_cap = v_in * (1 - exp(-SHTIM/RC)) = v_in * (1 - exp(-40us/10.9us)) = v_in * 0,97 (i.e. an error of 3%) +static int ReadAdc(int ch) +{ + uint32_t d; AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; AT91C_BASE_ADC->ADC_MR = - ADC_MODE_PRESCALE(63) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz - ADC_MODE_STARTUP_TIME(1) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us - ADC_MODE_SAMPLE_HOLD_TIME(15); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us - + ADC_MODE_PRESCALE(32) | + ADC_MODE_STARTUP_TIME(16) | + ADC_MODE_SAMPLE_HOLD_TIME(8); AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch); + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) + ; + d = AT91C_BASE_ADC->ADC_CDR[ch]; - while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) {}; - - return AT91C_BASE_ADC->ADC_CDR[ch] & 0x3ff; + return d; } -int AvgAdc(int ch) { // was static - merlok{ +int AvgAdc(int ch) // was static - merlok +{ int i; int a = 0; @@ -170,26 +193,17 @@ int AvgAdc(int ch) { // was static - merlok{ return (a + 15) >> 5; } -static int AvgAdc_Voltage_HF(void) { - int AvgAdc_Voltage_Low, AvgAdc_Voltage_High; +void MeasureAntennaTuning(void) +{ + uint8_t *dest = (uint8_t *)BigBuf+FREE_BUFFER_OFFSET; + int i, adcval = 0, peak = 0, peakv = 0, peakf = 0; //ptr = 0 + int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV - AvgAdc_Voltage_Low= (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10; - // if voltage range is about to be exceeded, use high voltage ADC channel if available (RDV40 only) - if (AvgAdc_Voltage_Low > MAX_ADC_HF_VOLTAGE_LOW - 300) { - AvgAdc_Voltage_High = (MAX_ADC_HF_VOLTAGE_HIGH * AvgAdc(ADC_CHAN_HF_HIGH)) >> 10; - if (AvgAdc_Voltage_High >= AvgAdc_Voltage_Low) { - return AvgAdc_Voltage_High; - } - } - return AvgAdc_Voltage_Low; -} +// UsbCommand c; -static int AvgAdc_Voltage_LF(void) { - return (MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10; -} - -void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[]) { - int i, adcval = 0, peak = 0; + LED_B_ON(); + DbpString("Measuring antenna characteristics, please wait..."); + memset(dest,0,sizeof(FREE_BUFFER_SIZE)); /* * Sweeps the useful LF range of the proxmark from @@ -199,94 +213,117 @@ void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv * the resonating frequency of your LF antenna * ( hopefully around 95 if it is tuned to 125kHz!) */ - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - SpinDelay(50); - - for (i = 255; i >= 19; i--) { - WDT_HIT(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + for (i=255; i>19; i--) { + WDT_HIT(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i); SpinDelay(20); - adcval = AvgAdc_Voltage_LF(); - if (i == 95) *vLf125 = adcval; // voltage at 125Khz - if (i == 89) *vLf134 = adcval; // voltage at 134Khz + // Vref = 3.3V, and a 10000:240 voltage divider on the input + // can measure voltages up to 137500 mV + adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10); + if (i==95) vLf125 = adcval; // voltage at 125Khz + if (i==89) vLf134 = adcval; // voltage at 134Khz - LF_Results[i] = adcval >> 9; // scale int to fit in byte for graphing purposes - if (LF_Results[i] > peak) { - *peakv = adcval; - peak = LF_Results[i]; - *peakf = i; + dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes + if(dest[i] > peak) { + peakv = adcval; + peak = dest[i]; + peakf = i; //ptr = i; } } - for (i = 18; i >= 0; i--) LF_Results[i] = 0; - - return; -} - -void MeasureAntennaTuningHfOnly(int *vHf) { + LED_A_ON(); // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(20); - *vHf = AvgAdc_Voltage_HF(); - LED_A_OFF(); - return; -} + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; -void MeasureAntennaTuning(int mode) { - uint8_t LF_Results[256] = {0}; - int peakv = 0, peakf = 0; - int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV +// c.cmd = CMD_MEASURED_ANTENNA_TUNING; +// c.arg[0] = (vLf125 << 0) | (vLf134 << 16); +// c.arg[1] = vHf; +// c.arg[2] = peakf | (peakv << 16); - LED_B_ON(); - - if (((mode & FLAG_TUNE_ALL) == FLAG_TUNE_ALL) && (FpgaGetCurrent() == FPGA_BITSTREAM_HF)) { - // Reverse "standard" order if HF already loaded, to avoid unnecessary swap. - MeasureAntennaTuningHfOnly(&vHf); - MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results); - } else { - if (mode & FLAG_TUNE_LF) { - MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results); - } - if (mode & FLAG_TUNE_HF) { - MeasureAntennaTuningHfOnly(&vHf); - } - } - - cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125>>1 | (vLf134>>1<<16), vHf, peakf | (peakv>>1<<16), LF_Results, 256); + DbpString("Measuring complete, sending report back to host"); + cmd_send(CMD_MEASURED_ANTENNA_TUNING,vLf125|(vLf134<<16),vHf,peakf|(peakv<<16),0,0); +// UsbSendPacket((uint8_t *)&c, sizeof(c)); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_B_OFF(); - return; + LED_A_OFF(); + LED_B_OFF(); + return; } -void MeasureAntennaTuningHf(void) { - int vHf = 0; // in mV +void MeasureAntennaTuningHf(void) +{ + int vHf = 0; // in mV DbpString("Measuring HF antenna, press button to exit"); - // Let the FPGA drive the high-frequency antenna around 13.56 MHz. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - for (;;) { - SpinDelay(500); - vHf = AvgAdc_Voltage_HF(); + // Let the FPGA drive the high-frequency antenna around 13.56 MHz. + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(20); + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; Dbprintf("%d mV",vHf); if (BUTTON_PRESS()) break; } DbpString("cancelled"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - } -void ReadMem(int addr) { +void SimulateTagHfListen(void) +{ + uint8_t *dest = (uint8_t *)BigBuf+FREE_BUFFER_OFFSET; + uint8_t v = 0; + int i; + int p = 0; + + // We're using this mode just so that I can test it out; the simulated + // tag mode would work just as well and be simpler. + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + FpgaSetupSsc(); + + i = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t r = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + v <<= 1; + if(r & 1) { + v |= 1; + } + p++; + + if(p >= 8) { + dest[i] = v; + v = 0; + p = 0; + i++; + + if(i >= FREE_BUFFER_SIZE) { + break; + } + } + } + } + DbpString("simulate tag (now type bitsamples)"); +} + +void ReadMem(int addr) +{ const uint8_t *data = ((uint8_t *)addr); Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x", @@ -296,378 +333,74 @@ void ReadMem(int addr) { /* osimage version information is linked in */ extern struct version_information version_information; /* bootrom version information is pointed to from _bootphase1_version_pointer */ -extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__; - - -void set_hw_capabilities(void) { - if (I2C_is_available()) { - hw_capabilities |= HAS_SMARTCARD_SLOT; - } - - if (false) { // TODO: implement a test - hw_capabilities |= HAS_EXTRA_FLASH_MEM; - } -} - - -void SendVersion(void) { - LED_A_ON(); - set_hw_capabilities(); - - char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ - char VersionString[USB_CMD_DATA_SIZE] = { '\0' }; +extern char *_bootphase1_version_pointer, _flash_start, _flash_end; +void SendVersion(void) +{ + char temp[48]; /* Limited data payload in USB packets */ + DbpString("Prox/RFID mark3 RFID instrument"); /* Try to find the bootrom version information. Expect to find a pointer at * symbol _bootphase1_version_pointer, perform slight sanity checks on the * pointer, then use it. */ char *bootrom_version = *(char**)&_bootphase1_version_pointer; - if (bootrom_version < &_flash_start || bootrom_version >= &_flash_end) { - strcat(VersionString, "bootrom version information appears invalid\n"); + if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) { + DbpString("bootrom version information appears invalid"); } else { FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + DbpString(temp); } FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information); - strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1); + DbpString(temp); - for (int i = 0; i < fpga_bitstream_num; i++) { - strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1); - strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1); - } - - // test availability of SmartCard slot - if (I2C_is_available()) { - strncat(VersionString, "SmartCard Slot: available\n", sizeof(VersionString) - strlen(VersionString) - 1); - } else { - strncat(VersionString, "SmartCard Slot: not available\n", sizeof(VersionString) - strlen(VersionString) - 1); - } - - // Send Chip ID and used flash memory - uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; - uint32_t compressed_data_section_size = common_area.arg1; - cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString) + 1); - LED_A_OFF(); + FpgaGatherVersion(temp, sizeof(temp)); + DbpString(temp); + // Send Chip ID + cmd_send(CMD_ACK,*(AT91C_DBGU_CIDR),0,0,NULL,0); } -// measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. -// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the UsbCommand structure included. -void printUSBSpeed(void) { - Dbprintf("USB Speed:"); - Dbprintf(" Sending USB packets to client..."); - - #define USB_SPEED_TEST_MIN_TIME 1500 // in milliseconds - uint8_t *test_data = BigBuf_get_addr(); - uint32_t end_time; - - uint32_t start_time = end_time = GetTickCount(); - uint32_t bytes_transferred = 0; - - while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) { - cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE); - end_time = GetTickCount(); - bytes_transferred += USB_CMD_DATA_SIZE; - } - - Dbprintf(" Time elapsed: %dms", end_time - start_time); - Dbprintf(" Bytes transferred: %d", bytes_transferred); - Dbprintf(" USB Transfer Speed PM3 -> Client = %d Bytes/s", - 1000 * bytes_transferred / (end_time - start_time)); - -} - -/** - * Prints runtime information about the PM3. -**/ -void SendStatus(void) { - LED_A_ON(); - BigBuf_print_status(); - Fpga_print_status(); -#ifdef WITH_SMARTCARD - I2C_print_status(); -#endif - printConfig(); //LF Sampling config - printUSBSpeed(); - Dbprintf("Various"); - Dbprintf(" MF_DBGLEVEL........%d", MF_DBGLEVEL); - Dbprintf(" ToSendMax..........%d", ToSendMax); - Dbprintf(" ToSendBit..........%d", ToSendBit); - - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - LED_A_OFF(); -} - -#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone) +#ifdef WITH_LF +// samy's sniff and repeat routine +void SamyRun() +{ + DbpString("Stand-alone mode! No PC necessary."); + // 3 possible options? no just 2 for now #define OPTS 2 -void StandAloneMode() { - DbpString("Stand-alone mode! No PC necessary."); + int high[OPTS], low[OPTS]; + // Oooh pretty -- notify user we're in elite samy mode now - LED(LED_RED, 200); + LED(LED_RED, 200); LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); + LED(LED_GREEN, 200); LED(LED_ORANGE, 200); - LED(LED_RED, 200); + LED(LED_RED, 200); LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); + LED(LED_GREEN, 200); LED(LED_ORANGE, 200); - LED(LED_RED, 200); -} + LED(LED_RED, 200); -#endif - - - -#ifdef WITH_ISO14443a_StandAlone -void StandAloneMode14a() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - int selected = 0; - bool playing = false, GotoRecord = false, GotoClone = false; - bool cardRead[OPTS] = {false}; - uint8_t readUID[10] = {0}; - uint32_t uid_1st[OPTS]={0}; - uint32_t uid_2nd[OPTS]={0}; - uint32_t uid_tmp1 = 0; - uint32_t uid_tmp2 = 0; - iso14a_card_select_t hi14a_card[OPTS]; - - LED(selected + 1, 0); - - for (;;) { - usb_poll(); - WDT_HIT(); - SpinDelay(300); - - if (GotoRecord || !cardRead[selected]) { - GotoRecord = false; - LEDsoff(); - LED(selected + 1, 0); - LED(LED_RED2, 0); - - // record - Dbprintf("Enabling iso14443a reader mode for [Bank: %u]...", selected); - /* need this delay to prevent catching some weird data */ - SpinDelay(500); - /* Code for reading from 14a tag */ - uint8_t uid[10] ={0}; - uint32_t cuid; - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - - for ( ; ; ) { - WDT_HIT(); - if (BUTTON_PRESS()) { - if (cardRead[selected]) { - Dbprintf("Button press detected -- replaying card in bank[%d]", selected); - break; - } else if (cardRead[(selected+1)%OPTS]) { - Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS); - selected = (selected+1)%OPTS; - break; - } else { - Dbprintf("Button press detected but no stored tag to play. (Ignoring button)"); - SpinDelay(300); - } - } - if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0, true)) - continue; - else { - Dbprintf("Read UID:"); Dbhexdump(10,uid,0); - memcpy(readUID,uid,10*sizeof(uint8_t)); - uint8_t *dst = (uint8_t *)&uid_tmp1; - // Set UID byte order - for (int i = 0; i < 4; i++) - dst[i] = uid[3-i]; - dst = (uint8_t *)&uid_tmp2; - for (int i = 0; i < 4; i++) - dst[i] = uid[7-i]; - if (uid_1st[(selected+1) % OPTS] == uid_tmp1 && uid_2nd[(selected+1) % OPTS] == uid_tmp2) { - Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping."); - } else { - if (uid_tmp2) { - Dbprintf("Bank[%d] received a 7-byte UID", selected); - uid_1st[selected] = (uid_tmp1)>>8; - uid_2nd[selected] = (uid_tmp1<<24) + (uid_tmp2>>8); - } else { - Dbprintf("Bank[%d] received a 4-byte UID", selected); - uid_1st[selected] = uid_tmp1; - uid_2nd[selected] = uid_tmp2; - } - break; - } - } - } - Dbprintf("ATQA = %02X%02X", hi14a_card[selected].atqa[0], hi14a_card[selected].atqa[1]); - Dbprintf("SAK = %02X", hi14a_card[selected].sak); - LEDsoff(); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); - LED(LED_GREEN, 200); - LED(LED_ORANGE, 200); - - LEDsoff(); - LED(selected + 1, 0); - - // Next state is replay: - playing = true; - - cardRead[selected] = true; - } else if (GotoClone) { /* MF Classic UID clone */ - GotoClone=false; - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 250); - - - // record - Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]); - - // wait for button to be released - while(BUTTON_PRESS()) { - // Delay cloning until card is in place - WDT_HIT(); - } - Dbprintf("Starting clone. [Bank: %u]", selected); - // need this delay to prevent catching some weird data - SpinDelay(500); - // Begin clone function here: - /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards: - UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; - memcpy(c.d.asBytes, data, 16); - SendCommand(&c); - - Block read is similar: - UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; - We need to imitate that call with blockNo 0 to set a uid. - - The get and set commands are handled in this file: - // Work with "magic Chinese" card - case CMD_MIFARE_CSETBLOCK: - MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_CGETBLOCK: - MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - - mfCSetUID provides example logic for UID set workflow: - -Read block0 from card in field with MifareCGetBlock() - -Configure new values without replacing reserved bytes - memcpy(block0, uid, 4); // Copy UID bytes from byte array - // Mifare UID BCC - block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5 - Bytes 5-7 are reserved SAK and ATQA for mifare classic - -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it - */ - uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0}; - // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo - MifareCGetBlock(0x3F, 1, 0, oldBlock0); - if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) { - Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected); - playing = true; - } else { - Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]); - memcpy(newBlock0, oldBlock0, 16); - // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic) - - newBlock0[0] = uid_1st[selected] >> 24; - newBlock0[1] = 0xFF & (uid_1st[selected] >> 16); - newBlock0[2] = 0xFF & (uid_1st[selected] >> 8); - newBlock0[3] = 0xFF & (uid_1st[selected]); - newBlock0[4] = newBlock0[0] ^ newBlock0[1] ^ newBlock0[2] ^ newBlock0[3]; - // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain - MifareCSetBlock(0, 0xFF, 0, newBlock0); - MifareCGetBlock(0x3F, 1, 0, testBlock0); - if (memcmp(testBlock0, newBlock0, 16) == 0) { - DbpString("Cloned successfull!"); - cardRead[selected] = false; // Only if the card was cloned successfully should we clear it - playing = false; - GotoRecord = true; - selected = (selected+1) % OPTS; - } else { - Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected); - playing = true; - } - } - LEDsoff(); - LED(selected + 1, 0); - - } else if (playing) { - // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) - // Change where to record (or begin playing) - LEDsoff(); - LED(selected + 1, 0); - - // Begin transmitting - LED(LED_GREEN, 0); - DbpString("Playing"); - for ( ; ; ) { - WDT_HIT(); - int button_action = BUTTON_HELD(1000); - if (button_action == 0) { // No button action, proceed with sim - uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break - Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected], uid_2nd[selected], selected); - if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) { - DbpString("Mifare Classic"); - SimulateIso14443aTag(1, uid_1st[selected], uid_2nd[selected], data); // Mifare Classic - } else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) { - DbpString("Mifare Ultralight"); - SimulateIso14443aTag(2, uid_1st[selected], uid_2nd[selected], data); // Mifare Ultralight - } else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) { - DbpString("Mifare DESFire"); - SimulateIso14443aTag(3, uid_1st[selected], uid_2nd[selected], data); // Mifare DESFire - } else { - Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); - SimulateIso14443aTag(1, uid_1st[selected], uid_2nd[selected], data); - } - } else if (button_action == BUTTON_SINGLE_CLICK) { - selected = (selected + 1) % OPTS; - Dbprintf("Done playing. Switching to record mode on bank %d",selected); - GotoRecord = true; - break; - } else if (button_action == BUTTON_HOLD) { - Dbprintf("Playtime over. Begin cloning..."); - GotoClone = true; - break; - } - WDT_HIT(); - } - - /* We pressed a button so ignore it here with a delay */ - SpinDelay(300); - LEDsoff(); - LED(selected + 1, 0); - } - } -} - -#elif WITH_LF_StandAlone - -// samy's sniff and repeat routine -void SamyRun() { - StandAloneMode(); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - int tops[OPTS], high[OPTS], low[OPTS]; int selected = 0; int playing = 0; - int cardRead = 0; // Turn on selected LED LED(selected + 1, 0); - for (;;) { + for (;;) + { +// UsbPoll(FALSE); usb_poll(); - WDT_HIT(); + WDT_HIT(); // Was our button held down or pressed? int button_pressed = BUTTON_HELD(1000); SpinDelay(300); // Button was held for a second, begin recording - if (button_pressed > 0 && cardRead == 0) { + if (button_pressed > 0) + { LEDsoff(); LED(selected + 1, 0); LED(LED_RED2, 0); @@ -682,11 +415,8 @@ void SamyRun() { /* need this delay to prevent catching some weird data */ SpinDelay(500); - CmdHIDdemodFSK(1, &tops[selected], &high[selected], &low[selected], 0); - if (tops[selected] > 0) - Dbprintf("Recorded %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); - else - Dbprintf("Recorded %x %x%08x", selected, high[selected], low[selected]); + CmdHIDdemodFSK(1, &high[selected], &low[selected], 0); + Dbprintf("Recorded %x %x %x", selected, high[selected], low[selected]); LEDsoff(); LED(selected + 1, 0); @@ -695,46 +425,11 @@ void SamyRun() { // If we were previously playing, set playing off // so next button push begins playing what we recorded playing = 0; + } - cardRead = 1; - - } else if (button_pressed > 0 && cardRead == 1) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 0); - - // record - if (tops[selected] > 0) - Dbprintf("Cloning %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); - else - Dbprintf("Cloning %x %x%08x", selected, high[selected], low[selected]); - - // wait for button to be released - while(BUTTON_PRESS()) - WDT_HIT(); - - /* need this delay to prevent catching some weird data */ - SpinDelay(500); - - CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)), 0x1D); - if (tops[selected] > 0) - Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); - else - Dbprintf("Cloned %x %x%08x", selected, high[selected], low[selected]); - - LEDsoff(); - LED(selected + 1, 0); - // Finished recording - - // If we were previously playing, set playing off - // so next button push begins playing what we recorded - playing = 0; - - cardRead = 0; - - } else if (button_pressed) { - - // Change where to record (or begin playing) + // Change where to record (or begin playing) + else if (button_pressed) + { // Next option if we were previously playing if (playing) selected = (selected + 1) % OPTS; @@ -744,24 +439,22 @@ void SamyRun() { LED(selected + 1, 0); // Begin transmitting - if (playing) { + if (playing) + { LED(LED_GREEN, 0); DbpString("Playing"); // wait for button to be released while(BUTTON_PRESS()) WDT_HIT(); - if (tops[selected] > 0) - Dbprintf("%x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); - else - Dbprintf("%x %x%08x", selected, high[selected], low[selected]); - - CmdHIDsimTAG(tops[selected], high[selected], low[selected], 0); + Dbprintf("%x %x %x", selected, high[selected], low[selected]); + CmdHIDsimTAG(high[selected], low[selected], 0); DbpString("Done playing"); - if (BUTTON_HELD(1000) > 0) { + if (BUTTON_HELD(1000) > 0) + { DbpString("Exiting"); LEDsoff(); return; - } + } /* We pressed a button so ignore it here with a delay */ SpinDelay(300); @@ -771,13 +464,13 @@ void SamyRun() { playing = !playing; LEDsoff(); LED(selected + 1, 0); - } else + } + else while(BUTTON_PRESS()) WDT_HIT(); } } } - #endif /* @@ -815,44 +508,36 @@ static const char LIGHT_SCHEME[] = { 0xE, /* -XXX | 86% of maximum current detected */ 0xF, /* XXXX | 100% of maximum current detected */ }; - static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]); -void ListenReaderField(int limit) { - int lf_av, lf_av_new=0, lf_baseline= 0, lf_max; - int hf_av, hf_av_new=0, hf_baseline= 0, hf_max; +void ListenReaderField(int limit) +{ + int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max; + int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max; int mode=1, display_val, display_max, i; -#define LF_ONLY 1 -#define HF_ONLY 2 -#define REPORT_CHANGE_PERCENT 5 // report new values only if they have changed at least by REPORT_CHANGE_PERCENT -#define MIN_HF_FIELD 300 // in mode 1 signal HF field greater than MIN_HF_FIELD above baseline -#define MIN_LF_FIELD 1200 // in mode 1 signal LF field greater than MIN_LF_FIELD above baseline - - - // switch off FPGA - we don't want to measure our own signal - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +#define LF_ONLY 1 +#define HF_ONLY 2 LEDsoff(); - lf_av = lf_max = AvgAdc_Voltage_LF(); + lf_av=lf_max=ReadAdc(ADC_CHAN_LF); - if (limit != HF_ONLY) { - Dbprintf("LF 125/134kHz Baseline: %dmV", lf_av); + if(limit != HF_ONLY) { + Dbprintf("LF 125/134 Baseline: %d", lf_av); lf_baseline = lf_av; } - hf_av = hf_max = AvgAdc_Voltage_HF(); + hf_av=hf_max=ReadAdc(ADC_CHAN_HF); if (limit != LF_ONLY) { - Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av); + Dbprintf("HF 13.56 Baseline: %d", hf_av); hf_baseline = hf_av; } for(;;) { - SpinDelay(500); if (BUTTON_PRESS()) { + SpinDelay(500); switch (mode) { case 1: mode=2; @@ -865,49 +550,46 @@ void ListenReaderField(int limit) { return; break; } - while (BUTTON_PRESS()) - /* wait */; } WDT_HIT(); if (limit != HF_ONLY) { - if(mode == 1) { - if (lf_av - lf_baseline > MIN_LF_FIELD) - LED_D_ON(); - else - LED_D_OFF(); + if(mode==1) { + if (abs(lf_av - lf_baseline) > 10) LED_D_ON(); + else LED_D_OFF(); } - lf_av_new = AvgAdc_Voltage_LF(); + ++lf_count; + lf_av_new= ReadAdc(ADC_CHAN_LF); // see if there's a significant change - if (ABS((lf_av - lf_av_new) * 100 / (lf_av?lf_av:1)) > REPORT_CHANGE_PERCENT) { - Dbprintf("LF 125/134kHz Field Change: %5dmV", lf_av_new); + if(abs(lf_av - lf_av_new) > 10) { + Dbprintf("LF 125/134 Field Change: %x %x %x", lf_av, lf_av_new, lf_count); lf_av = lf_av_new; if (lf_av > lf_max) lf_max = lf_av; + lf_count= 0; } } if (limit != LF_ONLY) { if (mode == 1){ - if (hf_av - hf_baseline > MIN_HF_FIELD) - LED_B_ON(); - else - LED_B_OFF(); + if (abs(hf_av - hf_baseline) > 10) LED_B_ON(); + else LED_B_OFF(); } - hf_av_new = AvgAdc_Voltage_HF(); - + ++hf_count; + hf_av_new= ReadAdc(ADC_CHAN_HF); // see if there's a significant change - if (ABS((hf_av - hf_av_new) * 100 / (hf_av?hf_av:1)) > REPORT_CHANGE_PERCENT) { - Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new); + if(abs(hf_av - hf_av_new) > 10) { + Dbprintf("HF 13.56 Field Change: %x %x %x", hf_av, hf_av_new, hf_count); hf_av = hf_av_new; if (hf_av > hf_max) hf_max = hf_av; + hf_count= 0; } } - if (mode == 2) { + if(mode == 2) { if (limit == LF_ONLY) { display_val = lf_av; display_max = lf_max; @@ -923,8 +605,8 @@ void ListenReaderField(int limit) { display_max = lf_max; } } - for (i = 0; i < LIGHT_LEN; i++) { - if (display_val >= (display_max / LIGHT_LEN * i) && display_val <= (display_max / LIGHT_LEN * (i+1))) { + for (i=0; i= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) { if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF(); if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF(); if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF(); @@ -936,55 +618,35 @@ void ListenReaderField(int limit) { } } - -void UsbPacketReceived(UsbCommand *c) { +void UsbPacketReceived(uint8_t *packet, int len) +{ + UsbCommand *c = (UsbCommand *)packet; // Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]); - + switch(c->cmd) { #ifdef WITH_LF - case CMD_SET_LF_SAMPLING_CONFIG: - setSamplingConfig(c->d.asBytes); - break; case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: - cmd_send(CMD_ACK,SampleLF(c->arg[0], c->arg[1]),0,0,0,0); + AcquireRawAdcSamples125k(c->arg[0]); + cmd_send(CMD_ACK,0,0,0,0,0); break; case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K: ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); break; - case CMD_LF_SNOOP_RAW_ADC_SAMPLES: - cmd_send(CMD_ACK,SnoopLF(),0,0,0,0); - break; case CMD_HID_DEMOD_FSK: - CmdHIDdemodFSK(c->arg[0], 0, 0, 0, 1); + CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag break; case CMD_HID_SIM_TAG: - CmdHIDsimTAG(c->arg[0], c->arg[1], c->arg[2], 1); + CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID break; - case CMD_FSK_SIM_TAG: - CmdFSKsimTAG(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_ASK_SIM_TAG: - CmdASKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_PSK_SIM_TAG: - CmdPSKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_HID_CLONE_TAG: - CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x1D); - break; - case CMD_PARADOX_CLONE_TAG: - // Paradox cards are the same as HID, with a different preamble, so we can reuse the same function - CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x0F); + case CMD_HID_CLONE_TAG: // Clone HID tag by ID to T55x7 + CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); break; case CMD_IO_DEMOD_FSK: - CmdIOdemodFSK(c->arg[0], 0, 0, 1); + CmdIOdemodFSK(1, 0, 0, 1); // Demodulate IO tag break; - case CMD_IO_CLONE_TAG: - CopyIOtoT55x7(c->arg[0], c->arg[1]); - break; - case CMD_EM410X_DEMOD: - CmdEM410xdemod(c->arg[0], 0, 0, 1); + case CMD_IO_CLONE_TAG: // Clone IO tag by ID to T55x7 + CopyIOtoT55x7(c->arg[0], c->arg[1], c->d.asBytes[0]); break; case CMD_EM410X_WRITE_TAG: WriteEM410x(c->arg[0], c->arg[1], c->arg[2]); @@ -1003,50 +665,31 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_LF_SIMULATE_BIDIR: SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]); break; - case CMD_INDALA_CLONE_TAG: - CopyIndala64toT55x7(c->arg[0], c->arg[1]); + case CMD_INDALA_CLONE_TAG: // Clone Indala 64-bit tag by UID to T55x7 + CopyIndala64toT55x7(c->arg[0], c->arg[1]); break; - case CMD_INDALA_CLONE_TAG_L: + case CMD_INDALA_CLONE_TAG_L: // Clone Indala 224-bit tag by UID to T55x7 CopyIndala224toT55x7(c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6]); break; case CMD_T55XX_READ_BLOCK: - T55xxReadBlock(c->arg[0], c->arg[1], c->arg[2]); + T55xxReadBlock(c->arg[1], c->arg[2],c->d.asBytes[0]); break; case CMD_T55XX_WRITE_BLOCK: T55xxWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); break; - case CMD_T55XX_WAKEUP: - T55xxWakeUp(c->arg[0]); + case CMD_T55XX_READ_TRACE: // Clone HID tag by ID to T55x7 + T55xxReadTrace(); break; - case CMD_T55XX_RESET_READ: - T55xxResetRead(); - break; - case CMD_PCF7931_READ: + case CMD_PCF7931_READ: // Read PCF7931 tag ReadPCF7931(); - break; - case CMD_PCF7931_WRITE: - WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_PCF7931_BRUTEFORCE: - BruteForcePCF7931(c->arg[0], (c->arg[1] & 0xFF), c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128); + cmd_send(CMD_ACK,0,0,0,0,0); +// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); break; case CMD_EM4X_READ_WORD: - EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]); + EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]); break; case CMD_EM4X_WRITE_WORD: - EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_EM4X_PROTECT: - EM4xProtect(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation - CmdAWIDdemodFSK(c->arg[0], 0, 0, 1); - break; - case CMD_VIKING_CLONE_TAG: - CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]); - break; - case CMD_COTAG: - Cotag(c->arg[0]); + EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); break; #endif @@ -1055,50 +698,29 @@ void UsbPacketReceived(UsbCommand *c) { SnoopHitag(c->arg[0]); break; case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content - SimulateHitagTag((bool)c->arg[0], (uint8_t*)c->d.asBytes); + SimulateHitagTag((bool)c->arg[0],(byte_t*)c->d.asBytes); break; case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); break; - case CMD_SIMULATE_HITAG_S:// Simulate Hitag s tag, args = memory content - SimulateHitagSTag((bool)c->arg[0],(uint8_t*)c->d.asBytes); - break; - case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file - check_challenges_cmd((bool)c->arg[0], (uint8_t*)c->d.asBytes, (uint8_t)c->arg[1]); - break; - case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge - ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], false); - break; - case CMD_READ_HITAG_S_BLK: - ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], true); - break; - case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge - if ((hitag_function)c->arg[0] < 10) { - WritePageHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes,c->arg[2]); - } - else if ((hitag_function)c->arg[0] >= 10) { - WriterHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes, c->arg[2]); - } - break; #endif - + #ifdef WITH_ISO15693 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: AcquireRawAdcSamplesIso15693(); break; - - case CMD_SNOOP_ISO_15693: - SnoopIso15693(0, NULL); + case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693: + RecordRawAdcSamplesIso15693(); break; - + case CMD_ISO_15693_COMMAND: DirectTag15693Command(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); break; - + case CMD_ISO_15693_FIND_AFI: BruteforceIso15693Afi(c->arg[0]); - break; - + break; + case CMD_ISO_15693_DEBUG: SetDebugIso15693(c->arg[0]); break; @@ -1106,19 +728,14 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_READER_ISO_15693: ReaderIso15693(c->arg[0]); break; - case CMD_SIMTAG_ISO_15693: - SimTagIso15693(c->arg[0], c->d.asBytes); - break; - - case CMD_CSETUID_ISO_15693: - SetTag15693Uid(c->d.asBytes); + SimTagIso15693(c->arg[0]); break; #endif #ifdef WITH_LEGICRF case CMD_SIMULATE_TAG_LEGIC_RF: - LegicRfSimulate(c->arg[0]); + LegicRfSimulate(c->arg[0], c->arg[1], c->arg[2]); break; case CMD_WRITER_LEGIC_RF: @@ -1131,17 +748,20 @@ void UsbPacketReceived(UsbCommand *c) { #endif #ifdef WITH_ISO14443b + case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: + AcquireRawAdcSamplesIso14443(c->arg[0]); + break; case CMD_READ_SRI512_TAG: - ReadSTMemoryIso14443b(0x0F); + ReadSTMemoryIso14443(0x0F); break; case CMD_READ_SRIX4K_TAG: - ReadSTMemoryIso14443b(0x7F); + ReadSTMemoryIso14443(0x7F); break; - case CMD_SNOOP_ISO_14443B: - SnoopIso14443b(); + case CMD_SNOOP_ISO_14443: + SnoopIso14443(); break; - case CMD_SIMULATE_TAG_ISO_14443B: - SimulateIso14443bTag(); + case CMD_SIMULATE_TAG_ISO_14443: + SimulateIso14443Tag(); break; case CMD_ISO_14443B_COMMAND: SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); @@ -1158,50 +778,34 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_SIMULATE_TAG_ISO_14443a: SimulateIso14443aTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); // ## Simulate iso14443a tag - pass tag type & UID break; - case CMD_EPA_PACE_COLLECT_NONCE: EPA_PACE_Collect_Nonce(c); break; - case CMD_EPA_PACE_REPLAY: - EPA_PACE_Replay(c); - break; - + case CMD_READER_MIFARE: - ReaderMifare(c->arg[0]); + ReaderMifare(c->arg[0]); break; case CMD_MIFARE_READBL: MifareReadBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_MIFAREU_READBL: - MifareUReadBlock(c->arg[0],c->arg[1], c->d.asBytes); - break; - case CMD_MIFAREUC_AUTH: - MifareUC_Auth(c->arg[0],c->d.asBytes); + MifareUReadBlock(c->arg[0],c->d.asBytes); break; case CMD_MIFAREU_READCARD: - MifareUReadCard(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFAREUC_SETPWD: - MifareUSetPwd(c->arg[0], c->d.asBytes); - break; + MifareUReadCard(c->arg[0],c->d.asBytes); + break; case CMD_MIFARE_READSC: MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_MIFARE_WRITEBL: MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - case CMD_MIFARE_PERSONALIZE_UID: - MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes); - break; - //case CMD_MIFAREU_WRITEBL_COMPAT: - //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes); - //break; + case CMD_MIFAREU_WRITEBL_COMPAT: + MifareUWriteBlock(c->arg[0], c->d.asBytes); + break; case CMD_MIFAREU_WRITEBL: - MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes); - break; - case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES: - MifareAcquireEncryptedNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; + MifareUWriteBlock_Special(c->arg[0], c->d.asBytes); + break; case CMD_MIFARE_NESTED: MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; @@ -1209,9 +813,9 @@ void UsbPacketReceived(UsbCommand *c) { MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_SIMULATE_MIFARE_CARD: - MifareSim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - + // emulator case CMD_MIFARE_SET_DBGMODE: MifareSetDbgLvl(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); @@ -1228,103 +832,44 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_MIFARE_EML_CARDLOAD: MifareECardLoad(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - + // Work with "magic Chinese" card - case CMD_MIFARE_CWIPE: - MifareCWipe(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_CSETBLOCK: + case CMD_MIFARE_EML_CSETBLOCK: MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - case CMD_MIFARE_CGETBLOCK: + case CMD_MIFARE_EML_CGETBLOCK: MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; - case CMD_MIFARE_CIDENT: - MifareCIdent(); - break; - + // mifare sniffer case CMD_MIFARE_SNIFFER: SniffMifare(c->arg[0]); break; - #endif #ifdef WITH_ICLASS // Makes use of ISO14443a FPGA Firmware case CMD_SNOOP_ICLASS: - SnoopIClass(c->arg[0], c->d.asBytes); + SnoopIClass(); break; case CMD_SIMULATE_TAG_ICLASS: - SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + SimulateIClass(c->arg[0], c->d.asBytes); break; case CMD_READER_ICLASS: ReaderIClass(c->arg[0]); break; - case CMD_ICLASS_EML_MEMSET: - emlSet(c->d.asBytes,c->arg[0], c->arg[1]); - break; - case CMD_ICLASS_WRITEBLOCK: - iClass_WriteBlock(c->arg[0], c->d.asBytes); - break; - case CMD_ICLASS_READBLOCK: - iClass_ReadBlk(c->arg[0]); - break; - case CMD_ICLASS_CHECK: - iClass_Check(c->d.asBytes); - break; - case CMD_ICLASS_READCHECK: - iClass_Readcheck(c->arg[0], c->arg[1]); - break; - case CMD_ICLASS_DUMP: - iClass_Dump(c->arg[0], c->arg[1]); - break; - case CMD_ICLASS_CLONE: - iClass_Clone(c->arg[0], c->arg[1], c->d.asBytes); - break; #endif -#ifdef WITH_HFSNOOP - case CMD_HF_SNIFFER: - HfSnoop(c->arg[0], c->arg[1]); + case CMD_SIMULATE_TAG_HF_LISTEN: + SimulateTagHfListen(); break; - case CMD_HF_PLOT: - HfPlot(); - break; -#endif - -#ifdef WITH_SMARTCARD - case CMD_SMART_ATR: { - SmartCardAtr(); - break; - } - case CMD_SMART_SETCLOCK:{ - SmartCardSetClock(c->arg[0]); - break; - } - case CMD_SMART_RAW: { - SmartCardRaw(c->arg[0], c->arg[1], c->d.asBytes); - break; - } - case CMD_SMART_UPLOAD: { - // upload file from client - uint8_t *mem = BigBuf_get_addr(); - memcpy( mem + c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE); - cmd_send(CMD_ACK,1,0,0,0,0); - break; - } - case CMD_SMART_UPGRADE: { - SmartCardUpgrade(c->arg[0]); - break; - } -#endif case CMD_BUFF_CLEAR: - BigBuf_Clear(); + BufferClear(); break; case CMD_MEASURE_ANTENNA_TUNING: - MeasureAntennaTuning(c->arg[0]); + MeasureAntennaTuning(); break; case CMD_MEASURE_ANTENNA_TUNING_HF: @@ -1335,47 +880,49 @@ void UsbPacketReceived(UsbCommand *c) { ListenReaderField(c->arg[0]); break; - case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control - LED_A_ON(); + case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); LED_D_OFF(); // LED D indicates field ON or OFF - LED_A_OFF(); break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: +// UsbCommand n; +// if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) { +// n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K; +// } else { +// n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE; +// } +// n.arg[0] = c->arg[0]; + // memcpy(n.d.asBytes, BigBuf+c->arg[0], 48); // 12*sizeof(uint32_t) + // LED_B_ON(); + // usb_write((uint8_t *)&n, sizeof(n)); + // UsbSendPacket((uint8_t *)&n, sizeof(n)); + // LED_B_OFF(); + LED_B_ON(); - uint8_t *BigBuf = BigBuf_get_addr(); for(size_t i=0; iarg[1]; i += USB_CMD_DATA_SIZE) { size_t len = MIN((c->arg[1] - i),USB_CMD_DATA_SIZE); - cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,i,len,BigBuf_get_traceLen(),BigBuf+c->arg[0]+i,len); + cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,i,len,0,((byte_t*)BigBuf)+c->arg[0]+i,len); } // Trigger a finish downloading signal with an ACK frame - cmd_send(CMD_ACK,1,0,BigBuf_get_traceLen(),getSamplingConfig(),sizeof(sample_config)); + cmd_send(CMD_ACK,0,0,0,0,0); LED_B_OFF(); break; case CMD_DOWNLOADED_SIM_SAMPLES_125K: { - // iceman; since changing fpga_bitstreams clears bigbuff, Its better to call it before. - // to be able to use this one for uploading data to device - // arg1 = 0 upload for LF usage - // 1 upload for HF usage - if (c->arg[1] == 0) - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - else - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - uint8_t *b = BigBuf_get_addr(); - memcpy(b+c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE); + uint8_t *b = (uint8_t *)BigBuf; + memcpy(b+c->arg[0], c->d.asBytes, 48); + //Dbprintf("copied 48 bytes to %i",b+c->arg[0]); +// UsbSendPacket((uint8_t*)&ack, sizeof(ack)); cmd_send(CMD_ACK,0,0,0,0,0); break; - } + } case CMD_READ_MEM: ReadMem(c->arg[0]); break; case CMD_SET_LF_DIVISOR: - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]); break; @@ -1391,12 +938,7 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_VERSION: SendVersion(); break; - case CMD_STATUS: - SendStatus(); - break; - case CMD_PING: - cmd_send(CMD_ACK,0,0,0,0,0); - break; + #ifdef WITH_LCD case CMD_LCD_RESET: LCDReset(); @@ -1429,7 +971,8 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_DEVICE_INFO: { uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS; if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT; - cmd_send_old(CMD_DEVICE_INFO,dev_info,0,0,0,0); +// UsbSendPacket((uint8_t*)&c, sizeof(c)); + cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0); break; } default: @@ -1438,11 +981,10 @@ void UsbPacketReceived(UsbCommand *c) { } } - -void __attribute__((noreturn)) AppMain(void) { - +void __attribute__((noreturn)) AppMain(void) +{ SpinDelay(100); - clear_trace(); + if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) { /* Initialize common area */ memset(&common_area, 0, sizeof(common_area)); @@ -1451,10 +993,14 @@ void __attribute__((noreturn)) AppMain(void) { } common_area.flags.osimage_present = 1; - LEDsoff(); + LED_D_OFF(); + LED_C_OFF(); + LED_B_OFF(); + LED_A_OFF(); - // Init USB device - usb_enable(); + // Init USB device` + usb_enable(); +// UsbStart(); // The FPGA gets its clock from us from PCK0 output, so set that up. AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; @@ -1462,39 +1008,40 @@ void __attribute__((noreturn)) AppMain(void) { AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0; // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK | - AT91C_PMC_PRES_CLK_4; // 4 for 24Mhz pck0, 2 for 48 MHZ pck0 + AT91C_PMC_PRES_CLK_4; AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0; // Reset SPI AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; - AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; // required twice on some AT91SAM Revisions (see Errata in AT91SAM datasheet) // Reset SSC AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - // Load the FPGA image, which we have stored in our flash (HF version by default) - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - StartTickCount(); + // Load the FPGA image, which we have stored in our flash. + FpgaDownloadAndGo(); + StartTickCount(); + #ifdef WITH_LCD LCDInit(); #endif - UsbCommand rx; + byte_t rx[sizeof(UsbCommand)]; + size_t rx_len; for(;;) { + if (usb_poll()) { + rx_len = usb_read(rx,sizeof(UsbCommand)); + if (rx_len) { + UsbPacketReceived(rx,rx_len); + } + } +// UsbPoll(FALSE); + WDT_HIT(); - if (cmd_receive(&rx)) { - UsbPacketReceived(&rx); - } else { -#if defined(WITH_LF_StandAlone) && !defined(WITH_ISO14443a_StandAlone) - if (BUTTON_HELD(1000) > 0) - SamyRun(); + +#ifdef WITH_LF + if (BUTTON_HELD(1000) > 0) + SamyRun(); #endif -#if defined(WITH_ISO14443a) && defined(WITH_ISO14443a_StandAlone) - if (BUTTON_HELD(1000) > 0) - StandAloneMode14a(); -#endif - } } } diff --git a/armsrc/apps.h b/armsrc/apps.h index 0431d2ee..e21b5ce5 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -15,16 +15,35 @@ #include #include #include "common.h" -#include "usb_cmd.h" -#include "hitagS.h" +#include "hitag2.h" #include "mifare.h" -#include "../common/crc32.h" -#include "BigBuf.h" + +// The large multi-purpose buffer, typically used to hold A/D samples, +// maybe processed in some way. +uint32_t BigBuf[10000]; +// BIG CHANGE - UNDERSTAND THIS BEFORE WE COMMIT +#define TRACE_OFFSET 0 +#define TRACE_SIZE 3000 +#define RECV_CMD_OFFSET 3032 +#define RECV_CMD_SIZE 64 +#define RECV_RES_OFFSET 3096 +#define RECV_RES_SIZE 64 +#define DMA_BUFFER_OFFSET 3160 +#define DMA_BUFFER_SIZE 4096 +#define FREE_BUFFER_OFFSET 7256 +#define FREE_BUFFER_SIZE 2744 extern const uint8_t OddByteParity[256]; +extern uint8_t *trace; // = (uint8_t *) BigBuf; +extern int traceLen; // = 0; extern int rsamples; // = 0; +extern int tracing; // = TRUE; extern uint8_t trigger; +// This may be used (sparingly) to declare a function to be copied to +// and executed from RAM +#define RAMFUNC __attribute((long_call, section(".ramfunc"))) + /// appmain.h void ReadMem(int addr); void __attribute__((noreturn)) AppMain(void); @@ -34,82 +53,153 @@ void DbpString(char *str); void Dbprintf(const char *fmt, ...); void Dbhexdump(int len, uint8_t *d, bool bAsci); -// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV -#define MAX_ADC_HF_VOLTAGE_LOW 36300 -// ADC Vref = 3300mV, and an (10000k+240k):240k voltage divider on the LF input can measure voltages up to 140800 mV -#define MAX_ADC_HF_VOLTAGE_HIGH 140800 -#define MAX_ADC_LF_VOLTAGE 140800 int AvgAdc(int ch); void ToSendStuffBit(int b); void ToSendReset(void); void ListenReaderField(int limit); +void AcquireRawAdcSamples125k(int at134khz); +void DoAcquisition125k(void); extern int ToSendMax; extern uint8_t ToSend[]; +extern uint32_t BigBuf[]; +/// fpga.h +void FpgaSendCommand(uint16_t cmd, uint16_t v); +void FpgaWriteConfWord(uint8_t v); +void FpgaDownloadAndGo(void); +void FpgaGatherVersion(char *dst, int len); +void FpgaSetupSsc(void); +void SetupSpi(int mode); +bool FpgaSetupSscDma(uint8_t *buf, int len); +#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; +#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; +void SetAdcMuxFor(uint32_t whichGpio); + +// Definitions for the FPGA commands. +#define FPGA_CMD_SET_CONFREG (1<<12) +#define FPGA_CMD_SET_DIVISOR (2<<12) +// Definitions for the FPGA configuration word. +#define FPGA_MAJOR_MODE_LF_READER (0<<5) +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) +#define FPGA_MAJOR_MODE_HF_READER_TX (2<<5) +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (3<<5) +#define FPGA_MAJOR_MODE_HF_SIMULATOR (4<<5) +#define FPGA_MAJOR_MODE_HF_ISO14443A (5<<5) +#define FPGA_MAJOR_MODE_LF_PASSTHRU (6<<5) +#define FPGA_MAJOR_MODE_OFF (7<<5) +// Options for LF_EDGE_DETECT +#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) +// Options for the HF reader, tx to tag +#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) +// Options for the HF reader, correlating against rx from tag +#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) +#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) +#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) +// Options for the HF simulated tag, how to modulate +#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) +#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) +#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) +// Options for ISO14443A +#define FPGA_HF_ISO14443A_SNIFFER (0<<0) +#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) +#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) +#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) +#define FPGA_HF_ISO14443A_READER_MOD (4<<0) /// lfops.h -extern uint8_t decimation; -extern uint8_t bits_per_sample ; -extern bool averaging; - void AcquireRawAdcSamples125k(int divisor); -void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command); +void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,uint8_t *command); void ReadTItag(void); void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); - void AcquireTiType(void); void AcquireRawBitsTI(void); void SimulateTagLowFrequency(int period, int gap, int ledcontrol); -void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); -void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol); -void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); -void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); -void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream); -void CmdHIDdemodFSK(int findone, int *high2, int *high, int *low, int ledcontrol); -void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol); // Realtime demodulation mode for AWID26 -void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol); +void CmdHIDsimTAG(int hi, int lo, int ledcontrol); +void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); -void CopyIOtoT55x7(uint32_t hi, uint32_t lo); // Clone an ioProx card to T5557/T5567 -void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble); // Clone an HID-like card to T5557/T5567 -void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5); +void CopyIOtoT55x7(uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an ioProx card to T5557/T5567 +void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen); +void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567 void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo); -void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7 -void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7); // Clone Indala 224-bit tag by UID to T55x7 -void T55xxResetRead(void); +void CopyIndala64toT55x7(int hi, int lo); // Clone Indala 64-bit tag by UID to T55x7 +void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7); // Clone Indala 224-bit tag by UID to T55x7 void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode); -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd); -void T55xxWakeUp(uint32_t Pwd); -void TurnReadLFOn(); -//void T55xxReadTrace(void); +void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode ); +void T55xxReadTrace(void); +int DemodPCF7931(uint8_t **outBlocks); +int IsBlock0PCF7931(uint8_t *Block); +int IsBlock1PCF7931(uint8_t *Block); +void ReadPCF7931(); void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); -void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd); -void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd); -void Cotag(uint32_t arg0); +void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode); /// iso14443.h -void SimulateIso14443bTag(void); -void AcquireRawAdcSamplesIso14443b(uint32_t parameter); -void ReadSTMemoryIso14443b(uint32_t); -void RAMFUNC SnoopIso14443b(void); +void SimulateIso14443Tag(void); +void AcquireRawAdcSamplesIso14443(uint32_t parameter); +void ReadSTMemoryIso14443(uint32_t); +void RAMFUNC SnoopIso14443(void); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); +/// iso14443a.h +void RAMFUNC SnoopIso14443a(uint8_t param); +void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data); +void ReaderIso14443a(UsbCommand * c); // Also used in iclass.c -void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity); - +bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t iSamples, uint32_t dwParity, bool bReader); +uint32_t GetParity(const uint8_t * pbtCmd, int iLen); +void iso14a_set_trigger(bool enable); +void iso14a_clear_trace(); +void iso14a_set_tracing(bool enable); void RAMFUNC SniffMifare(uint8_t param); /// epa.h void EPA_PACE_Collect_Nonce(UsbCommand * c); -void EPA_PACE_Replay(UsbCommand *c); -// mifaredesfire.h -bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); -void MifareDesfireGetInformation(); -void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); -void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); +// mifarecmd.h +void ReaderMifare(bool first_try); +int32_t dist_nt(uint32_t nt1, uint32_t nt2); +void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); +void MifareUReadBlock(uint8_t arg0,uint8_t *datain); +void MifareUReadCard(uint8_t arg0,uint8_t *datain); +void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareUWriteBlock(uint8_t arg0,uint8_t *datain); +void MifareUWriteBlock_Special(uint8_t arg0,uint8_t *datain); +void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card +void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); + +/// iso15693.h +void RecordRawAdcSamplesIso15693(void); +void AcquireRawAdcSamplesIso15693(void); +void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg +void SimTagIso15693(uint32_t parameter); // simulate an ISO15693 tag - greg +void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox +void SetDebugIso15693(uint32_t flag); + +/// iclass.h +void RAMFUNC SnoopIClass(void); +void SimulateIClass(uint8_t arg0, uint8_t *datain); +void ReaderIClass(uint8_t arg0); + +// hitag2.h +void SnoopHitag(uint32_t type); +void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); +void ReaderHitag(hitag_function htf, hitag_data* htd); + +// cmd.h +bool cmd_receive(UsbCommand* cmd); +bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); + +/// util.h #endif diff --git a/common/crapto1/crapto1.c b/armsrc/crapto1.c similarity index 67% rename from common/crapto1/crapto1.c rename to armsrc/crapto1.c index 1edfca1b..9d491d12 100644 --- a/common/crapto1/crapto1.c +++ b/armsrc/crapto1.c @@ -1,533 +1,478 @@ -/* crapto1.c - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, US$ - - Copyright (C) 2008-2014 bla -*/ -#include "crapto1.h" - -#include -#include "parity.h" - -#if !defined LOWMEM && defined __GNUC__ -static uint8_t filterlut[1 << 20]; -static void __attribute__((constructor)) fill_lut() -{ - uint32_t i; - for(i = 0; i < 1 << 20; ++i) - filterlut[i] = filter(i); -} -#define filter(x) (filterlut[(x) & 0xfffff]) -#endif - - - -typedef struct bucket { - uint32_t *head; - uint32_t *bp; -} bucket_t; - -typedef bucket_t bucket_array_t[2][0x100]; - -typedef struct bucket_info { - struct { - uint32_t *head, *tail; - } bucket_info[2][0x100]; - uint32_t numbuckets; - } bucket_info_t; - - -static void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop, - uint32_t* const ostart, uint32_t* const ostop, - bucket_info_t *bucket_info, bucket_array_t bucket) -{ - uint32_t *p1, *p2; - uint32_t *start[2]; - uint32_t *stop[2]; - - start[0] = estart; - stop[0] = estop; - start[1] = ostart; - stop[1] = ostop; - - // init buckets to be empty - for (uint32_t i = 0; i < 2; i++) { - for (uint32_t j = 0x00; j <= 0xff; j++) { - bucket[i][j].bp = bucket[i][j].head; - } - } - - // sort the lists into the buckets based on the MSB (contribution bits) - for (uint32_t i = 0; i < 2; i++) { - for (p1 = start[i]; p1 <= stop[i]; p1++) { - uint32_t bucket_index = (*p1 & 0xff000000) >> 24; - *(bucket[i][bucket_index].bp++) = *p1; - } - } - - - // write back intersecting buckets as sorted list. - // fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets. - uint32_t nonempty_bucket; - for (uint32_t i = 0; i < 2; i++) { - p1 = start[i]; - nonempty_bucket = 0; - for (uint32_t j = 0x00; j <= 0xff; j++) { - if (bucket[0][j].bp != bucket[0][j].head && bucket[1][j].bp != bucket[1][j].head) { // non-empty intersecting buckets only - bucket_info->bucket_info[i][nonempty_bucket].head = p1; - for (p2 = bucket[i][j].head; p2 < bucket[i][j].bp; *p1++ = *p2++); - bucket_info->bucket_info[i][nonempty_bucket].tail = p1 - 1; - nonempty_bucket++; - } - } - bucket_info->numbuckets = nonempty_bucket; - } -} -/** binsearch - * Binary search for the first occurence of *stop's MSB in sorted [start,stop] - */ -/* static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop) -{ - uint32_t mid, val = *stop & 0xff000000; - while(start != stop) - if(start[mid = (stop - start) >> 1] > val) - stop = &start[mid]; - else - start += mid + 1; - - return start; -} - */ -/** update_contribution - * helper, calculates the partial linear feedback contributions and puts in MSB - */ -static inline void -update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) -{ - uint32_t p = *item >> 25; - - p = p << 1 | evenparity32(*item & mask1); - p = p << 1 | evenparity32(*item & mask2); - *item = p << 24 | (*item & 0xffffff); -} - -/** extend_table - * using a bit of the keystream extend the table of possible lfsr states - */ -static inline void -extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) -{ - in <<= 24; - for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) - if(filter(*tbl) ^ filter(*tbl | 1)) { - *tbl |= filter(*tbl) ^ bit; - update_contribution(tbl, m1, m2); - *tbl ^= in; - } else if(filter(*tbl) == bit) { - *++*end = tbl[1]; - tbl[1] = tbl[0] | 1; - update_contribution(tbl, m1, m2); - *tbl++ ^= in; - update_contribution(tbl, m1, m2); - *tbl ^= in; - } else - *tbl-- = *(*end)--; -} -/** extend_table_simple - * using a bit of the keystream extend the table of possible lfsr states - */ -static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) -{ - for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) - if(filter(*tbl) ^ filter(*tbl | 1)) - *tbl |= filter(*tbl) ^ bit; - else if(filter(*tbl) == bit) { - *++*end = *++tbl; - *tbl = tbl[-1] | 1; - - } else - *tbl-- = *(*end)--; -} - - -/** recover - * recursively narrow down the search space, 4 bits of keystream at a time - */ -static struct Crypto1State* -recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, - uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, - struct Crypto1State *sl, uint32_t in, bucket_array_t bucket) -{ - uint32_t *o, *e, i; - bucket_info_t bucket_info; - - if(rem == -1) { - for(e = e_head; e <= e_tail; ++e) { - *e = *e << 1 ^ evenparity32(*e & LF_POLY_EVEN) ^ !!(in & 4); - for(o = o_head; o <= o_tail; ++o, ++sl) { - sl->even = *o; - sl->odd = *e ^ evenparity32(*o & LF_POLY_ODD); - sl[1].odd = sl[1].even = 0; - } - } - return sl; - } - - for(i = 0; i < 4 && rem--; i++) { - oks >>= 1; - eks >>= 1; - in >>= 2; - extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, - LF_POLY_ODD << 1, 0); - if(o_head > o_tail) - return sl; - - extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD, - LF_POLY_EVEN << 1 | 1, in & 3); - if(e_head > e_tail) - return sl; - } - bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket); - - for (int i = bucket_info.numbuckets - 1; i >= 0; i--) { - sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks, - bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks, - rem, sl, in, bucket); - } - - return sl; -} -/** lfsr_recovery - * recover the state of the lfsr given 32 bits of the keystream - * additionally you can use the in parameter to specify the value - * that was fed into the lfsr at the time the keystream was generated - */ -struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) -{ - struct Crypto1State *statelist; - uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; - uint32_t *even_head = 0, *even_tail = 0, eks = 0; - int i; - - for(i = 31; i >= 0; i -= 2) - oks = oks << 1 | BEBIT(ks2, i); - for(i = 30; i >= 0; i -= 2) - eks = eks << 1 | BEBIT(ks2, i); - - odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); - even_head = even_tail = malloc(sizeof(uint32_t) << 21); - statelist = malloc(sizeof(struct Crypto1State) << 18); - if(!odd_tail-- || !even_tail-- || !statelist) { - free(statelist); - statelist = 0; - goto out; - } - statelist->odd = statelist->even = 0; - - // allocate memory for out of place bucket_sort - bucket_array_t bucket; - for (uint32_t i = 0; i < 2; i++) - for (uint32_t j = 0; j <= 0xff; j++) { - bucket[i][j].head = malloc(sizeof(uint32_t)<<14); - if (!bucket[i][j].head) { - goto out; - } - } - - - for(i = 1 << 20; i >= 0; --i) { - if(filter(i) == (oks & 1)) - *++odd_tail = i; - if(filter(i) == (eks & 1)) - *++even_tail = i; - } - - for(i = 0; i < 4; i++) { - extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); - extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); - } - - in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); - recover(odd_head, odd_tail, oks, - even_head, even_tail, eks, 11, statelist, in << 1, bucket); - -out: - free(odd_head); - free(even_head); - for (uint32_t i = 0; i < 2; i++) - for (uint32_t j = 0; j <= 0xff; j++) - free(bucket[i][j].head); - - return statelist; -} - -static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, - 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, - 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA}; -static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, - 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, - 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, - 0x7EC7EE90, 0x7F63F748, 0x79117020}; -static const uint32_t T1[] = { - 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, - 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, - 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, - 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C}; -static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, - 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, - 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, - 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, - 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, - 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0}; -static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; -static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; -/** Reverse 64 bits of keystream into possible cipher states - * Variation mentioned in the paper. Somewhat optimized version - */ -struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) -{ - struct Crypto1State *statelist, *sl; - uint8_t oks[32], eks[32], hi[32]; - uint32_t low = 0, win = 0; - uint32_t *tail, table[1 << 16]; - int i, j; - - sl = statelist = malloc(sizeof(struct Crypto1State) << 4); - if(!sl) - return 0; - sl->odd = sl->even = 0; - - for(i = 30; i >= 0; i -= 2) { - oks[i >> 1] = BEBIT(ks2, i); - oks[16 + (i >> 1)] = BEBIT(ks3, i); - } - for(i = 31; i >= 0; i -= 2) { - eks[i >> 1] = BEBIT(ks2, i); - eks[16 + (i >> 1)] = BEBIT(ks3, i); - } - - for(i = 0xfffff; i >= 0; --i) { - if (filter(i) != oks[0]) - continue; - - *(tail = table) = i; - for(j = 1; tail >= table && j < 29; ++j) - extend_table_simple(table, &tail, oks[j]); - - if(tail < table) - continue; - - for(j = 0; j < 19; ++j) - low = low << 1 | evenparity32(i & S1[j]); - for(j = 0; j < 32; ++j) - hi[j] = evenparity32(i & T1[j]); - - for(; tail >= table; --tail) { - for(j = 0; j < 3; ++j) { - *tail = *tail << 1; - *tail |= evenparity32((i & C1[j]) ^ (*tail & C2[j])); - if(filter(*tail) != oks[29 + j]) - goto continue2; - } - - for(j = 0; j < 19; ++j) - win = win << 1 | evenparity32(*tail & S2[j]); - - win ^= low; - for(j = 0; j < 32; ++j) { - win = win << 1 ^ hi[j] ^ evenparity32(*tail & T2[j]); - if(filter(win) != eks[j]) - goto continue2; - } - - *tail = *tail << 1 | evenparity32(LF_POLY_EVEN & *tail); - sl->odd = *tail ^ evenparity32(LF_POLY_ODD & win); - sl->even = win; - ++sl; - sl->odd = sl->even = 0; - continue2:; - } - } - return statelist; -} - -/** lfsr_rollback_bit - * Rollback the shift register in order to get previous states - */ -uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) -{ - int out; - uint8_t ret; - uint32_t t; - - s->odd &= 0xffffff; - t = s->odd, s->odd = s->even, s->even = t; - - out = s->even & 1; - out ^= LF_POLY_EVEN & (s->even >>= 1); - out ^= LF_POLY_ODD & s->odd; - out ^= !!in; - out ^= (ret = filter(s->odd)) & !!fb; - - s->even |= evenparity32(out) << 23; - return ret; -} -/** lfsr_rollback_byte - * Rollback the shift register in order to get previous states - */ -uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) -{ - int i, ret=0; - for (i = 7; i >= 0; --i) - ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; - return ret; -} -/** lfsr_rollback_word - * Rollback the shift register in order to get previous states - */ -uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) -{ - int i; - uint32_t ret = 0; - for (i = 31; i >= 0; --i) - ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); - return ret; -} - -/** nonce_distance - * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y - */ -static uint16_t *dist = 0; -int nonce_distance(uint32_t from, uint32_t to) -{ - uint16_t x, i; - if(!dist) { - dist = malloc(2 << 16); - if(!dist) - return -1; - for (x = i = 1; i; ++i) { - dist[(x & 0xff) << 8 | x >> 8] = i; - x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; - } - } - return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; -} - -static uint32_t fastfwd[2][8] = { - { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, - { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}}; -/** lfsr_prefix_ks - * - * Is an exported helper function from the common prefix attack - * Described in the "dark side" paper. It returns an -1 terminated array - * of possible partial(21 bit) secret state. - * The required keystream(ks) needs to contain the keystream that was used to - * encrypt the NACK which is observed when varying only the 3 last bits of Nr - * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 - */ -uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) -{ - uint32_t c, entry, *candidates = malloc(4 << 10); - int i, size = 0, good; - - if(!candidates) - return 0; - - for(i = 0; i < 1 << 21; ++i) { - for(c = 0, good = 1; good && c < 8; ++c) { - entry = i ^ fastfwd[isodd][c]; - good &= (BIT(ks[c], isodd) == filter(entry >> 1)); - good &= (BIT(ks[c], isodd + 2) == filter(entry)); - } - if(good) - candidates[size++] = i; - } - - candidates[size] = -1; - - return candidates; -} - -/** check_pfx_parity - * helper function which eliminates possible secret states using parity bits - */ -static struct Crypto1State* -check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], - uint32_t odd, uint32_t even, struct Crypto1State* sl, uint32_t no_par) -{ - uint32_t ks1, nr, ks2, rr, ks3, c, good = 1; - - for(c = 0; good && c < 8; ++c) { - sl->odd = odd ^ fastfwd[1][c]; - sl->even = even ^ fastfwd[0][c]; - - lfsr_rollback_bit(sl, 0, 0); - lfsr_rollback_bit(sl, 0, 0); - - ks3 = lfsr_rollback_bit(sl, 0, 0); - ks2 = lfsr_rollback_word(sl, 0, 0); - ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); - - if (no_par) - break; - - nr = ks1 ^ (prefix | c << 5); - rr = ks2 ^ rresp; - - good &= evenparity32(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); - good &= evenparity32(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); - good &= evenparity32(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); - good &= evenparity32(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); - good &= evenparity32(rr & 0x000000ff) ^ parities[c][7] ^ ks3; - } - - return sl + good; -} - - -/** lfsr_common_prefix - * Implentation of the common prefix attack. - */ -struct Crypto1State* -lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par) -{ - struct Crypto1State *statelist, *s; - uint32_t *odd, *even, *o, *e, top; - - odd = lfsr_prefix_ks(ks, 1); - even = lfsr_prefix_ks(ks, 0); - - s = statelist = malloc((sizeof *statelist) << 22); // was << 20. Need more for no_par special attack. Enough??? - if(!s || !odd || !even) { - free(statelist); - statelist = 0; - goto out; - } - - for(o = odd; *o + 1; ++o) - for(e = even; *e + 1; ++e) - for(top = 0; top < 64; ++top) { - *o += 1 << 21; - *e += (!(top & 7) + 1) << 21; - s = check_pfx_parity(pfx, rr, par, *o, *e, s, no_par); - } - - s->odd = s->even = 0; -out: - free(odd); - free(even); - return statelist; -} +/* crapto1.c + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, US$ + + Copyright (C) 2008-2008 bla +*/ +#include "crapto1.h" +#include + +#if !defined LOWMEM && defined __GNUC__ +static uint8_t filterlut[1 << 20]; +static void __attribute__((constructor)) fill_lut() +{ + uint32_t i; + for(i = 0; i < 1 << 20; ++i) + filterlut[i] = filter(i); +} +#define filter(x) (filterlut[(x) & 0xfffff]) +#endif + +static void quicksort(uint32_t* const start, uint32_t* const stop) +{ + uint32_t *it = start + 1, *rit = stop; + + if(it > rit) + return; + + while(it < rit) + if(*it <= *start) + ++it; + else if(*rit > *start) + --rit; + else + *it ^= (*it ^= *rit, *rit ^= *it); + + if(*rit >= *start) + --rit; + if(rit != start) + *rit ^= (*rit ^= *start, *start ^= *rit); + + quicksort(start, rit - 1); + quicksort(rit + 1, stop); +} +/** binsearch + * Binary search for the first occurence of *stop's MSB in sorted [start,stop] + */ +static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop) +{ + uint32_t mid, val = *stop & 0xff000000; + while(start != stop) + if(start[mid = (stop - start) >> 1] > val) + stop = &start[mid]; + else + start += mid + 1; + + return start; +} + +/** update_contribution + * helper, calculates the partial linear feedback contributions and puts in MSB + */ +static inline void +update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) +{ + uint32_t p = *item >> 25; + + p = p << 1 | parity(*item & mask1); + p = p << 1 | parity(*item & mask2); + *item = p << 24 | (*item & 0xffffff); +} + +/** extend_table + * using a bit of the keystream extend the table of possible lfsr states + */ +static inline void +extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) +{ + in <<= 24; + for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) + if(filter(*tbl) ^ filter(*tbl | 1)) { + *tbl |= filter(*tbl) ^ bit; + update_contribution(tbl, m1, m2); + *tbl ^= in; + } else if(filter(*tbl) == bit) { + *++*end = tbl[1]; + tbl[1] = tbl[0] | 1; + update_contribution(tbl, m1, m2); + *tbl++ ^= in; + update_contribution(tbl, m1, m2); + *tbl ^= in; + } else + *tbl-- = *(*end)--; +} +/** extend_table_simple + * using a bit of the keystream extend the table of possible lfsr states + */ +static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) +{ + for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) + if(filter(*tbl) ^ filter(*tbl | 1)) + *tbl |= filter(*tbl) ^ bit; + else if(filter(*tbl) == bit) { + *++*end = *++tbl; + *tbl = tbl[-1] | 1; + } else + *tbl-- = *(*end)--; +} +/** recover + * recursively narrow down the search space, 4 bits of keystream at a time + */ +static struct Crypto1State* +recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, + uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, + struct Crypto1State *sl, uint32_t in) +{ + uint32_t *o, *e, i; + + if(rem == -1) { + for(e = e_head; e <= e_tail; ++e) { + *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); + for(o = o_head; o <= o_tail; ++o, ++sl) { + sl->even = *o; + sl->odd = *e ^ parity(*o & LF_POLY_ODD); + sl[1].odd = sl[1].even = 0; + } + } + return sl; + } + + for(i = 0; i < 4 && rem--; i++) { + oks >>= 1; + eks >>= 1; + in >>= 2; + extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, + LF_POLY_ODD << 1, 0); + if(o_head > o_tail) + return sl; + + extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD, + LF_POLY_EVEN << 1 | 1, in & 3); + if(e_head > e_tail) + return sl; + } + + quicksort(o_head, o_tail); + quicksort(e_head, e_tail); + + while(o_tail >= o_head && e_tail >= e_head) + if(((*o_tail ^ *e_tail) >> 24) == 0) { + o_tail = binsearch(o_head, o = o_tail); + e_tail = binsearch(e_head, e = e_tail); + sl = recover(o_tail--, o, oks, + e_tail--, e, eks, rem, sl, in); + } + else if(*o_tail > *e_tail) + o_tail = binsearch(o_head, o_tail) - 1; + else + e_tail = binsearch(e_head, e_tail) - 1; + + return sl; +} +/** lfsr_recovery + * recover the state of the lfsr given 32 bits of the keystream + * additionally you can use the in parameter to specify the value + * that was fed into the lfsr at the time the keystream was generated + */ +struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) +{ + struct Crypto1State *statelist; + uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; + uint32_t *even_head = 0, *even_tail = 0, eks = 0; + int i; + + for(i = 31; i >= 0; i -= 2) + oks = oks << 1 | BEBIT(ks2, i); + for(i = 30; i >= 0; i -= 2) + eks = eks << 1 | BEBIT(ks2, i); + + odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); + even_head = even_tail = malloc(sizeof(uint32_t) << 21); + statelist = malloc(sizeof(struct Crypto1State) << 18); + if(!odd_tail-- || !even_tail-- || !statelist) { + free(statelist); + statelist = 0; + goto out; + } + + statelist->odd = statelist->even = 0; + + for(i = 1 << 20; i >= 0; --i) { + if(filter(i) == (oks & 1)) + *++odd_tail = i; + if(filter(i) == (eks & 1)) + *++even_tail = i; + } + + for(i = 0; i < 4; i++) { + extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); + extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); + } + + in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); + recover(odd_head, odd_tail, oks, + even_head, even_tail, eks, 11, statelist, in << 1); + +out: + free(odd_head); + free(even_head); + return statelist; +} + +static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, + 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, + 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA}; +static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, + 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, + 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, + 0x7EC7EE90, 0x7F63F748, 0x79117020}; +static const uint32_t T1[] = { + 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, + 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, + 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, + 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C}; +static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, + 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, + 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, + 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, + 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, + 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0}; +static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; +static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; +/** Reverse 64 bits of keystream into possible cipher states + * Variation mentioned in the paper. Somewhat optimized version + */ +struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) +{ + struct Crypto1State *statelist, *sl; + uint8_t oks[32], eks[32], hi[32]; + uint32_t low = 0, win = 0; + uint32_t *tail, table[1 << 16]; + int i, j; + + sl = statelist = malloc(sizeof(struct Crypto1State) << 4); + if(!sl) + return 0; + sl->odd = sl->even = 0; + + for(i = 30; i >= 0; i -= 2) { + oks[i >> 1] = BEBIT(ks2, i); + oks[16 + (i >> 1)] = BEBIT(ks3, i); + } + for(i = 31; i >= 0; i -= 2) { + eks[i >> 1] = BEBIT(ks2, i); + eks[16 + (i >> 1)] = BEBIT(ks3, i); + } + + for(i = 0xfffff; i >= 0; --i) { + if (filter(i) != oks[0]) + continue; + + *(tail = table) = i; + for(j = 1; tail >= table && j < 29; ++j) + extend_table_simple(table, &tail, oks[j]); + + if(tail < table) + continue; + + for(j = 0; j < 19; ++j) + low = low << 1 | parity(i & S1[j]); + for(j = 0; j < 32; ++j) + hi[j] = parity(i & T1[j]); + + for(; tail >= table; --tail) { + for(j = 0; j < 3; ++j) { + *tail = *tail << 1; + *tail |= parity((i & C1[j]) ^ (*tail & C2[j])); + if(filter(*tail) != oks[29 + j]) + goto continue2; + } + + for(j = 0; j < 19; ++j) + win = win << 1 | parity(*tail & S2[j]); + + win ^= low; + for(j = 0; j < 32; ++j) { + win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); + if(filter(win) != eks[j]) + goto continue2; + } + + *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); + sl->odd = *tail ^ parity(LF_POLY_ODD & win); + sl->even = win; + ++sl; + sl->odd = sl->even = 0; + continue2:; + } + } + return statelist; +} + +/** lfsr_rollback_bit + * Rollback the shift register in order to get previous states + */ +uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) +{ + int out; + uint8_t ret; + + s->odd &= 0xffffff; + s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); + + out = s->even & 1; + out ^= LF_POLY_EVEN & (s->even >>= 1); + out ^= LF_POLY_ODD & s->odd; + out ^= !!in; + out ^= (ret = filter(s->odd)) & !!fb; + + s->even |= parity(out) << 23; + return ret; +} +/** lfsr_rollback_byte + * Rollback the shift register in order to get previous states + */ +uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) +{ + int i, ret = 0; + for (i = 7; i >= 0; --i) + ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; + return ret; +} +/** lfsr_rollback_word + * Rollback the shift register in order to get previous states + */ +uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) +{ + int i; + uint32_t ret = 0; + for (i = 31; i >= 0; --i) + ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); + return ret; +} + +/** nonce_distance + * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y + */ +static uint16_t *dist = 0; +int nonce_distance(uint32_t from, uint32_t to) +{ + uint16_t x, i; + if(!dist) { + dist = malloc(2 << 16); + if(!dist) + return -1; + for (x = i = 1; i; ++i) { + dist[(x & 0xff) << 8 | x >> 8] = i; + x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; + } + } + return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; +} + + +static uint32_t fastfwd[2][8] = { + { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, + { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}}; +/** lfsr_prefix_ks + * + * Is an exported helper function from the common prefix attack + * Described in the "dark side" paper. It returns an -1 terminated array + * of possible partial(21 bit) secret state. + * The required keystream(ks) needs to contain the keystream that was used to + * encrypt the NACK which is observed when varying only the 3 last bits of Nr + * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 + */ +uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) +{ + uint32_t c, entry, *candidates = malloc(4 << 10); + int i, size = 0, good; + + if(!candidates) + return 0; + + for(i = 0; i < 1 << 21; ++i) { + for(c = 0, good = 1; good && c < 8; ++c) { + entry = i ^ fastfwd[isodd][c]; + good &= (BIT(ks[c], isodd) == filter(entry >> 1)); + good &= (BIT(ks[c], isodd + 2) == filter(entry)); + } + if(good) + candidates[size++] = i; + } + + candidates[size] = -1; + + return candidates; +} + +/** check_pfx_parity + * helper function which eliminates possible secret states using parity bits + */ +static struct Crypto1State* +check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], + uint32_t odd, uint32_t even, struct Crypto1State* sl) +{ + uint32_t ks1, nr, ks2, rr, ks3, c, good = 1; + + for(c = 0; good && c < 8; ++c) { + sl->odd = odd ^ fastfwd[1][c]; + sl->even = even ^ fastfwd[0][c]; + + lfsr_rollback_bit(sl, 0, 0); + lfsr_rollback_bit(sl, 0, 0); + + ks3 = lfsr_rollback_bit(sl, 0, 0); + ks2 = lfsr_rollback_word(sl, 0, 0); + ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); + + nr = ks1 ^ (prefix | c << 5); + rr = ks2 ^ rresp; + + good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); + good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); + good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); + good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); + good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; + } + + return sl + good; +} + + +/** lfsr_common_prefix + * Implentation of the common prefix attack. + */ +struct Crypto1State* +lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) +{ + struct Crypto1State *statelist, *s; + uint32_t *odd, *even, *o, *e, top; + + odd = lfsr_prefix_ks(ks, 1); + even = lfsr_prefix_ks(ks, 0); + + s = statelist = malloc((sizeof *statelist) << 20); + if(!s || !odd || !even) { + free(statelist); + statelist = 0; + goto out; + } + + for(o = odd; *o + 1; ++o) + for(e = even; *e + 1; ++e) + for(top = 0; top < 64; ++top) { + *o += 1 << 21; + *e += (!(top & 7) + 1) << 21; + s = check_pfx_parity(pfx, rr, par, *o, *e, s); + } + + s->odd = s->even = 0; +out: + free(odd); + free(even); + return statelist; +} diff --git a/common/crapto1/crapto1.h b/armsrc/crapto1.h similarity index 83% rename from common/crapto1/crapto1.h rename to armsrc/crapto1.h index 8e79d224..b144853c 100644 --- a/common/crapto1/crapto1.h +++ b/armsrc/crapto1.h @@ -15,7 +15,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US$ - Copyright (C) 2008-2014 bla + Copyright (C) 2008-2008 bla */ #ifndef CRAPTO1_INCLUDED #define CRAPTO1_INCLUDED @@ -25,11 +25,7 @@ extern "C" { #endif struct Crypto1State {uint32_t odd, even;}; -#if defined(__arm__) && !defined(__linux__) && !defined(_WIN32) && !defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() void crypto1_create(struct Crypto1State *s, uint64_t key); -#else -struct Crypto1State *crypto1_create(uint64_t key); -#endif void crypto1_destroy(struct Crypto1State*); void crypto1_get_lfsr(struct Crypto1State*, uint64_t*); uint8_t crypto1_bit(struct Crypto1State*, uint8_t, int); @@ -41,8 +37,7 @@ struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in); struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd); struct Crypto1State* -lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par); - +lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]); uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb); uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb); @@ -53,7 +48,7 @@ int nonce_distance(uint32_t from, uint32_t to); int __i;\ for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ for(__i = FSIZE - 1; __i >= 0; __i--)\ - if(BIT(FILTER, __i) ^ evenparity32(__M & 0xFF01))\ + if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\ break;\ else if(__i)\ __M = prng_successor(__M, (__i == 7) ? 48 : 8);\ @@ -63,6 +58,24 @@ int nonce_distance(uint32_t from, uint32_t to); #define LF_POLY_EVEN (0x870804) #define BIT(x, n) ((x) >> (n) & 1) #define BEBIT(x, n) BIT(x, (n) ^ 24) +static inline int parity(uint32_t x) +{ +#if !defined __i386__ || !defined __GNUC__ + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + return BIT(0x6996, x & 0xf); +#else + asm( "movl %1, %%eax\n" + "mov %%ax, %%cx\n" + "shrl $0x10, %%eax\n" + "xor %%ax, %%cx\n" + "xor %%ch, %%cl\n" + "setpo %%al\n" + "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx"); + return x; +#endif +} static inline int filter(uint32_t const x) { uint32_t f; diff --git a/armsrc/crypto1.c b/armsrc/crypto1.c new file mode 100644 index 00000000..9d103c7f --- /dev/null +++ b/armsrc/crypto1.c @@ -0,0 +1,95 @@ +/* crypto1.c + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, US + + Copyright (C) 2008-2008 bla +*/ +#include "crapto1.h" +#include + +#define SWAPENDIAN(x)\ + (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) + +void crypto1_create(struct Crypto1State *s, uint64_t key) +{ +// struct Crypto1State *s = malloc(sizeof(*s)); + int i; + + for(i = 47;s && i > 0; i -= 2) { + s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7); + s->even = s->even << 1 | BIT(key, i ^ 7); + } + return; +} +void crypto1_destroy(struct Crypto1State *state) +{ +// free(state); + state->odd = 0; + state->even = 0; +} +void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) +{ + int i; + for(*lfsr = 0, i = 23; i >= 0; --i) { + *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); + *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); + } +} +uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) +{ + uint32_t feedin; + uint8_t ret = filter(s->odd); + + feedin = ret & !!is_encrypted; + feedin ^= !!in; + feedin ^= LF_POLY_ODD & s->odd; + feedin ^= LF_POLY_EVEN & s->even; + s->even = s->even << 1 | parity(feedin); + + s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); + + return ret; +} +uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) +{ + uint8_t i, ret = 0; + + for (i = 0; i < 8; ++i) + ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i; + + return ret; +} +uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) +{ + uint32_t i, ret = 0; + + for (i = 0; i < 32; ++i) + ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24); + + return ret; +} + +/* prng_successor + * helper used to obscure the keystream during authentication + */ +uint32_t prng_successor(uint32_t x, uint32_t n) +{ + SWAPENDIAN(x); + while(n--) + x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; + + return SWAPENDIAN(x); +} diff --git a/armsrc/epa.c b/armsrc/epa.c index fe32e497..b0ae5e0d 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -5,22 +5,17 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Routines to support the German electronic "Personalausweis" (ID card) +// Routines to support the German eletronic "Personalausweis" (ID card) // Note that the functions which do not implement USB commands do NOT initialize // the card (with iso14443a_select_card etc.). If You want to use these // functions, You need to do the setup before calling them! //----------------------------------------------------------------------------- -#include "apps.h" #include "iso14443a.h" -#include "iso14443b.h" #include "epa.h" -#include "usb_cdc.h" -#include "fpgaloader.h" -#include "string.h" -#include "util.h" +#include "cmd.h" -// Protocol and Parameter Selection Request for ISO 14443 type A cards +// Protocol and Parameter Selection Request // use regular (1x) speed in both directions // CRC is already included static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6}; @@ -79,54 +74,6 @@ static const uint8_t oid_pace_start[] = { 0x04 // id-PACE }; -// APDUs for replaying: -// MSE: Set AT (initiate PACE) -static uint8_t apdu_replay_mse_set_at_pace[41]; -// General Authenticate (Get Nonce) -static uint8_t apdu_replay_general_authenticate_pace_get_nonce[8]; -// General Authenticate (Map Nonce) -static uint8_t apdu_replay_general_authenticate_pace_map_nonce[75]; -// General Authenticate (Mutual Authenticate) -static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75]; -// General Authenticate (Perform Key Agreement) -static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18]; -// pointers to the APDUs (for iterations) -static struct { - uint8_t len; - uint8_t *data; -} const apdus_replay[] = { - {sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace}, - {sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce}, - {sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce}, - {sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate}, - {sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement} -}; - -// lengths of the replay APDUs -static uint8_t apdu_lengths_replay[5]; - -// type of card (ISO 14443 A or B) -static char iso_type = 0; - -//----------------------------------------------------------------------------- -// Wrapper for sending APDUs to type A and B cards -//----------------------------------------------------------------------------- -int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) -{ - switch(iso_type) - { - case 'a': - return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); - break; - case 'b': - return iso14443b_apdu(apdu, length, response); - break; - default: - return 0; - break; - } -} - //----------------------------------------------------------------------------- // Closes the communication channel and turns off the field //----------------------------------------------------------------------------- @@ -134,7 +81,6 @@ void EPA_Finish() { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - iso_type = 0; } //----------------------------------------------------------------------------- @@ -155,16 +101,16 @@ size_t EPA_Parse_CardAccess(uint8_t *data, pace_version_info_t *pace_info) { size_t index = 0; - + while (index <= length - 2) { // determine type of element // SET or SEQUENCE if (data[index] == 0x31 || data[index] == 0x30) { // enter the set (skip tag + length) index += 2; - // check for extended length + // extended length if ((data[index - 1] & 0x80) != 0) { - index += (data[index-1] & 0x7F); + index += (data[index] & 0x7F); } } // OID @@ -212,7 +158,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data, index += 2 + data[index + 1]; } } - + // TODO: We should check whether we reached the end in error, but for that // we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO) return 0; @@ -230,31 +176,29 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) // we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame) uint8_t response_apdu[262]; int rapdu_length = 0; - + // select the file EF.CardAccess - rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess, + rapdu_length = iso14_apdu((uint8_t *)apdu_select_binary_cardaccess, sizeof(apdu_select_binary_cardaccess), response_apdu); - if (rapdu_length < 6 + if (rapdu_length != 6 || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { - DbpString("Failed to select EF.CardAccess!"); return -1; } - + // read the file - rapdu_length = EPA_APDU((uint8_t *)apdu_read_binary, + rapdu_length = iso14_apdu((uint8_t *)apdu_read_binary, sizeof(apdu_read_binary), response_apdu); if (rapdu_length <= 6 || response_apdu[rapdu_length - 4] != 0x90 || response_apdu[rapdu_length - 3] != 0x00) { - Dbprintf("Failed to read EF.CardAccess!"); return -1; } - + // copy the content into the buffer // length of data available: apdu_length - 4 (ISO frame) - 2 (SW) size_t to_copy = rapdu_length - 6; @@ -269,11 +213,17 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) //----------------------------------------------------------------------------- static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) { +// // step in which the failure occured +// ack->arg[0] = step; +// // last return code +// ack->arg[1] = func_return; + // power down the field EPA_Finish(); - + // send the USB packet - cmd_send(CMD_ACK,step,func_return,0,0,0); + cmd_send(CMD_ACK,step,func_return,0,0,0); +//UsbSendPacket((void *)ack, sizeof(UsbCommand)); } //----------------------------------------------------------------------------- @@ -293,8 +243,12 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) */ // return value of a function - int func_return = 0; + int func_return; +// // initialize ack with 0s +// memset(ack->arg, 0, 12); +// memset(ack->d.asBytes, 0, 48); + // set up communication func_return = EPA_Setup(); if (func_return != 0) { @@ -302,6 +256,9 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) return; } + // increase the timeout (at least some cards really do need this!) + iso14a_set_timeout(0x0002FFFF); + // read the CardAccess file // this array will hold the CardAccess file uint8_t card_access[256] = {0}; @@ -322,11 +279,11 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) EPA_PACE_Collect_Nonce_Abort(3, func_return); return; } - + // initiate the PACE protocol // use the CAN for the password since that doesn't change func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2); - + // now get the nonce uint8_t nonce[256] = {0}; uint8_t requested_size = (uint8_t)c->arg[0]; @@ -337,12 +294,15 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c) EPA_PACE_Collect_Nonce_Abort(4, func_return); return; } - - // all done, return + + // all done, return EPA_Finish(); - + // save received information - cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); +// ack->arg[1] = func_return; +// memcpy(ack->d.asBytes, nonce, func_return); +// UsbSendPacket((void *)ack, sizeof(UsbCommand)); + cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); } //----------------------------------------------------------------------------- @@ -363,10 +323,10 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) sizeof(apdu_general_authenticate_pace_get_nonce)); // append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4; - + // send it uint8_t response_apdu[262]; - int send_return = EPA_APDU(apdu, + int send_return = iso14_apdu(apdu, sizeof(apdu), response_apdu); // check if the command succeeded @@ -376,7 +336,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) { return -1; } - + // if there is no nonce in the RAPDU, return here if (send_return < 10) { @@ -391,7 +351,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) } // copy the nonce memcpy(nonce, response_apdu + 6, nonce_length); - + return nonce_length; } @@ -437,7 +397,7 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) apdu[4] = apdu_length - 5; // send it uint8_t response_apdu[6]; - int send_return = EPA_APDU(apdu, + int send_return = iso14_apdu(apdu, apdu_length, response_apdu); // check if the command succeeded @@ -450,106 +410,34 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) return 0; } -//----------------------------------------------------------------------------- -// Perform the PACE protocol by replaying given APDUs -//----------------------------------------------------------------------------- -void EPA_PACE_Replay(UsbCommand *c) { - uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0}; - - // if an APDU has been passed, just save it - if (c->arg[0] != 0) { - // make sure it's not too big - if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) { - cmd_send(CMD_ACK, 1, 0, 0, NULL, 0); - return; - } - memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1], c->d.asBytes, c->arg[2]); - // save/update APDU length - if (c->arg[1] == 0) { - apdu_lengths_replay[c->arg[0] - 1] = c->arg[2]; - } else { - apdu_lengths_replay[c->arg[0] - 1] += c->arg[2]; - } - cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); - return; - } - - // return value of a function - int func_return; - - // set up communication - func_return = EPA_Setup(); - if (func_return != 0) { - EPA_Finish(); - cmd_send(CMD_ACK, 2, func_return, 0, NULL, 0); - return; - } - - // response APDU - uint8_t response_apdu[300] = {0}; - - // now replay the data and measure the timings - for (int i = 0; i < sizeof(apdu_lengths_replay); i++) { - StartCountUS(); - func_return = EPA_APDU(apdus_replay[i].data, - apdu_lengths_replay[i], - response_apdu); - timings[i] = GetCountUS(); - // every step but the last one should succeed - if (i < sizeof(apdu_lengths_replay) - 1 - && (func_return < 6 - || response_apdu[func_return - 4] != 0x90 - || response_apdu[func_return - 3] != 0x00)) - { - EPA_Finish(); - cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20); - return; - } - } - EPA_Finish(); - cmd_send(CMD_ACK,0,0,0,timings,20); - return; -} - //----------------------------------------------------------------------------- // Set up a communication channel (Card Select, PPS) // Returns 0 on success or a non-zero error code on failure //----------------------------------------------------------------------------- int EPA_Setup() { + // return code int return_code = 0; - uint8_t uid[10]; - uint8_t pps_response[3]; - uint8_t pps_response_par[1]; + // card UID + uint8_t uid[8]; + // card select information iso14a_card_select_t card_select_info; - - // first, look for type A cards // power up the field iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + // select the card - return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0, false); - if (return_code == 1) { - // send the PPS request - ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); - return_code = ReaderReceive(pps_response, pps_response_par); - if (return_code != 3 || pps_response[0] != 0xD0) { - return return_code == 0 ? 2 : return_code; - } - Dbprintf("ISO 14443 Type A"); - iso_type = 'a'; - return 0; + return_code = iso14443a_select_card(uid, &card_select_info, NULL); + if (return_code != 1) { + return 1; } - // if we're here, there is no type A card, so we look for type B - // power up the field - iso14443b_setup(); - // select the card - return_code = iso14443b_select_card(); - if (return_code == 1) { - Dbprintf("ISO 14443 Type B"); - iso_type = 'b'; - return 0; + // send the PPS request + ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL); + uint8_t pps_response[3]; + return_code = ReaderReceive(pps_response); + if (return_code != 3 || pps_response[0] != 0xD0) { + return return_code == 0 ? 2 : return_code; } - Dbprintf("No card found."); - return 1; -} + + return 0; +} \ No newline at end of file diff --git a/armsrc/epa.h b/armsrc/epa.h index d2ebed57..730652b7 100644 --- a/armsrc/epa.h +++ b/armsrc/epa.h @@ -19,7 +19,7 @@ typedef struct { uint8_t parameter_id; } pace_version_info_t; -// note: EPA_PACE_Collect_Nonce and EPA_PACE_Replay are declared in apps.h +// note: EPA_PACE_GetNonce is declared in apps.h // general functions void EPA_Finish(); @@ -33,4 +33,4 @@ int EPA_Setup(); int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password); int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce); -#endif /* __EPA_H */ +#endif /* __EPA_H */ \ No newline at end of file diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 61db66d3..d63310a3 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -1,6 +1,5 @@ //----------------------------------------------------------------------------- // Jonathan Westhues, April 2006 -// iZsh , 2014 // // 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 @@ -10,29 +9,10 @@ // mode once it is configured. //----------------------------------------------------------------------------- -#include "fpgaloader.h" - -#include -#include -#include -#include "apps.h" -#include "fpga.h" #include "proxmark3.h" +#include "apps.h" #include "util.h" #include "string.h" -#include "BigBuf.h" -#include "zlib.h" - -// remember which version of the bitstream we have already downloaded to the FPGA -static int downloaded_bitstream = 0; - -// this is where the bitstreams are located in memory: -extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end; - -static uint8_t *fpga_image_ptr = NULL; -static uint32_t uncompressed_bytes_cnt; - -#define OUTPUT_BUFFER_LEN 80 //----------------------------------------------------------------------------- // Set up the Serial Peripheral Interface as master @@ -49,16 +29,16 @@ void SetupSpi(int mode) // Disable PIO control of the following pins, allows use by the SPI peripheral AT91C_BASE_PIOA->PIO_PDR = - GPIO_NCS0 | - GPIO_NCS2 | - GPIO_MISO | - GPIO_MOSI | + GPIO_NCS0 | + GPIO_NCS2 | + GPIO_MISO | + GPIO_MOSI | GPIO_SPCK; AT91C_BASE_PIOA->PIO_ASR = - GPIO_NCS0 | - GPIO_MISO | - GPIO_MOSI | + GPIO_NCS0 | + GPIO_MISO | + GPIO_MOSI | GPIO_SPCK; AT91C_BASE_PIOA->PIO_BSR = GPIO_NCS2; @@ -71,56 +51,57 @@ void SetupSpi(int mode) switch (mode) { case SPI_FPGA_MODE: AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) - ( 0 << 7) | // Local Loopback Disabled - ( 1 << 4) | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - ( 0 << 1) | // Fixed Peripheral Select - ( 1 << 0); // Master Mode + ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) + (14 << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11) + ( 0 << 7) | // Local Loopback Disabled + ( 1 << 4) | // Mode Fault Detection disabled + ( 0 << 2) | // Chip selects connected directly to peripheral + ( 0 << 1) | // Fixed Peripheral Select + ( 1 << 0); // Master Mode AT91C_BASE_SPI->SPI_CSR[0] = - ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 1 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 8 << 4) | // Bits per Transfer (16 bits) - ( 0 << 3) | // Chip Select inactive after transfer - ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge - ( 0 << 0); // Clock Polarity inactive state is logic 0 + ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) + ( 1 << 16) | // Delay Before SPCK (1 MCK period) + ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud + ( 8 << 4) | // Bits per Transfer (16 bits) + ( 0 << 3) | // Chip Select inactive after transfer + ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge + ( 0 << 0); // Clock Polarity inactive state is logic 0 break; case SPI_LCD_MODE: AT91C_BASE_SPI->SPI_MR = - ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) - (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10) - ( 0 << 7) | // Local Loopback Disabled - ( 1 << 4) | // Mode Fault Detection disabled - ( 0 << 2) | // Chip selects connected directly to peripheral - ( 0 << 1) | // Fixed Peripheral Select - ( 1 << 0); // Master Mode + ( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods) + (11 << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10) + ( 0 << 7) | // Local Loopback Disabled + ( 1 << 4) | // Mode Fault Detection disabled + ( 0 << 2) | // Chip selects connected directly to peripheral + ( 0 << 1) | // Fixed Peripheral Select + ( 1 << 0); // Master Mode AT91C_BASE_SPI->SPI_CSR[2] = - ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) - ( 1 << 16) | // Delay Before SPCK (1 MCK period) - ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud - ( 1 << 4) | // Bits per Transfer (9 bits) - ( 0 << 3) | // Chip Select inactive after transfer - ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge - ( 0 << 0); // Clock Polarity inactive state is logic 0 + ( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods) + ( 1 << 16) | // Delay Before SPCK (1 MCK period) + ( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud + ( 1 << 4) | // Bits per Transfer (9 bits) + ( 0 << 3) | // Chip Select inactive after transfer + ( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge + ( 0 << 0); // Clock Polarity inactive state is logic 0 break; - default: // Disable SPI + default: // Disable SPI AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; break; } } //----------------------------------------------------------------------------- -// Set up the synchronous serial port with the set of options that fits -// the FPGA mode. Both RX and TX are always enabled. +// Set up the synchronous serial port, with the one set of options that we +// always use when we are talking to the FPGA. Both RX and TX are enabled. //----------------------------------------------------------------------------- -void FpgaSetupSsc(uint16_t FPGA_mode) { +void FpgaSetupSsc(void) +{ // First configure the GPIOs, and get ourselves a clock. AT91C_BASE_PIOA->PIO_ASR = - GPIO_SSC_FRAME | - GPIO_SSC_DIN | - GPIO_SSC_DOUT | + GPIO_SSC_FRAME | + GPIO_SSC_DIN | + GPIO_SSC_DOUT | GPIO_SSC_CLK; AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; @@ -129,21 +110,17 @@ void FpgaSetupSsc(uint16_t FPGA_mode) { // Now set up the SSC proper, starting from a known state. AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - // RX clock comes from TX clock, RX starts on Transmit Start, - // data and frame signal is sampled on falling edge of RK + // RX clock comes from TX clock, RX starts when TX starts, data changes + // on RX clock rising edge, sampled on falling edge AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); - // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync + // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync - if ((FPGA_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) { - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - } else { - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - } + AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - // TX clock comes from TK pin, no clock output, outputs change on rising edge of TK, - // TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF - AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); + // clock comes from TK pin, no clock output, outputs change on falling + // edge of TK, sample on rising edge of TK, start on positive-going edge of sync + AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR; @@ -157,105 +134,22 @@ void FpgaSetupSsc(uint16_t FPGA_mode) { // ourselves, not to another buffer). The stuff to manipulate those buffers // is in apps.h, because it should be inlined, for speed. //----------------------------------------------------------------------------- -bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) { - if (buf == NULL) return false; - - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address - AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address - AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go! - return true; -} - - -//---------------------------------------------------------------------------- -// Uncompress (inflate) the FPGA data. Returns one decompressed byte with -// each call. -//---------------------------------------------------------------------------- -static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer) +bool FpgaSetupSscDma(uint8_t *buf, int len) { - if (fpga_image_ptr == compressed_fpga_stream->next_out) { // need more data - compressed_fpga_stream->next_out = output_buffer; - compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN; - fpga_image_ptr = output_buffer; - int res = inflate(compressed_fpga_stream, Z_SYNC_FLUSH); - if (res != Z_OK) - Dbprintf("inflate returned: %d, %s", res, compressed_fpga_stream->msg); + if (buf == NULL) { + return false; + } - if (res < 0) - return res; - } - - uncompressed_bytes_cnt++; - - return *fpga_image_ptr++; + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address + AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address + AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go! + + return true; } -//---------------------------------------------------------------------------- -// Undo the interleaving of several FPGA config files. FPGA config files -// are combined into one big file: -// 288 bytes from FPGA file 1, followed by 288 bytes from FGPA file 2, etc. -//---------------------------------------------------------------------------- -static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) -{ - while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) { - // skip undesired data belonging to other bitstream_versions - get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer); - } - - return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer); - -} - - -static voidpf fpga_inflate_malloc(voidpf opaque, uInt items, uInt size) -{ - return BigBuf_malloc(items*size); -} - - -static void fpga_inflate_free(voidpf opaque, voidpf address) -{ - BigBuf_free(); BigBuf_Clear_ext(false); -} - - -//---------------------------------------------------------------------------- -// Initialize decompression of the respective (HF or LF) FPGA stream -//---------------------------------------------------------------------------- -static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) -{ - uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE]; - - uncompressed_bytes_cnt = 0; - - // initialize z_stream structure for inflate: - compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start; - compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start; - compressed_fpga_stream->next_out = output_buffer; - compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN; - compressed_fpga_stream->zalloc = &fpga_inflate_malloc; - compressed_fpga_stream->zfree = &fpga_inflate_free; - - inflateInit2(compressed_fpga_stream, 0); - - fpga_image_ptr = output_buffer; - - for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++) { - header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); - } - - // Check for a valid .bit file (starts with bitparse_fixed_header) - if(memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) { - return true; - } else { - return false; - } -} - - static void DownloadFPGA_byte(unsigned char w) { #define SEND_BIT(x) { if(w & (1<PIO_OER = GPIO_FPGA_ON; AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON; - HIGH(GPIO_FPGA_ON); // ensure everything is powered on + HIGH(GPIO_FPGA_ON); // ensure everything is powered on SpinDelay(50); LED_D_ON(); // These pins are inputs - AT91C_BASE_PIOA->PIO_ODR = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; + AT91C_BASE_PIOA->PIO_ODR = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; // PIO controls the following pins - AT91C_BASE_PIOA->PIO_PER = - GPIO_FPGA_NINIT | - GPIO_FPGA_DONE; + AT91C_BASE_PIOA->PIO_PER = + GPIO_FPGA_NINIT | + GPIO_FPGA_DONE; // Enable pull-ups AT91C_BASE_PIOA->PIO_PPUER = GPIO_FPGA_NINIT | @@ -304,8 +196,8 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp LOW(GPIO_FPGA_DIN); // These pins are outputs AT91C_BASE_PIOA->PIO_OER = - GPIO_FPGA_NPROGRAM | - GPIO_FPGA_CCLK | + GPIO_FPGA_NPROGRAM | + GPIO_FPGA_CCLK | GPIO_FPGA_DIN; // enter FPGA configuration mode @@ -326,13 +218,21 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp return; } - for(i = 0; i < FpgaImageLen; i++) { - int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); - if (b < 0) { - Dbprintf("Error %d during FpgaDownload", b); - break; + if(bytereversal) { + /* This is only supported for uint32_t aligned images */ + if( ((int)FpgaImage % sizeof(uint32_t)) == 0 ) { + i=0; + while(FpgaImageLen-->0) + DownloadFPGA_byte(FpgaImage[(i++)^0x3]); + /* Explanation of the magic in the above line: + * i^0x3 inverts the lower two bits of the integer i, counting backwards + * for each 4 byte increment. The generated sequence of (i++)^3 is + * 3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 etc. pp. + */ } - DownloadFPGA_byte(b); + } else { + while(FpgaImageLen-->0) + DownloadFPGA_byte(*FpgaImage++); } // continue to clock FPGA until ready signal goes high @@ -350,21 +250,39 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp LED_D_OFF(); } - +static char *bitparse_headers_start; +static char *bitparse_bitstream_end; +static int bitparse_initialized; /* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence * 00 09 0f f0 0f f0 0f f0 0f f0 00 00 01 * After that the format is 1 byte section type (ASCII character), 2 byte length * (big endian), bytes content. Except for section 'e' which has 4 bytes * length. */ -static int bitparse_find_section(int bitstream_version, char section_name, unsigned int *section_length, z_streamp compressed_fpga_stream, uint8_t *output_buffer) +static const char _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; +static int bitparse_init(void * start_address, void *end_address) { + bitparse_initialized = 0; + + if(memcmp(_bitparse_fixed_header, start_address, sizeof(_bitparse_fixed_header)) != 0) { + return 0; /* Not matched */ + } else { + bitparse_headers_start= ((char*)start_address) + sizeof(_bitparse_fixed_header); + bitparse_bitstream_end= (char*)end_address; + bitparse_initialized = 1; + return 1; + } +} + +int bitparse_find_section(char section_name, char **section_start, unsigned int *section_length) +{ + char *pos = bitparse_headers_start; int result = 0; - #define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section - uint16_t numbytes = 0; - while(numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) { - char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); - numbytes++; + + if(!bitparse_initialized) return 0; + + while(pos < bitparse_bitstream_end) { + char current_name = *pos++; unsigned int current_length = 0; if(current_name < 'a' || current_name > 'e') { /* Strange section name, abort */ @@ -374,13 +292,11 @@ static int bitparse_find_section(int bitstream_version, char section_name, unsig switch(current_name) { case 'e': /* Four byte length field */ - current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 24; - current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 16; - numbytes += 2; + current_length += (*pos++) << 24; + current_length += (*pos++) << 16; default: /* Fall through, two byte length field */ - current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8; - current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0; - numbytes += 2; + current_length += (*pos++) << 8; + current_length += (*pos++) << 0; } if(current_name != 'e' && current_length > 255) { @@ -390,90 +306,103 @@ static int bitparse_find_section(int bitstream_version, char section_name, unsig if(current_name == section_name) { /* Found it */ + *section_start = pos; *section_length = current_length; result = 1; break; } - for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) { - get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer); - numbytes++; - } + pos += current_length; /* Skip section */ } return result; } - -//---------------------------------------------------------------------------- -// Check which FPGA image is currently loaded (if any). If necessary -// decompress and load the correct (HF or LF) image to the FPGA -//---------------------------------------------------------------------------- -void FpgaDownloadAndGo(int bitstream_version) +//----------------------------------------------------------------------------- +// Find out which FPGA image format is stored in flash, then call DownloadFPGA +// with the right parameters to download the image +//----------------------------------------------------------------------------- +extern char _binary_fpga_bit_start, _binary_fpga_bit_end; +void FpgaDownloadAndGo(void) { - z_stream compressed_fpga_stream; - uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; + /* Check for the new flash image format: Should have the .bit file at &_binary_fpga_bit_start + */ + if(bitparse_init(&_binary_fpga_bit_start, &_binary_fpga_bit_end)) { + /* Successfully initialized the .bit parser. Find the 'e' section and + * send its contents to the FPGA. + */ + char *bitstream_start; + unsigned int bitstream_length; + if(bitparse_find_section('e', &bitstream_start, &bitstream_length)) { + DownloadFPGA(bitstream_start, bitstream_length, 0); - // check whether or not the bitstream is already loaded - if (downloaded_bitstream == bitstream_version) { - FpgaEnableTracing(); - return; + return; /* All done */ + } } - // make sure that we have enough memory to decompress - BigBuf_free(); BigBuf_Clear_ext(false); - - if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer)) { - return; - } - - unsigned int bitstream_length; - if (bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) { - DownloadFPGA(bitstream_version, bitstream_length, &compressed_fpga_stream, output_buffer); - downloaded_bitstream = bitstream_version; - } - - inflateEnd(&compressed_fpga_stream); - - // turn off antenna - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - // free eventually allocated BigBuf memory - BigBuf_free(); BigBuf_Clear_ext(false); + /* Fallback for the old flash image format: Check for the magic marker 0xFFFFFFFF + * 0xAA995566 at address 0x102000. This is raw bitstream with a size of 336,768 bits + * = 10,524 uint32_t, stored as uint32_t e.g. little-endian in memory, but each DWORD + * is still to be transmitted in MSBit first order. Set the invert flag to indicate + * that the DownloadFPGA function should invert every 4 byte sequence when doing + * the bytewise download. + */ + if( *(uint32_t*)0x102000 == 0xFFFFFFFF && *(uint32_t*)0x102004 == 0xAA995566 ) + DownloadFPGA((char*)0x102000, 10524*4, 1); } +void FpgaGatherVersion(char *dst, int len) +{ + char *fpga_info; + unsigned int fpga_info_len; + dst[0] = 0; + if(!bitparse_find_section('e', &fpga_info, &fpga_info_len)) { + strncat(dst, "FPGA image: legacy image without version information", len-1); + } else { + strncat(dst, "FPGA image built", len-1); + /* USB packets only have 48 bytes data payload, so be terse */ +#if 0 + if(bitparse_find_section('a', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + strncat(dst, " from ", len-1); + strncat(dst, fpga_info, len-1); + } + if(bitparse_find_section('b', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + strncat(dst, " for ", len-1); + strncat(dst, fpga_info, len-1); + } +#endif + if(bitparse_find_section('c', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + strncat(dst, " on ", len-1); + strncat(dst, fpga_info, len-1); + } + if(bitparse_find_section('d', &fpga_info, &fpga_info_len) && fpga_info[fpga_info_len-1] == 0 ) { + strncat(dst, " at ", len-1); + strncat(dst, fpga_info, len-1); + } + } +} //----------------------------------------------------------------------------- // Send a 16 bit command/data pair to the FPGA. // The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 // where C is the 4 bit command and D is the 12 bit data //----------------------------------------------------------------------------- -void FpgaSendCommand(uint16_t cmd, uint16_t v) { +void FpgaSendCommand(uint16_t cmd, uint16_t v) +{ SetupSpi(SPI_FPGA_MODE); - AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // write the data to be sent - while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete + while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete + AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data } - //----------------------------------------------------------------------------- // Write the FPGA setup word (that determines what mode the logic is in, read // vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to // avoid changing this function's occurence everywhere in the source code. //----------------------------------------------------------------------------- -void FpgaWriteConfWord(uint16_t v) { +void FpgaWriteConfWord(uint8_t v) +{ FpgaSendCommand(FPGA_CMD_SET_CONFREG, v); } -//----------------------------------------------------------------------------- -// enable/disable FPGA internal tracing -//----------------------------------------------------------------------------- -void FpgaEnableTracing(void) { - FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 1); -} - -void FpgaDisableTracing(void) { - FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 0); -} - //----------------------------------------------------------------------------- // Set up the CMOS switches that mux the ADC: four switches, independently // closable, but should only close one at a time. Not an FPGA thing, but @@ -500,12 +429,3 @@ void SetAdcMuxFor(uint32_t whichGpio) HIGH(whichGpio); } - -void Fpga_print_status(void) { - Dbprintf("Currently loaded FPGA image:"); - Dbprintf(" %s", fpga_version_information[downloaded_bitstream-1]); -} - -int FpgaGetCurrent() { - return downloaded_bitstream; -} diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h deleted file mode 100644 index 57e9c28a..00000000 --- a/armsrc/fpgaloader.h +++ /dev/null @@ -1,99 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, April 2006 -// iZsh , 2014 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to load the FPGA image, and then to configure the FPGA's major -// mode once it is configured. -//----------------------------------------------------------------------------- - -#ifndef __FPGALOADER_H -#define __FPGALOADER_H - -#include -#include - -void FpgaSendCommand(uint16_t cmd, uint16_t v); -void FpgaWriteConfWord(uint16_t v); -void FpgaDownloadAndGo(int bitstream_version); -void FpgaSetupSsc(uint16_t mode); -void SetupSpi(int mode); -bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count); -void Fpga_print_status(); -int FpgaGetCurrent(); -void FpgaEnableTracing(void); -void FpgaDisableTracing(void); -#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; -#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; -void SetAdcMuxFor(uint32_t whichGpio); - -// definitions for multiple FPGA config files support -#define FPGA_BITSTREAM_LF 1 -#define FPGA_BITSTREAM_HF 2 - -// Definitions for the FPGA commands. -#define FPGA_CMD_MASK 0xF000 -// BOTH -#define FPGA_CMD_SET_CONFREG (1<<12) -// LF -#define FPGA_CMD_SET_DIVISOR (2<<12) -#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD (3<<12) -// HF -#define FPGA_CMD_TRACE_ENABLE (2<<12) - -// Definitions for the FPGA configuration word. -#define FPGA_MAJOR_MODE_MASK 0x01C0 -// LF -#define FPGA_MAJOR_MODE_LF_ADC (0<<6) -#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<6) -#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<6) -// HF -#define FPGA_MAJOR_MODE_HF_READER (0<<6) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6) -#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6) -#define FPGA_MAJOR_MODE_HF_SNOOP (3<<6) -#define FPGA_MAJOR_MODE_HF_GET_TRACE (4<<6) -// BOTH -#define FPGA_MAJOR_MODE_OFF (7<<6) - -#define FPGA_MINOR_MODE_MASK 0x003F -// Options for LF_ADC -#define FPGA_LF_ADC_READER_FIELD (1<<0) - -// Options for LF_EDGE_DETECT -#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) -#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (2<<0) - -// Options for the HF reader -#define FPGA_HF_READER_MODE_RECEIVE_IQ (0<<0) -#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE (1<<0) -#define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0) -#define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0) -#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0) -#define FPGA_HF_READER_MODE_SNOOP_IQ (5<<0) -#define FPGA_HF_READER_MODE_SNOOP_AMPLITUDE (6<<0) -#define FPGA_HF_READER_MODE_SNOOP_PHASE (7<<0) -#define FPGA_HF_READER_MODE_SEND_JAM (8<<0) - -#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4) -#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<4) -#define FPGA_HF_READER_SUBCARRIER_212_KHZ (2<<4) - -// Options for the HF simulated tag, how to modulate -#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) -#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) -#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) -#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) -#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5//101 - -// Options for ISO14443A -#define FPGA_HF_ISO14443A_SNIFFER (0<<0) -#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) -#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) -#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) -#define FPGA_HF_ISO14443A_READER_MOD (4<<0) - -#endif diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c deleted file mode 100644 index 3a0ac65f..00000000 --- a/armsrc/hfsnoop.c +++ /dev/null @@ -1,118 +0,0 @@ -//----------------------------------------------------------------------------- -// piwi, 2019 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to get sample data from FPGA. -//----------------------------------------------------------------------------- - -#include "hfsnoop.h" - -#include "proxmark3.h" -#include "BigBuf.h" -#include "util.h" -#include "apps.h" -#include "usb_cdc.h" -#include "fpga.h" -#include "fpgaloader.h" - -static void RAMFUNC optimizedSnoop(void) -{ - int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory - - uint16_t *dest = (uint16_t *)BigBuf_get_addr(); - uint16_t *destend = dest + n; - - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); // Setting Frame mode, 16 bits per word - // Reading data loop - while(dest <= destend) - { - if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) - { - *dest = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); - dest++; - } - } - //Resetting Frame mode (First set in fpgaloader.c) - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); -} - -void HfSnoop(int samplesToSkip, int triggersToSkip) -{ - BigBuf_free(); BigBuf_Clear(); - - Dbprintf("Skipping first %d sample pairs, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); - int trigger_cnt; - LED_D_ON(); - // Select correct configs - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNOOP); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); - SpinDelay(100); - - AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16); // Setting Frame Mode For better performance on high speed data transfer. - - trigger_cnt = 0; - uint16_t r = 0; - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - WDT_HIT(); - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - r = (uint16_t)AT91C_BASE_SSC->SSC_RHR; - r = MAX(r & 0xff, r >> 8); - if (r >= 240) { - if (++trigger_cnt > triggersToSkip) - break; - } - } - } - - if(!BUTTON_PRESS()) { - int waitcount = samplesToSkip; // lets wait 40000 ticks of pck0 - while(waitcount != 0) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) - waitcount--; - } - optimizedSnoop(); - Dbprintf("Trigger kicked! Value: %d, Dumping Samples Hispeed now.", r); - } - - DbpString("HF Snoop end"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); -} - -void HfPlot(void) -{ - uint8_t *buf = ToSend; - uint8_t *this_buf = buf; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE); - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer - AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address - AT91C_BASE_PDC_SSC->PDC_RCR = USB_CMD_DATA_SIZE; // transfer this many samples - buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM - - LED_B_ON(); - for(size_t i = 0; i < FPGA_TRACE_SIZE; i += USB_CMD_DATA_SIZE) { - // prepare next DMA transfer: - uint8_t *next_buf = buf + ((i + USB_CMD_DATA_SIZE) % (2 * USB_CMD_DATA_SIZE)); - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf; - AT91C_BASE_PDC_SSC->PDC_RNCR = USB_CMD_DATA_SIZE; - size_t len = MIN(FPGA_TRACE_SIZE - i, USB_CMD_DATA_SIZE); - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX))) ; // wait for DMA transfer to complete - cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, i, len, FPGA_TRACE_SIZE, this_buf, len); - this_buf = next_buf; - } - // Trigger a finish downloading signal with an ACK frame - cmd_send(CMD_ACK, 1, 0, FPGA_TRACE_SIZE, 0, 0); - LED_B_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -} diff --git a/armsrc/hfsnoop.h b/armsrc/hfsnoop.h deleted file mode 100644 index 8c45e170..00000000 --- a/armsrc/hfsnoop.h +++ /dev/null @@ -1,17 +0,0 @@ -//----------------------------------------------------------------------------- -// piwi, 2019 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to get sample data from FPGA. -//----------------------------------------------------------------------------- - -#ifndef HFSNOOP_H__ -#define HFSNOOP_H__ - -void HfSnoop(int samplesToSkip, int triggersToSkip); -void HfPlot(void); - -#endif diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 688805be..1a0e9b56 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,26 +16,42 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- -#include "hitag2.h" - #include "proxmark3.h" -#include "usb_cdc.h" #include "apps.h" #include "util.h" -#include "hitag.h" +#include "hitag2.h" #include "string.h" -#include "BigBuf.h" -#include "fpgaloader.h" -#include "protocols.h" static bool bQuiet; -static bool bCrypto; -static bool bAuthenticating; -static bool bPwd; -static bool bSuccessful; - +bool bCrypto; +bool bAuthenticating; +bool bPwd; +bool bSuccessful; +int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader) +{ + // Return when trace is full + if (traceLen >= TRACE_SIZE) return FALSE; + + // Trace the random, i'm curious + rsamples += iSamples; + trace[traceLen++] = ((rsamples >> 0) & 0xff); + trace[traceLen++] = ((rsamples >> 8) & 0xff); + trace[traceLen++] = ((rsamples >> 16) & 0xff); + trace[traceLen++] = ((rsamples >> 24) & 0xff); + if (!bReader) { + trace[traceLen - 1] |= 0x80; + } + trace[traceLen++] = ((dwParity >> 0) & 0xff); + trace[traceLen++] = ((dwParity >> 8) & 0xff); + trace[traceLen++] = ((dwParity >> 16) & 0xff); + trace[traceLen++] = ((dwParity >> 24) & 0xff); + trace[traceLen++] = iBits; + memcpy(trace + traceLen, btBytes, nbytes(iBits)); + traceLen += nbytes(iBits); + return TRUE; +} struct hitag2_tag { uint32_t uid; @@ -46,48 +62,44 @@ struct hitag2_tag { TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written } state; unsigned int active_sector; - uint8_t crypto_active; + byte_t crypto_active; uint64_t cs; - uint8_t sectors[12][4]; + byte_t sectors[12][4]; }; static struct hitag2_tag tag = { - .state = TAG_STATE_RESET, - .sectors = { // Password mode: | Crypto mode: - [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID - [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key - [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved - [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG - [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK - [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... - [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low - [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High - [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF - [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC - }, + .state = TAG_STATE_RESET, + .sectors = { // Password mode: | Crypto mode: + [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID + [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key + [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved + [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG + [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK + [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... + [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low + [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High + [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF + [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC + }, }; -static enum { - WRITE_STATE_START = 0x0, - WRITE_STATE_PAGENUM_WRITTEN, - WRITE_STATE_PROG -} writestate; +//#define TRACE_LENGTH 3000 +//uint8_t *trace = (uint8_t *) BigBuf; +//int traceLen = 0; +//int rsamples = 0; +#define AUTH_TABLE_OFFSET FREE_BUFFER_OFFSET +#define AUTH_TABLE_LENGTH FREE_BUFFER_SIZE +byte_t* auth_table = (byte_t *)BigBuf+AUTH_TABLE_OFFSET; +size_t auth_table_pos = 0; +size_t auth_table_len = AUTH_TABLE_LENGTH; -// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. -// Historically it used to be FREE_BUFFER_SIZE, which was 2744. -#define AUTH_TABLE_LENGTH 2744 -static uint8_t *auth_table; -static size_t auth_table_pos = 0; -static size_t auth_table_len = AUTH_TABLE_LENGTH; - -static uint8_t password[4]; -static uint8_t NrAr[8]; -static uint8_t key[8]; -static uint8_t writedata[4]; -static uint64_t cipher_state; +byte_t password[4]; +byte_t NrAr[8]; +byte_t key[8]; +uint64_t cipher_state; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ // Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007. @@ -95,89 +107,112 @@ static uint64_t cipher_state; // No warranties or guarantees of any kind. // This code is released into the public domain by its author. +// Basic macros: + +#define u8 uint8_t +#define u32 uint32_t +#define u64 uint64_t +#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) +#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) +#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) +#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) +#define bit(x,n) (((x)>>(n))&1) +#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) +#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) +#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) + // Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 -static uint32_t _f20(const uint64_t x) { - uint32_t i5; +static u32 _f20 (const u64 x) +{ + u32 i5; - i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 - + ((ht2_f4b >> i4(x, 7,11,13,14)) & 1) * 2 - + ((ht2_f4b >> i4(x,16,20,22,25)) & 1) * 4 - + ((ht2_f4b >> i4(x,27,28,30,32)) & 1) * 8 - + ((ht2_f4a >> i4(x,33,42,43,45)) & 1) * 16; + i5 = ((ht2_f4a >> i4 (x, 1, 2, 4, 5)) & 1)* 1 + + ((ht2_f4b >> i4 (x, 7,11,13,14)) & 1)* 2 + + ((ht2_f4b >> i4 (x,16,20,22,25)) & 1)* 4 + + ((ht2_f4b >> i4 (x,27,28,30,32)) & 1)* 8 + + ((ht2_f4a >> i4 (x,33,42,43,45)) & 1)*16; return (ht2_f5c >> i5) & 1; } -static uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) { - uint32_t i; - uint64_t x = ((key & 0xFFFF) << 32) + serial; +static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) +{ + u32 i; + u64 x = ((key & 0xFFFF) << 32) + serial; - for (i = 0; i < 32; i++) { + for (i = 0; i < 32; i++) + { x >>= 1; - x += (uint64_t)(_f20(x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; + x += (u64) (_f20 (x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; } return x; } -static uint64_t _hitag2_round(uint64_t *state) { - uint64_t x = *state; +static u64 _hitag2_round (u64 *state) +{ + u64 x = *state; x = (x >> 1) + - ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) - ^ (x >> 7) ^ (x >> 8) ^ (x >> 16) ^ (x >> 22) - ^ (x >> 23) ^ (x >> 26) ^ (x >> 30) ^ (x >> 41) - ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) + ^ (x >> 7) ^ (x >> 8) ^ (x >> 16) ^ (x >> 22) + ^ (x >> 23) ^ (x >> 26) ^ (x >> 30) ^ (x >> 41) + ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); *state = x; - return _f20(x); + return _f20 (x); } -static uint32_t _hitag2_byte(uint64_t *x) { - uint32_t i, c; - for (i = 0, c = 0; i < 8; i++) { - c += (uint32_t) _hitag2_round(x) << (i^7); - } +static u32 _hitag2_byte (u64 * x) +{ + u32 i, c; + + for (i = 0, c = 0; i < 8; i++) c += (u32) _hitag2_round (x) << (i^7); return c; } -static int hitag2_reset(void) { +int hitag2_reset(void) +{ tag.state = TAG_STATE_RESET; tag.crypto_active = 0; return 0; } -static int hitag2_init(void) { +int hitag2_init(void) +{ +// memcpy(&tag, &resetdata, sizeof(tag)); hitag2_reset(); return 0; } -static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv) { - uint64_t key = ((uint64_t)tag->sectors[2][2]) | - ((uint64_t)tag->sectors[2][3] << 8) | - ((uint64_t)tag->sectors[1][0] << 16) | - ((uint64_t)tag->sectors[1][1] << 24) | - ((uint64_t)tag->sectors[1][2] << 32) | - ((uint64_t)tag->sectors[1][3] << 40); - uint32_t uid = ((uint32_t)tag->sectors[0][0]) | - ((uint32_t)tag->sectors[0][1] << 8) | - ((uint32_t)tag->sectors[0][2] << 16) | - ((uint32_t)tag->sectors[0][3] << 24); +static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) +{ + uint64_t key = ((uint64_t)tag->sectors[2][2]) | + ((uint64_t)tag->sectors[2][3] << 8) | + ((uint64_t)tag->sectors[1][0] << 16) | + ((uint64_t)tag->sectors[1][1] << 24) | + ((uint64_t)tag->sectors[1][2] << 32) | + ((uint64_t)tag->sectors[1][3] << 40); + uint32_t uid = ((uint32_t)tag->sectors[0][0]) | + ((uint32_t)tag->sectors[0][1] << 8) | + ((uint32_t)tag->sectors[0][2] << 16) | + ((uint32_t)tag->sectors[0][3] << 24); uint32_t iv_ = (((uint32_t)(iv[0]))) | - (((uint32_t)(iv[1])) << 8) | - (((uint32_t)(iv[2])) << 16) | - (((uint32_t)(iv[3])) << 24); - tag->cs = _hitag2_init(REV64(key), REV32(uid), REV32(iv_)); + (((uint32_t)(iv[1])) << 8) | + (((uint32_t)(iv[2])) << 16) | + (((uint32_t)(iv[3])) << 24); + tag->cs = _hitag2_init(rev64(key), rev32(uid), rev32(iv_)); } -static int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) { - uint8_t authenticator_should[4]; +static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_is) +{ + byte_t authenticator_should[4]; authenticator_should[0] = ~_hitag2_byte(cs); authenticator_should[1] = ~_hitag2_byte(cs); authenticator_should[2] = ~_hitag2_byte(cs); @@ -185,10 +220,11 @@ static int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator return (memcmp(authenticator_should, authenticator_is, 4) == 0); } -static int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, unsigned int bytes, unsigned int bits) { +static int hitag2_cipher_transcrypt(uint64_t* cs, byte_t *data, unsigned int bytes, unsigned int bits) +{ int i; - for (i = 0; i < bytes; i++) data[i] ^= _hitag2_byte(cs); - for (i = 0; i < bits; i++) data[bytes] ^= _hitag2_round(cs) << (7-i); + for(i=0; i 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ -//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + +#define HITAG_FRAME_LEN 20 +#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ -#define HITAG_T_PROG 614 -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 -#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 + +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 +#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 -#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 -#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 static void hitag_send_bit(int bit) { LED_A_ON(); - // Reset clock for the next bit + // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + // Fixed modulation, earlier proxmark version used inverted signal - if (bit == 0) { + if(bit == 0) { // Manchester: Unloaded, then loaded |__--| LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } else { // Manchester: Loaded, then unloaded |--__| HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } LED_A_OFF(); } -static void hitag_send_frame(const uint8_t *frame, size_t frame_len) +static void hitag_send_frame(const byte_t* frame, size_t frame_len) { // Send start of frame - for(size_t i = 0; i < 5; i++) { + for(size_t i=0; i<5; i++) { hitag_send_bit(1); } // Send the content of the frame - for (size_t i = 0; i < frame_len; i++) { - hitag_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); + for(size_t i=0; i> (7-(i%8)))&1); } // Drop the modulation LOW(GPIO_SSC_DOUT); } -static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { - uint8_t rx_air[HITAG_FRAME_LEN]; - +void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) +{ + byte_t rx_air[HITAG_FRAME_LEN]; + // Copy the (original) received frame how it is send over the air - memcpy(rx_air, rx, nbytes(rxlen)); + memcpy(rx_air,rx,nbytes(rxlen)); - if (tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen/8, rxlen%8); + if(tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); } - - // Reset the transmission frame length + + // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { - // Received 11000 from the reader, request for UID, send UID + // Received 11000 from the reader, request for UID, send UID case 05: { // Always send over the air in the clear plaintext mode - if (rx_air[0] != HITAG2_START_AUTH) { + if(rx_air[0] != 0xC0) { // Unknown frame ? return; } *txlen = 32; - memcpy(tx, tag.sectors[0], 4); + memcpy(tx,tag.sectors[0],4); tag.crypto_active = 0; } break; - // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number + // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number case 10: { - unsigned int sector = (~( ((rx[0]<<2) & 0x04) | ((rx[1]>>6) & 0x03) ) & 0x07); + unsigned int sector = (~( ((rx[0]<<2)&0x04) | ((rx[1]>>6)&0x03) ) & 0x07); // Verify complement of sector index - if (sector != ((rx[0]>>3) & 0x07)) { + if(sector != ((rx[0]>>3)&0x07)) { //DbpString("Transmission error (read/write)"); return; } switch (rx[0] & 0xC6) { // Read command: 11xx x00y - case HITAG2_READ_PAGE: - memcpy(tx, tag.sectors[sector], 4); + case 0xC0: + memcpy(tx,tag.sectors[sector],4); *txlen = 32; - break; - - // Inverted Read command: 01xx x10y - case HITAG2_READ_PAGE_INVERTED: - for (size_t i = 0; i < 4; i++) { + break; + + // Inverted Read command: 01xx x10y + case 0x44: + for (size_t i=0; i<4; i++) { tx[i] = tag.sectors[sector][i] ^ 0xff; } *txlen = 32; - break; + break; // Write command: 10xx x01y - case HITAG2_WRITE_PAGE: + case 0x82: // Prepare write, acknowledge by repeating command - memcpy(tx, rx, nbytes(rxlen)); + memcpy(tx,rx,nbytes(rxlen)); *txlen = rxlen; tag.active_sector = sector; - tag.state = TAG_STATE_WRITING; - break; - + tag.state=TAG_STATE_WRITING; + break; + // Unknown command default: - Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); + Dbprintf("Uknown command: %02x %02x",rx[0],rx[1]); return; - break; + break; } } break; // Writing data or Reader password case 32: { - if (tag.state == TAG_STATE_WRITING) { + if(tag.state == TAG_STATE_WRITING) { // These are the sector contents to be written. We don't have to do anything else. - memcpy(tag.sectors[tag.active_sector], rx, nbytes(rxlen)); - tag.state = TAG_STATE_RESET; + memcpy(tag.sectors[tag.active_sector],rx,nbytes(rxlen)); + tag.state=TAG_STATE_RESET; return; } else { // Received RWD password, respond with configuration and our password - if (memcmp(rx, tag.sectors[1], 4) != 0) { + if(memcmp(rx,tag.sectors[1],4) != 0) { DbpString("Reader password is wrong"); return; } *txlen = 32; - memcpy(tx, tag.sectors[3], 4); + memcpy(tx,tag.sectors[3],4); } } break; @@ -354,16 +394,16 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ case 64: { // Store the authentication attempt if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { - memcpy(auth_table+auth_table_len, rx, 8); + memcpy(auth_table+auth_table_len,rx,8); auth_table_len += 8; } // Reset the cipher state - hitag2_cipher_reset(&tag, rx); + hitag2_cipher_reset(&tag,rx); // Check if the authentication was correct - if (!hitag2_cipher_authenticate(&(tag.cs), rx+4)) { + if(!hitag2_cipher_authenticate(&(tag.cs),rx+4)) { // The reader failed to authenticate, do nothing - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); return; } // Succesful, but commented out reporting back to the Host, this may delay to much. @@ -373,295 +413,220 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ tag.crypto_active = 1; // Use the tag password as response - memcpy(tx, tag.sectors[3], 4); + memcpy(tx,tag.sectors[3],4); *txlen = 32; } break; } - // LogTraceHitag(rx, rxlen, 0, 0, false); - // LogTraceHitag(tx, *txlen, 0, 0, true); - - if (tag.crypto_active) { +// LogTraceHitag(rx,rxlen,0,0,false); +// LogTraceHitag(tx,*txlen,0,0,true); + + if(tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); } } static void hitag_reader_send_bit(int bit) { LED_A_ON(); - // Reset clock for the next bit + // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + // Binary puls length modulation (BPLM) is used to encode the data stream // This means that a transmission of a one takes longer than that of a zero - - // Enable modulation, which means, drop the field + + // Enable modulation, which means, drop the the field HIGH(GPIO_SSC_DOUT); - - // t_low = 4...10 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*6); - + + // Wait for 4-10 times the carrier period + while(AT91C_BASE_TC0->TC_CV < T0*6); + // SpinDelayUs(8*8); + // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); - - if (bit == 0) { - // Zero bit: |_-|, T[0] = 18...22 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*22); + + if(bit == 0) { + // Zero bit: |_-| + while(AT91C_BASE_TC0->TC_CV < T0*22); + // SpinDelayUs(16*8); } else { - // One bit: |_--|, T[1] = 26...32 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*28); + // One bit: |_--| + while(AT91C_BASE_TC0->TC_CV < T0*28); + // SpinDelayUs(22*8); } LED_A_OFF(); } - -static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) +static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) { // Send the content of the frame - for(size_t i = 0; i < frame_len; i++) { - hitag_reader_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); + for(size_t i=0; i> (7-(i%8)))&1); } - // Send EOF + // Send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - // Enable modulation, which means, drop the field + // Enable modulation, which means, drop the the field HIGH(GPIO_SSC_DOUT); - // t_low = 4...10 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*6); + // Wait for 4-10 times the carrier period + while(AT91C_BASE_TC0->TC_CV < T0*6); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); - // t_stop > 36 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*36); } size_t blocknr; -//----------------------------------------------------------------------------- -// Hitag2 operations -//----------------------------------------------------------------------------- - -static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { - switch (writestate) { - case WRITE_STATE_START: - tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - *txlen = 10; - writestate = WRITE_STATE_PAGENUM_WRITTEN; - break; - case WRITE_STATE_PAGENUM_WRITTEN: - // Check if page number was received correctly - if ((rxlen == 10) - && (rx[0] == (HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2))) - && (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { +bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer (after sending password) + if (bPwd) { + DbpString("Password failed!"); + return false; + } + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, tag password + case 32: { + if (!bPwd) { *txlen = 32; - memset(tx, 0, HITAG_FRAME_LEN); - memcpy(tx, writedata, 4); - writestate = WRITE_STATE_PROG; + memcpy(tx,password,4); + bPwd = true; + memcpy(tag.sectors[blocknr],rx,4); + blocknr++; } else { - Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen=%d rx=%02x%02x%02x%02x", - rxlen, rx[0], rx[1], rx[2], rx[3]); - bSuccessful = false; - return false; + + if(blocknr == 1){ + //store password in block1, the TAG answers with Block3, but we need the password in memory + memcpy(tag.sectors[blocknr],tx,4); + }else{ + memcpy(tag.sectors[blocknr],rx,4); } - break; - case WRITE_STATE_PROG: - if (rxlen == 0) { - bSuccessful = true; + + blocknr++; + if (blocknr > 7) { + DbpString("Read succesful!"); + bSuccessful = true; + return false; + } + *txlen = 10; + tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + } + } break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d",rxlen); + return false; + } break; + } + return true; +} + +bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length + *txlen = 0; + + if(bCrypto) { + hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8); + } + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + // Failed during authentication + if (bAuthenticating) { + DbpString("Authentication failed!"); + return false; + } else { + // Failed reading a block, could be (read/write) locked, skip block and re-authenticate + if (blocknr == 1) { + // Write the low part of the key in memory + memcpy(tag.sectors[1],key+2,4); + } else if (blocknr == 2) { + // Write the high part of the key in memory + tag.sectors[2][0] = 0x00; + tag.sectors[2][1] = 0x00; + tag.sectors[2][2] = key[0]; + tag.sectors[2][3] = key[1]; + } else { + // Just put zero's in the memory (of the unreadable block) + memset(tag.sectors[blocknr],0x00,4); + } + blocknr++; + bCrypto = false; + } } else { - bSuccessful = false; - Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); + *txlen = 5; + memcpy(tx,"\xc0",nbytes(*txlen)); + } + } break; + + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; + uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; + cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0); + memset(tx,0x00,4); + memset(tx+4,0xff,4); + hitag2_cipher_transcrypt(&cipher_state,tx+4,4,0); + *txlen = 64; + bCrypto = true; + bAuthenticating = true; + } else { + // Check if we received answer tag (at) + if (bAuthenticating) { + bAuthenticating = false; + } else { + // Store the received block + memcpy(tag.sectors[blocknr],rx,4); + blocknr++; + } + if (blocknr > 7) { + DbpString("Read succesful!"); + bSuccessful = true; + return false; + } + *txlen = 10; + tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); } + } break; + + // Unexpected response + default: { + Dbprintf("Uknown frame length: %d",rxlen); return false; - default: - DbpString("hitag2_write_page: Unknown state %d"); - bSuccessful = false; - return false; + } break; + } + + + if(bCrypto) { + // We have to return now to avoid double encryption + if (!bAuthenticating) { + hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8); + } } return true; } -static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { - // Reset the transmission frame length + +bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length *txlen = 0; - - if (bPwd && !bAuthenticating && write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { - return false; - } - } else { - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer (after sending password) - if (bPwd) { - DbpString("Password failed!"); - return false; - } - tx[0] = HITAG2_START_AUTH; - *txlen = 5; - } - break; - - // Received UID, tag password - case 32: { - if (!bPwd) { - bPwd = true; - bAuthenticating = true; - memcpy(tx, password, 4); - *txlen = 32; - } else { - if (bAuthenticating) { - bAuthenticating = false; - if (write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { - return false; - } - break; - } - } else { - memcpy(tag.sectors[blocknr], rx, 4); - blocknr++; - } - - if (blocknr > 7) { - DbpString("Read successful!"); - bSuccessful = true; - return false; - } - tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - *txlen = 10; - } - } - break; - - // Unexpected response - default: { - Dbprintf("Unknown frame length: %d", rxlen); - return false; - } - break; - } - } - - return true; -} - -static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { - // Reset the transmission frame length - *txlen = 0; - - if (bCrypto) { - hitag2_cipher_transcrypt(&cipher_state, rx, rxlen/8, rxlen%8); - } - - if (bCrypto && !bAuthenticating && write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { - return false; - } - } else { - - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - // Failed during authentication - if (bAuthenticating) { - DbpString("Authentication failed!"); - return false; - } else { - // Failed reading a block, could be (read/write) locked, skip block and re-authenticate - if (blocknr == 1) { - // Write the low part of the key in memory - memcpy(tag.sectors[1], key+2, 4); - } else if (blocknr == 2) { - // Write the high part of the key in memory - tag.sectors[2][0] = 0x00; - tag.sectors[2][1] = 0x00; - tag.sectors[2][2] = key[0]; - tag.sectors[2][3] = key[1]; - } else { - // Just put zero's in the memory (of the unreadable block) - memset(tag.sectors[blocknr], 0x00, 4); - } - blocknr++; - bCrypto = false; - } - } else { - tx[0] = HITAG2_START_AUTH; - *txlen = 5; - } - break; - } - // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; - uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; - Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x", (uint32_t) ((REV64(ui64key)) >> 32), (uint32_t) ((REV64(ui64key)) & 0xffffffff), REV32(ui32uid)); - cipher_state = _hitag2_init(REV64(ui64key), REV32(ui32uid), 0); - memset(tx, 0x00, 4); - memset(tx+4, 0xff, 4); - hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); - *txlen = 64; - bCrypto = true; - bAuthenticating = true; - } else { - // Check if we received answer tag (at) - if (bAuthenticating) { - bAuthenticating = false; - if (write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { - return false; - } - break; - } - } - // stage 2+, got data block - else { - // Store the received block - memcpy(tag.sectors[blocknr], rx, 4); - blocknr++; - } - if (blocknr > 7) { - DbpString("Read successful!"); - bSuccessful = true; - return false; - } else { - tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2); - tx[1] = ((blocknr ^ 7) << 6); - *txlen = 10; - } - } - } - break; - - // Unexpected response - default: { - Dbprintf("Unknown frame length: %d",rxlen); - return false; - } - break; - } - } - - if (bCrypto) { - // We have to return now to avoid double encryption - if (!bAuthenticating) { - hitag2_cipher_transcrypt(&cipher_state, tx, *txlen/8, *txlen%8); - } - } - - return true; -} - -static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { - // Reset the transmission frame length - *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect @@ -671,137 +636,90 @@ static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, si DbpString("Authentication failed!"); return false; } - tx[0] = HITAG2_START_AUTH; *txlen = 5; - } - break; - + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + // Received UID, crypto tag answer case 32: { if (!bCrypto) { - memcpy(tx, NrAr, 8); *txlen = 64; + memcpy(tx,NrAr,8); bCrypto = true; } else { - DbpString("Authentication successful!"); + DbpString("Authentication succesful!"); // We are done... for now return false; } - } - break; - + } break; + // Unexpected response default: { - Dbprintf("Unknown frame length: %d",rxlen); + Dbprintf("Uknown frame length: %d",rxlen); return false; - } - break; + } break; } - + return true; } -static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { - - // Reset the transmission frame length +bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { + // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { - // No answer, try to resurrect + // No answer, try to resurrect case 0: { // Stop if there is no answer while we are in crypto mode (after sending NrAr) if (bCrypto) { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); - // Removing failed entry from authentiations table - memcpy(auth_table+auth_table_pos, auth_table+auth_table_pos+8, 8); - auth_table_len -= 8; + // Removing failed entry from authentiations table + memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8); + auth_table_len -= 8; - // Return if we reached the end of the authentications table + // Return if we reached the end of the authentiactions table bCrypto = false; if (auth_table_pos == auth_table_len) { return false; } - - // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) - memcpy(NrAr, auth_table+auth_table_pos, 8); + + // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) + memcpy(NrAr,auth_table+auth_table_pos,8); } - tx[0] = HITAG2_START_AUTH; *txlen = 5; - } - break; - - // Received UID, crypto tag answer, or read block response + memcpy(tx,"\xc0",nbytes(*txlen)); + } break; + + // Received UID, crypto tag answer, or read block response case 32: { if (!bCrypto) { *txlen = 64; - memcpy(tx, NrAr, 8); + memcpy(tx,NrAr,8); bCrypto = true; } else { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); bCrypto = false; if ((auth_table_pos+8) == auth_table_len) { return false; } auth_table_pos += 8; - memcpy(NrAr, auth_table+auth_table_pos, 8); + memcpy(NrAr,auth_table+auth_table_pos,8); } - } - break; - + } break; + default: { - Dbprintf("Unknown frame length: %d",rxlen); + Dbprintf("Uknown frame length: %d",rxlen); return false; - } - break; - } - - return true; -} - -static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { - // Reset the transmission frame length - *txlen = 0; - - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Just starting or if there is no answer - tx[0] = HITAG2_START_AUTH; - *txlen = 5; - } - break; - // Received UID - case 32: { - // Check if we received answer tag (at) - if (bAuthenticating) { - bAuthenticating = false; - } else { - // Store the received block - memcpy(tag.sectors[blocknr], rx, 4); - blocknr++; - } - if (blocknr > 0) { - //DbpString("Read successful!"); - bSuccessful = true; - return false; - } - } - break; - // Unexpected response - default: { - Dbprintf("Unknown frame length: %d",rxlen); - return false; - } - break; + } break; } + return true; } void SnoopHitag(uint32_t type) { - // int frame_count; + int frame_count; int response; int overflow; bool rising_edge; @@ -809,72 +727,70 @@ void SnoopHitag(uint32_t type) { int lastbit; bool bSkip; int tag_sof; - uint8_t rx[HITAG_FRAME_LEN] = {0}; - size_t rxlen = 0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); auth_table_len = 0; auth_table_pos = 0; - - BigBuf_free(); - auth_table = (uint8_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); - + DbpString("Starting Hitag2 snoop"); LED_D_ON(); - + // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - + RELAY_OFF(); + // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // Disable modulation, we are going to eavesdrop, not modulate ;) LOW(GPIO_SSC_DOUT); - + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration + + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + + // Capture mode, defaul 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_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; - + uint32_t t1_channel_mode = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; + AT91C_BASE_TC1->TC_CMR = t1_channel_mode; + // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + // Reset the received frame, frame count and timing info - // frame_count = 0; + memset(rx,0x00,sizeof(rx)); + frame_count = 0; response = 0; overflow = 0; reader_frame = false; lastbit = 1; bSkip = true; tag_sof = 4; - - while (!BUTTON_PRESS()) { + + while(!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); - + // Find out if we are dealing with a rising or falling edge rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0; @@ -883,35 +799,35 @@ void SnoopHitag(uint32_t type) { // Switch from tag to reader capture LED_C_OFF(); reader_frame = true; - memset(rx, 0x00, sizeof(rx)); + memset(rx,0x00,sizeof(rx)); rxlen = 0; } - + // Only handle if reader frame and rising edge, or tag frame and falling edge if (reader_frame != rising_edge) { - overflow += ra; + overflow += ra; continue; } - + // Add the buffered timing values of earlier captured edges which were skipped ra += overflow; overflow = 0; - + if (reader_frame) { LED_B_ON(); // Capture reader frame - if (ra >= HITAG_T_STOP) { + if(ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit + } else if(ra >= HITAG_T_1_MIN ) { + // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit + } else if(ra >= HITAG_T_0_MIN) { + // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; } else { @@ -920,31 +836,31 @@ void SnoopHitag(uint32_t type) { } else { LED_C_ON(); // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { + 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) { + 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) { + } 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 + // 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) { + } 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 @@ -960,11 +876,11 @@ void SnoopHitag(uint32_t type) { } } } - + // Check if frame was captured - if (rxlen > 0) { - // frame_count++; - if (!LogTraceHitag(rx, rxlen, response, 0, reader_frame)) { + if(rxlen > 0) { + frame_count++; + if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) { DbpString("Trace full"); break; } @@ -977,16 +893,16 @@ void SnoopHitag(uint32_t type) { auth_table_len += 8; } } - + // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); + memset(rx,0x00,sizeof(rx)); response = 0; reader_frame = false; lastbit = 1; bSkip = true; tag_sof = 4; overflow = 0; - + LED_B_OFF(); LED_C_OFF(); } else { @@ -998,67 +914,62 @@ void SnoopHitag(uint32_t type) { // Reset the timer to restart while-loop that receives frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; } - LED_A_ON(); + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); LED_D_OFF(); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - -// Dbprintf("frame received: %d",frame_count); -// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); -// DbpString("All done"); + LED_A_OFF(); + +// Dbprintf("frame received: %d",frame_count); +// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); +// DbpString("All done"); } -void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { - // int frame_count; +void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { + int frame_count; int response; int overflow; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - uint8_t tx[HITAG_FRAME_LEN]; - size_t txlen = 0; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + byte_t tx[HITAG_FRAME_LEN]; + size_t txlen=0; bool bQuitTraceFull = false; bQuiet = false; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - + // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); auth_table_len = 0; auth_table_pos = 0; - uint8_t *auth_table; - BigBuf_free(); - auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); DbpString("Starting Hitag2 simulation"); LED_D_ON(); hitag2_init(); - + if (tag_mem_supplied) { DbpString("Loading hitag2 memory..."); - memcpy((uint8_t*)tag.sectors, data, 48); + memcpy((byte_t*)tag.sectors,data,48); } uint32_t block = 0; - for (size_t i = 0; i < 12; i++) { - for (size_t j = 0; j < 4; j++) { + for (size_t i=0; i<12; i++) { + for (size_t j=0; j<4; j++) { block <<= 8; block |= tag.sectors[i][j]; } - Dbprintf("| %d | %08x |", i, block); + Dbprintf("| %d | %08x |",i,block); } - + // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -1066,64 +977,60 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { // Disable modulation at default, which means release resistance LOW(GPIO_SSC_DOUT); - + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // Capture mode, defaul 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; - - // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - // frame_count = 0; - response = 0; - overflow = 0; - + // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (!BUTTON_PRESS()) { + // Reset the received frame, frame count and timing info + memset(rx,0x00,sizeof(rx)); + frame_count = 0; + response = 0; + overflow = 0; + + while(!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; overflow = 0; // Reset timer every frame, we have to capture the last edge for timing AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + LED_B_ON(); - + // Capture reader frame - if (ra >= HITAG_T_STOP) { + if(ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit + } else if(ra >= HITAG_T_1_MIN ) { + // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit + } else if(ra >= HITAG_T_0_MIN) { + // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; } else { @@ -1131,12 +1038,12 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { } } } - + // Check if frame was captured - if (rxlen > 4) { - // frame_count++; + if(rxlen > 4) { + frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, true)) { + if (!LogTraceHitag(rx,rxlen,response,0,true)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1145,27 +1052,27 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { } } } - + // Disable timer 1 with external trigger to avoid triggers during our own modulation AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitag2_handle_reader_command(rx, rxlen, tx, &txlen); - + hitag2_handle_reader_command(rx,rxlen,tx,&txlen); + // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, // 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 + // periods. The gap time T_Low varies (4..10). All timer values are in // terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); + while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); // Send and store the tag answer (if there is any) if (txlen) { // Transmit the tag frame - hitag_send_frame(tx, txlen); + hitag_send_frame(tx,txlen); // Store the frame in the trace if (!bQuiet) { - if (!LogTraceHitag(tx, txlen, 0, 0, false)) { + if (!LogTraceHitag(tx,txlen,0,0,false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1175,11 +1082,11 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { } } } - + // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); + 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(); @@ -1196,488 +1103,157 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - DbpString("Sim Stopped"); - +// Dbprintf("frame received: %d",frame_count); +// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); +// DbpString("All done"); } -void ReaderHitag(hitag_function htf, hitag_data *htd) { - // int frame_count; +void ReaderHitag(hitag_function htf, hitag_data* htd) { + int frame_count; int response; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - uint8_t txbuf[HITAG_FRAME_LEN]; - uint8_t *tx = txbuf; - size_t txlen = 0; + byte_t rx[HITAG_FRAME_LEN]; + size_t rxlen=0; + byte_t txbuf[HITAG_FRAME_LEN]; + byte_t* tx = txbuf; + size_t txlen=0; int lastbit; bool bSkip; - int reset_sof; - int tag_sof; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop = false; - bool bQuitTraceFull = false; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - //DbpString("Starting Hitag reader family"); - - // Check configuration - switch (htf) { - case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); - memcpy(password, htd->pwd.password, 4); - blocknr = 0; - bQuitTraceFull = false; - bQuiet = false; - bPwd = false; - bAuthenticating = false; - } - break; - case RHT2F_AUTHENTICATE: { - DbpString("Authenticating using nr,ar pair:"); - memcpy(NrAr, htd->auth.NrAr, 8); - Dbhexdump(8, NrAr, false); - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } - break; - case RHT2F_CRYPTO: - { - DbpString("Authenticating using key:"); - memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. - Dbhexdump(6, key, false); - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } - break; - case RHT2F_TEST_AUTH_ATTEMPTS: { - Dbprintf("Testing %d authentication attempts", (auth_table_len/8)); - auth_table_pos = 0; - memcpy(NrAr, auth_table, 8); - bQuitTraceFull = false; - bQuiet = false; - bCrypto = false; - } - break; - case RHT2F_UID_ONLY: { - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } - break; - default: { - Dbprintf("Error, unknown function: %d", htf); - return; - } - break; - } - - LED_D_ON(); - hitag2_init(); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - - // Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Reset the received frame, frame count and timing info - // frame_count = 0; - response = 0; - lastbit = 1; - - // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10) { - // hitagS settings - reset_sof = 1; - t_wait = 200; - //DbpString("Configured for hitagS reader"); - } else if (htf < 20) { - // hitag1 settings - reset_sof = 1; - t_wait = 200; - //DbpString("Configured for hitag1 reader"); - } else if (htf < 30) { - // hitag2 settings - reset_sof = 4; - t_wait = HITAG_T_WAIT_2; - //DbpString("Configured for hitag2 reader"); - } else { - Dbprintf("Error, unknown hitag reader type: %d", htf); - goto out; - } - - // wait for tag to power up - // t_PowerUp = 312,5 carrier periods - while (AT91C_BASE_TC0->TC_CV < T0*(312-t_wait)); - - uint8_t attempt_count = 0; - while (!bStop && !BUTTON_PRESS()) { - WDT_HIT(); - - // Check if frame was captured and store it - if (rxlen > 0) { - // frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, false)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - // By default reset the transmission buffer - tx = txbuf; - switch (htf) { - case RHT2F_PASSWORD: { - bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); - } - break; - case RHT2F_AUTHENTICATE: { - bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen); - } - break; - case RHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false); - } - break; - case RHT2F_TEST_AUTH_ATTEMPTS: { - bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen); - } - break; - case RHT2F_UID_ONLY: { - bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen); - attempt_count++; //attempt 3 times to get uid then quit - if (!bStop && attempt_count == 3) - bStop = true; - } - break; - default: { - Dbprintf("Error, unknown function: %d", htf); - goto out; - } - } - - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occured halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); - - //Dbprintf("DEBUG: Sending reader frame"); - - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Add transmitted frame to total count - if (txlen > 0) { - // frame_count++; - if (!bQuiet) { - // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - response = 0; - //Dbprintf("DEBUG: Waiting to receive frame"); - 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) { - //Dbprintf("DEBUG: 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) - - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} - 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) - - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} - 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) - - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} - 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 { - //Dbprintf("DEBUG: Wierd2"); - errorCount++; - // Ignore wierd value, is to small to mean anything - } - } - //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; - } - } - } - -out: - //Dbprintf("DEBUG: Done waiting for frame"); - - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - //Dbprintf("frame received: %d",frame_count); - //DbpString("All done"); - if (bSuccessful) - cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); - else - cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); -} - -void WriterHitag(hitag_function htf, hitag_data *htd, int page) { - // int frame_count; - int response; - 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 lastbit; - bool bSkip; - int reset_sof; + int reset_sof; int tag_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop; bool bQuitTraceFull = false; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; - + + // Reset the return status + bSuccessful = false; + // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - //DbpString("Starting Hitag reader family"); + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + DbpString("Starting Hitag reader family"); // Check configuration - switch (htf) { - case WHT2F_CRYPTO: { - DbpString("Authenticating using key:"); - memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. - memcpy(writedata, htd->crypto.data, 4); - Dbhexdump(6, key, false); - blocknr = page; + switch(htf) { + case RHT2F_PASSWORD: { + Dbprintf("List identifier in password mode"); + memcpy(password,htd->pwd.password,4); + blocknr = 0; + bQuitTraceFull = false; + bQuiet = false; + bPwd = false; + } break; + + case RHT2F_AUTHENTICATE: { + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr,htd->auth.NrAr,8); + Dbhexdump(8,NrAr,false); bQuiet = false; bCrypto = false; - bAuthenticating = false; + bAuthenticating = false; bQuitTraceFull = true; - writestate = WRITE_STATE_START; - } - break; - case WHT2F_PASSWORD: { - DbpString("Authenticating using password:"); - memcpy(password, htd->pwd.password, 4); - memcpy(writedata, htd->crypto.data, 4); - Dbhexdump(4, password, false); - blocknr = page; - bPwd = false; - bAuthenticating = false; - writestate = WRITE_STATE_START; - } - break; - default: { - Dbprintf("Error, unknown function: %d", htf); - return; - } - break; - } + } break; + + case RHT2F_CRYPTO: { + DbpString("Authenticating using key:"); + memcpy(key,htd->crypto.key,6); + Dbhexdump(6,key,false); + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } break; + case RHT2F_TEST_AUTH_ATTEMPTS: { + Dbprintf("Testing %d authentication attempts",(auth_table_len/8)); + auth_table_pos = 0; + memcpy(NrAr,auth_table,8); + bQuitTraceFull = false; + bQuiet = false; + bCrypto = false; + } break; + + default: { + Dbprintf("Error, unknown function: %d",htf); + return; + } break; + } + LED_D_ON(); hitag2_init(); - + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + RELAY_OFF(); // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); - + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + + // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - // frame_count = 0; + frame_count = 0; response = 0; lastbit = 1; bStop = false; - // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10) { - // hitagS settings - reset_sof = 1; - t_wait = 200; - //DbpString("Configured for hitagS reader"); - } else if (htf < 20) { - // hitag1 settings - reset_sof = 1; - t_wait = 200; - //DbpString("Configured for hitag1 reader"); - } else if (htf < 30) { - // hitag2 settings - reset_sof = 4; - t_wait = HITAG_T_WAIT_2; - //DbpString("Configured for hitag2 reader"); + // Tag specific configuration settings (sof, timings, etc.) + if (htf < 10){ + // hitagS settings + reset_sof = 1; + t_wait = 200; + DbpString("Configured for hitagS reader"); + } else if (htf < 20) { + // hitag1 settings + reset_sof = 1; + t_wait = 200; + DbpString("Configured for hitag1 reader"); + } else if (htf < 30) { + // hitag2 settings + reset_sof = 4; + t_wait = HITAG_T_WAIT_2; + DbpString("Configured for hitag2 reader"); } else { - Dbprintf("Error, unknown hitag reader type: %d", htf); - return; - } - while (!bStop && !BUTTON_PRESS()) { - + Dbprintf("Error, unknown hitag reader type: %d",htf); + return; + } + + while(!bStop && !BUTTON_PRESS()) { + // Watchdog hit WDT_HIT(); - + // Check if frame was captured and store it - if (rxlen > 0) { - // frame_count++; + if(rxlen > 0) { + frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, false)) { + if (!LogTraceHitag(rx,rxlen,response,0,false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1687,50 +1263,51 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { } } } - + // By default reset the transmission buffer tx = txbuf; - switch (htf) { - case WHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); - } - break; - case WHT2F_PASSWORD: { - bStop = !hitag2_password(rx, rxlen, tx, &txlen, true); - } - break; + switch(htf) { + case RHT2F_PASSWORD: { + bStop = !hitag2_password(rx,rxlen,tx,&txlen); + } break; + case RHT2F_AUTHENTICATE: { + bStop = !hitag2_authenticate(rx,rxlen,tx,&txlen); + } break; + case RHT2F_CRYPTO: { + bStop = !hitag2_crypto(rx,rxlen,tx,&txlen); + } break; + case RHT2F_TEST_AUTH_ATTEMPTS: { + bStop = !hitag2_test_auth_attempts(rx,rxlen,tx,&txlen); + } break; default: { - Dbprintf("Error, unknown function: %d", htf); + Dbprintf("Error, unknown function: %d",htf); return; - } - break; + } break; } - + // Send and store the reader command // Disable timer 1 with external trigger to avoid triggers during our own modulation AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - + // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, // Since the clock counts since the last falling edge, a 'one' means that the // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); - - //Dbprintf("DEBUG: Sending reader frame"); - + while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + hitag_reader_send_frame(tx,txlen); // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count - if (txlen > 0) { - // frame_count++; + if(txlen > 0) { + frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { + if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { if (bQuitTraceFull) { break; } else { @@ -1739,71 +1316,54 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { } } } - + // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); + memset(rx,0x00,sizeof(rx)); rxlen = 0; lastbit = 1; bSkip = true; tag_sof = reset_sof; response = 0; - //Dbprintf("DEBUG: Waiting to receive frame"); - 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 + 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(ra >= HITAG_T_EOF) { if (rxlen != 0) { - //Dbprintf("DEBUG: Wierd1"); + //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) { + response = ra-HITAG_T_TAG_HALF_PERIOD; + } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } 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) { + } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; - // We have to skip this half period at start and add the 'one' the second time + // 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) { + } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } if (tag_sof) { // Ignore bits that are transmitted during SOF tag_sof--; @@ -1813,33 +1373,22 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { rxlen++; } } else { - // Dbprintf("DEBUG: Wierd2"); - errorCount++; - // Ignore wierd value, it is too small to mean anything + // Ignore wierd value, is to small to mean anything } } - // 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; + if (rxlen>0) break; } } - - // Wait some extra time for flash to be programmed - if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_PROG - HITAG_T_WAIT_MAX)); - } } - //Dbprintf("DEBUG: Done waiting for frame"); - LED_B_OFF(); LED_D_OFF(); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - //Dbprintf("frame received: %d",frame_count); - //DbpString("All done"); - cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); + Dbprintf("frame received: %d",frame_count); + DbpString("All done"); + cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48); } diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h deleted file mode 100644 index 3883c17b..00000000 --- a/armsrc/hitag2.h +++ /dev/null @@ -1,24 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// Hitag2 emulation -// -// (c) 2009 Henryk Plötz -// (c) 2012 Roel Verdult -//----------------------------------------------------------------------------- - -#ifndef HITAG2_H__ -#define HITAG2_H__ - -#include -#include -#include "hitag.h" - -extern void SnoopHitag(uint32_t type); -extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); -extern void ReaderHitag(hitag_function htf, hitag_data* htd); -extern void WriterHitag(hitag_function htf, hitag_data* htd, int page); - -#endif diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c deleted file mode 100644 index 2f5d6289..00000000 --- a/armsrc/hitagS.c +++ /dev/null @@ -1,2432 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// HitagS emulation (preliminary test version) -// -// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg -// -//----------------------------------------------------------------------------- -// Some code was copied from Hitag2.c -//----------------------------------------------------------------------------- - - -#include "hitagS.h" - -#include -#include "proxmark3.h" -#include "apps.h" -#include "usb_cdc.h" -#include "util.h" -#include "hitag.h" -#include "string.h" -#include "BigBuf.h" -#include "fpgaloader.h" - -#define CRC_PRESET 0xFF -#define CRC_POLYNOM 0x1D - -static bool bQuiet; -static bool bSuccessful; -static struct hitagS_tag tag; -static byte_t page_to_be_written = 0; -static int block_data_left = 0; -typedef enum modulation { - AC2K = 0, AC4K, MC4K, MC8K -} MOD; -static MOD m = AC2K; //used modulation -static uint32_t temp_uid; -static int temp2 = 0; -static int sof_bits; //number of start-of-frame bits -static byte_t pwdh0, pwdl0, pwdl1; //password bytes -static uint32_t rnd = 0x74124485; //randomnumber -static int test = 0; -bool end=false; - -// Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 -#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)))) -#define uf20bs uint32_t - -static uint32_t f20(const uint64_t x) { - uint32_t i5; - - i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 - + ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2 - + ((ht2_f4b >> i4(x, 16, 20, 22, 25)) & 1) * 4 - + ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8 - + ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16; - - return (ht2_f5c >> i5) & 1; -} - -static uint64_t hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) { - uint32_t i; - uint64_t x = ((key & 0xFFFF) << 32) + serial; - for (i = 0; i < 32; i++) { - x >>= 1; - x += (uint64_t) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; - } - return x; -} - -static uint64_t hitag2_round(uint64_t *state) { - uint64_t x = *state; - - x = (x >> 1) - + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8) - ^ (x >> 16) ^ (x >> 22) ^ (x >> 23) ^ (x >> 26) ^ (x >> 30) - ^ (x >> 41) ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) - & 1) << 47); - - *state = x; - return f20(x); -} - -static uint32_t hitag2_byte(uint64_t *x) { - uint32_t i, c; - - for (i = 0, c = 0; i < 8; i++) - c += (uint32_t) hitag2_round(x) << (i ^ 7); - return c; -} - -// 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 -// Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) -// T0 = TIMER_CLOCK1 / 125000 = 192 -#define T0 192 - -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) - -#define HITAG_FRAME_LEN 20 -#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ -//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ - -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 -#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 - -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 - -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 -#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 -#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 - -#define DEBUG 0 - -/* - * Implementation of the crc8 calculation from Hitag S - * from http://www.proxmark.org/files/Documents/125%20kHz%20-%20Hitag/HitagS.V11.pdf - */ -void calc_crc(unsigned char * crc, unsigned char data, unsigned char Bitcount) { - *crc ^= data; // crc = crc (exor) data - do { - if (*crc & 0x80) // if (MSB-CRC == 1) - { - *crc <<= 1; // CRC = CRC Bit-shift left - *crc ^= CRC_POLYNOM; // CRC = CRC (exor) CRC_POLYNOM - } else { - *crc <<= 1; // CRC = CRC Bit-shift left - } - } while (--Bitcount); -} - - -static void hitag_send_bit(int bit) { - LED_A_ON(); - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - switch (m) { - case AC2K: - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) - ; - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 48) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) - ;; - } - LED_A_OFF(); - break; - case AC4K: - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) - ; - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 24) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } - LED_A_OFF(); - break; - case MC4K: - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } - LED_A_OFF(); - break; - case MC8K: - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - } - LED_A_OFF(); - break; - default: - break; - } -} - -static void hitag_tag_send_frame(const byte_t* frame, size_t frame_len) { -// Send start of frame - for (size_t i = 0; i < sof_bits; i++) { - hitag_send_bit(1); - } - -// Send the content of the frame - for (size_t i = 0; i < frame_len; i++) { - hitag_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); - } -// Drop the modulation - LOW(GPIO_SSC_DOUT); -} - -static void hitag_reader_send_bit(int bit) { -//Dbprintf("BIT: %d",bit); - LED_A_ON(); -// Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - -// Binary puls length modulation (BPLM) is used to encode the data stream -// This means that a transmission of a one takes longer than that of a zero - -// Enable modulation, which means, drop the the field - HIGH(GPIO_SSC_DOUT); - if (test == 1) { - // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) - ; - // SpinDelayUs(8*8); - - // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); - - if (bit == 0) { - // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * 11) - ; - // SpinDelayUs(16*8); - } else { - // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * 14) - ; - // SpinDelayUs(22*8); - } - } else { - // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) - ; - // SpinDelayUs(8*8); - - // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); - - if (bit == 0) { - // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * 22) - ; - // SpinDelayUs(16*8); - } else { - // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * 28) - ; - // SpinDelayUs(22*8); - } - } - - LED_A_OFF(); -} - -static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) { - // Send the content of the frame - for (size_t i = 0; i < frame_len; i++) { - if (frame[0] == 0xf8) { - //Dbprintf("BIT: %d",(frame[i / 8] >> (7 - (i % 8))) & 1); - } - hitag_reader_send_bit(((frame[i / 8] >> (7 - (i % 8))) & 1)); - } -// Send EOF - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; -// Enable modulation, which means, drop the the field - HIGH(GPIO_SSC_DOUT); -// Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) - ; -// Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); -} - -static void hitag_decode_frame_MC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { - size_t rxlen = 0; - bool bSkip = true; - int lastbit = 1; - int tag_sof = 0; - int timing = 1; - if (bitRate == 8) { - timing = 2; - } - - for (int i=0; i < rawLen; i++) { - int ra = rawMod[i]; - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - tag_sof = sofBits; - - // 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 / timing) { - tag_sof=0; - // 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 / timing) { - tag_sof=0; - // 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 / timing) { - // 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 - } - } - *rxlenOrg = rxlen; -} - -/* -static void hitag_decode_frame_AC2K_rising(byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { - int tag_sof = 1; //skip start of frame - size_t rxlen = 0; - - for (int i=0; i < rawLen; i++) { - int ra = rawMod[i]; - 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 |-_| - tag_sof = 1; - *response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // AC coding example |--__|--__| means 0 - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - if (rawMod[i+1] == 0) { //TODO: this is weird - may we miss one capture with current configuration - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - i++; //drop next capture - } - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // AC coding example |-_-_|-_-_| which means 1 - //check if another high is coming (only -_-_ = 1) except end of the frame (support 0) - if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - i++; //drop next capture - } else { - Dbprintf("got weird high - %d,%d", ra, rawMod[i+1]); - } - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - *rxlenOrg = rxlen; -} -*/ - -static void hitag_decode_frame_AC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { - int tag_sof = 1; - size_t rxlen = 0; - int timing = 1; - if (bitRate == 4) { - timing = 2; - } - - - for (int i=0; i < rawLen; i++) { - int ra = rawMod[i]; - 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 |-_| - tag_sof = sofBits; - *response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF / timing) { - tag_sof=0; - - // AC coding example |--__|--__| means 0 - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) { - tag_sof=0; - - if (rawMod[i-1] >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) { - //treat like HITAG_T_TAG_CAPTURE_TWO_HALF - if (rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - i++; //drop next capture - } else { - Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]); - } - } else { - //treat like HITAG_T_TAG_CAPTURE_FOUR_HALF - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // AC coding example |-_-_|-_-_| which means 1 - //check if another high is coming (only -_-_ = 1) except end of the frame (support 0) - if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - i++; //drop next capture - } else { - Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]); - } - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - *rxlenOrg = rxlen; -} - -static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { - int rawMod[200] = {0}; - int rawLen = 0; - int i = 0; - int sofBits = 0; - - m = MC4K; - if (tag.pstate == READY) { - switch (tag.mode) { - case STANDARD: - m = AC2K; - sofBits = 1; - break; - case ADVANCED: - m = AC2K; - sofBits = 5; //3 sof bits but 5 captures - break; - case FAST_ADVANCED: - m = AC4K; - sofBits = 5; //3 sof bits but 5 captures - break; - default: - break; - } - } else { - switch (tag.mode) { - case STANDARD: - m = MC4K; - sofBits = 0; //in theory 1 - break; - case ADVANCED: - m = MC4K; - sofBits = 5; //in theory 6 - break; - case FAST_ADVANCED: - m = MC8K; - sofBits = 5; //in theory 6 - break; - default: - break; - } - } - - //rising AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - - //first capture timing values - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX ) { - // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - LED_B_ON(); - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - if (rawLen >= 200) { //avoid exception - break; - } - rawMod[rawLen] = ra; - rawLen++; - - // 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 (rawLen > 2) { - if (DEBUG >= 2) { Dbprintf("AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF breaking (%d)", rawLen); } - break; - } - } - } - } - - if (DEBUG >= 2) { - for (i=0; i < rawLen; i+=20) { - Dbprintf("raw modulation: - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - rawMod[i],rawMod[i+1],rawMod[i+2],rawMod[i+3], rawMod[i+4],rawMod[i+5],rawMod[i+6],rawMod[i+7], - rawMod[i+8],rawMod[i+9],rawMod[i+10],rawMod[i+11], rawMod[i+12],rawMod[i+13],rawMod[i+14],rawMod[i+15], - rawMod[i+16],rawMod[i+17],rawMod[i+18],rawMod[i+19] - ); - } - } - - switch (m) { - // DATA | 1 | 0 | 1 | 1 | 0 | - // Manchester |--__|__--|--__|--__|__--| - // Anti Collision |-_-_|--__|-_-_|-_-_|--__| - // |<-->| - // | T | - case AC2K: - if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC2K"); } - hitag_decode_frame_AC(2, sofBits, rx, rxlen, response, rawMod, rawLen); - break; - case AC4K: - if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC4K"); } - hitag_decode_frame_AC(4, sofBits, rx, rxlen, response, rawMod, rawLen); - break; - case MC4K: - if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC4K"); } - hitag_decode_frame_MC(4, sofBits, rx, rxlen, response, rawMod, rawLen); - break; - case MC8K: - if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC8K"); } - hitag_decode_frame_MC(8, sofBits, rx, rxlen, response, rawMod, rawLen); - break; - } - - LED_B_OFF(); - if (DEBUG >= 2) { - int rb[200] = {0}; int z = 0; - for (i = 0; i < 16; i++) { for (int j = 0; j < 8; j++) { - rb[z] = 0; - if ((rx[i] & ((1 << 7) >> j)) != 0) { rb[z] = 1; } - z++; - } } - for (i=0; i < z; i+=8) { - Dbprintf("raw bit: - %d%d%d%d%d%d%d%d", rb[i],rb[i+1],rb[i+2],rb[i+3],rb[i+4],rb[i+5],rb[i+6],rb[i+7] ); - } - } -} - -static void hitag_start_auth(byte_t* tx, size_t* txlen) { - *txlen = 5; - switch (tag.mode) { - case STANDARD: - //00110 - 0x30 - STANDARD MODE - memcpy(tx, "\x30", nbytes(*txlen)); - break; - case ADVANCED: - //11000 - 0xc0 - Advance Mode - memcpy(tx, "\xc0", nbytes(*txlen)); - break; - case FAST_ADVANCED: - //TODO! - break; - default: //STANDARD MODE - memcpy(tx, "\x30", nbytes(*txlen)); - break; - } - tag.pstate = READY; - tag.tstate = NO_OP; -} - -static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int pageNum) { - int i, j, z; - int response_bit[200]; - unsigned char mask = 1; - unsigned char crc; - unsigned char pageData[32]; - - if (pageNum >= tag.max_page) { - return -1; - } - if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) { - //send read request - tag.tstate = READING_PAGE; - *txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + (pageNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4); - tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE && *rxlen > 0) { - //save received data - z = 0; - for (i = 0; i < 4; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) { - response_bit[z] = 1; - } - if (z < 32) { - pageData[z] = response_bit[z]; - } - - z++; - } - } - for (i = 0; i < 4; i++) { - tag.pages[pageNum][i] = 0x0; - } - for (i = 0; i < 4; i++) { - tag.pages[pageNum][i] += ((pageData[i * 8] << 7) | (pageData[1 + (i * 8)] << 6) | - (pageData[2 + (i * 8)] << 5) | (pageData[3 + (i * 8)] << 4) | - (pageData[4 + (i * 8)] << 3) | (pageData[5 + (i * 8)] << 2) | - (pageData[6 + (i * 8)] - << 1) | pageData[7 + (i * 8)]); - } - if (tag.auth && tag.LKP && pageNum == 1) { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0, - tag.pages[pageNum][2], tag.pages[pageNum][1], tag.pages[pageNum][0]); - } else { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, - tag.pages[pageNum][3], tag.pages[pageNum][2], - tag.pages[pageNum][1], tag.pages[pageNum][0]); - } - - - //display key and password if possible - if (pageNum == 1 && tag.auth == 1 && tag.LKP) { - if (htf == 02) { //RHTS_KEY - Dbprintf("Page[ 2]: %02X %02X %02X %02X", - (byte_t)(key >> 8) & 0xff, - (byte_t) key & 0xff, pwdl1, pwdl0); - Dbprintf("Page[ 3]: %02X %02X %02X %02X", - (byte_t)(key >> 40) & 0xff, - (byte_t)(key >> 32) & 0xff, - (byte_t)(key >> 24) & 0xff, - (byte_t)(key >> 16) & 0xff); - } else { - //if the authentication is done with a challenge the key and password are unknown - Dbprintf("Page[ 2]: __ __ __ __"); - Dbprintf("Page[ 3]: __ __ __ __"); - } - } - - *txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + ((pageNum+1) / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + (((pageNum+1) % 16) * 16), 4); - tx[1] = 0x00 + (((pageNum+1) % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - - return 1; - } - return 0; -} - -static int hitag_read_block(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int blockNum) { - int i, j, z; - int response_bit[200]; - unsigned char mask = 1; - unsigned char crc; - unsigned char blockData[128]; - - if (blockNum+4 >= tag.max_page) { //block always = 4 pages - return -1; - } - - if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) { - //send read request - tag.tstate = READING_BLOCK; - *txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xd0 + (blockNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((blockNum % 16) * 16), 4); - tx[1] = 0x00 + ((blockNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - } else if (tag.pstate == SELECTED && tag.tstate == READING_BLOCK && *rxlen > 0) { - //save received data - z = 0; - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) { - response_bit[z] = 1; - } - if (z < 128) { - blockData[z] = response_bit[z]; - } - z++; - } - } - - for (z = 0; z < 4; z++) { //4 pages - for (i = 0; i < 4; i++) { - tag.pages[blockNum+z][i] = 0x0; - } - } - for (z = 0; z < 4; z++) { //4 pages - for (i = 0; i < 4; i++) { - j = (i * 8) + (z*32); //bit in page + pageStart - tag.pages[blockNum+z][i] = ((blockData[j] << 7) | (blockData[1 + j] << 6) | - (blockData[2 + j] << 5) | (blockData[3 + j] << 4) | - (blockData[4 + j] << 3) | (blockData[5 + j] << 2) | - (blockData[6 + j] << 1) | blockData[7 + j]); - } - } - if (DEBUG) { - for (z = 0; z < 4; z++) { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", blockNum+z, - tag.pages[blockNum+z][3], tag.pages[blockNum+z][2], - tag.pages[blockNum+z][1], tag.pages[blockNum+z][0]); - } - } - Dbprintf("Block[%2d]: %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X", blockNum, - tag.pages[blockNum][3], tag.pages[blockNum][2], tag.pages[blockNum][1], tag.pages[blockNum][0], - tag.pages[blockNum+1][3], tag.pages[blockNum+1][2], tag.pages[blockNum+1][1], tag.pages[blockNum+1][0], - tag.pages[blockNum+2][3], tag.pages[blockNum+2][2], tag.pages[blockNum+2][1], tag.pages[blockNum+2][0], - tag.pages[blockNum+3][3], tag.pages[blockNum+3][2], tag.pages[blockNum+3][1], tag.pages[blockNum+3][0]); - - *txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xd0 + ((blockNum+4) / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + (((blockNum+4) % 16) * 16), 4); - tx[1] = 0x00 + (((blockNum+4) % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - - return 1; - } - return 0; -} - - -/* - * to check if the right uid was selected - */ -static int check_select(byte_t* rx, uint32_t uid) { - unsigned char resp[48]; - int i; - uint32_t ans = 0x0; - for (i = 0; i < 48; i++) - resp[i] = (rx[i / 8] >> (7 - (i % 8))) & 0x1; - for (i = 0; i < 32; i++) - ans += resp[5 + i] << (31 - i); - /*if (rx[0] == 0x01 && rx[1] == 0x15 && rx[2] == 0xc1 && rx[3] == 0x14 - && rx[4] == 0x65 && rx[5] == 0x38) - Dbprintf("got uid %X", ans);*/ - temp_uid = ans; - if (ans == tag.uid) - return 1; - return 0; -} - -/* - * handles all commands from a reader - */ -static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, - byte_t* tx, size_t* txlen) { - byte_t rx_air[HITAG_FRAME_LEN]; - byte_t page; - int i; - uint64_t state; - unsigned char crc; - - // Copy the (original) received frame how it is send over the air - memcpy(rx_air, rx, nbytes(rxlen)); - // Reset the transmission frame length - *txlen = 0; - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - case 5: { - //UID request with a selected response protocol mode - tag.pstate = READY; - tag.tstate = NO_OP; - if ((rx[0] & 0xf0) == 0x30) { - Dbprintf("recieved uid request in Standard Mode"); - tag.mode = STANDARD; - sof_bits = 1; - m = AC2K; - } - if ((rx[0] & 0xf0) == 0xc0) { - Dbprintf("recieved uid request in ADVANCE Mode"); - tag.mode = ADVANCED; - sof_bits = 3; - m = AC2K; - } - if ((rx[0] & 0xf0) == 0xd0) { - Dbprintf("recieved uid request in FAST_ADVANCE Mode"); - tag.mode = FAST_ADVANCED; - sof_bits = 3; - m = AC4K; - } - //send uid as a response - *txlen = 32; - for (i = 0; i < 4; i++) { - tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff; - } - } - break; - case 45: { - //select command from reader received - if (check_select(rx, tag.uid) == 1) { - //if the right tag was selected - *txlen = 32; - switch (tag.mode) { - case STANDARD: - Dbprintf("uid selected in Standard Mode"); - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - Dbprintf("uid selected in ADVANCE Mode"); - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - Dbprintf("uid selected in FAST_ADVANCE Mode"); - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - - //send configuration - tx[0] = tag.pages[1][3]; - tx[1] = tag.pages[1][2]; - tx[2] = tag.pages[1][1]; - tx[3] = 0xff; - if (tag.mode != STANDARD) { - *txlen = 40; - crc = CRC_PRESET; - for (i = 0; i < 4; i++) - calc_crc(&crc, tx[i], 8); - tx[4] = crc; - } - } - } - break; - case 64: { - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - //challenge message received - Dbprintf("Challenge for UID: %X", temp_uid); - temp2++; - state = hitag2_init(REV64(tag.key), REV32(tag.pages[0][0]), - REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); - 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]); - - for (i = 0; i < 4; i++) { - hitag2_byte(&state); - } - - *txlen = 32; - //send con2,pwdh0,pwdl0,pwdl1 encrypted as a response - tx[0] = hitag2_byte(&state) ^ tag.pages[1][1]; - tx[1] = hitag2_byte(&state) ^ tag.pwdh0; - tx[2] = hitag2_byte(&state) ^ tag.pwdl0; - tx[3] = hitag2_byte(&state) ^ tag.pwdl1; - if (tag.mode != STANDARD) { - //add crc8 - *txlen = 40; - crc = CRC_PRESET; - calc_crc(&crc, tag.pages[1][1], 8); - calc_crc(&crc, tag.pwdh0, 8); - calc_crc(&crc, tag.pwdl0, 8); - calc_crc(&crc, tag.pwdl1, 8); - tx[4] = (crc ^ hitag2_byte(&state)); - } - } - case 40: - //data received to be written - if (tag.tstate == WRITING_PAGE_DATA) { - tag.tstate = NO_OP; - tag.pages[page_to_be_written][0] = rx[3]; - tag.pages[page_to_be_written][1] = rx[2]; - tag.pages[page_to_be_written][2] = rx[1]; - tag.pages[page_to_be_written][3] = rx[0]; - - //send ack - *txlen = 2; - tx[0] = 0x40; - page_to_be_written = 0; - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - } else if (tag.tstate == WRITING_BLOCK_DATA) { - tag.pages[page_to_be_written][0] = rx[0]; - tag.pages[page_to_be_written][1] = rx[1]; - tag.pages[page_to_be_written][2] = rx[2]; - tag.pages[page_to_be_written][3] = rx[3]; - - //send ack - *txlen = 2; - tx[0] = 0x40; - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - page_to_be_written++; - block_data_left--; - if (block_data_left == 0) { - tag.tstate = NO_OP; - page_to_be_written = 0; - } - } - break; - case 20: { - //write page, write block, read page or read block command received - if ((rx[0] & 0xf0) == 0xc0) { //read page - //send page data - page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); - Dbprintf("reading page %d", page); - *txlen = 32; - 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 STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - - if (tag.mode != STANDARD) { - //add crc8 - *txlen = 40; - crc = CRC_PRESET; - for (i = 0; i < 4; i++) - calc_crc(&crc, tx[i], 8); - tx[4] = crc; - } - - if (tag.LKP && (page == 2 || page == 3)) { - //if reader asks for key or password and the LKP-mark is set do not respond - sof_bits = 0; - *txlen = 0; - } - } else if ((rx[0] & 0xf0) == 0xd0) { //read block - page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); - Dbprintf("reading block %d", page); - *txlen = 32 * 4; - //send page,...,page+3 data - for (i = 0; i < 4; i++) { - tx[0 + (i * 4)] = tag.pages[page][0]; - tx[1 + (i * 4)] = tag.pages[page][1]; - tx[2 + (i * 4)] = tag.pages[page][2]; - tx[3 + (i * 4)] = tag.pages[page][3]; - page++; - } - - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - - if (tag.mode != STANDARD) { - //add crc8 - *txlen = 32 * 4 + 8; - crc = CRC_PRESET; - for (i = 0; i < 16; i++) - calc_crc(&crc, tx[i], 8); - tx[16] = crc; - } - - if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) { - sof_bits = 0; - *txlen = 0; - } - } else if ((rx[0] & 0xf0) == 0x80) { //write page - page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); - - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - if ((tag.LCON && page == 1) - || (tag.LKP && (page == 2 || page == 3))) { - //deny - *txlen = 0; - } else { - //allow - *txlen = 2; - tx[0] = 0x40; - page_to_be_written = page; - tag.tstate = WRITING_PAGE_DATA; - } - - } else if ((rx[0] & 0xf0) == 0x90) { //write block - page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } - if (page % 4 != 0 || page == 0) { - //deny - *txlen = 0; - } else { - //allow - *txlen = 2; - tx[0] = 0x40; - page_to_be_written = page; - block_data_left = 4; - tag.tstate = WRITING_BLOCK_DATA; - } - } - } - break; - default: - - break; - } -} - - -/* - * to autenticate to a tag with the given key or challenge - */ -static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, - const size_t rxlen, byte_t* tx, size_t* txlen) { - byte_t rx_air[HITAG_FRAME_LEN]; - int response_bit[200] = {0}; - int i, j, z, k; - unsigned char mask = 1; - unsigned char uid[32]; - byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00; - unsigned char crc; - uint64_t state; - byte_t auth_ks[4]; - byte_t conf_pages[3]; - memcpy(rx_air, rx, nbytes(rxlen)); - *txlen = 0; - - if (DEBUG) { - Dbprintf("START hitagS_handle_tag_auth - rxlen: %d, tagstate=%d", rxlen, (int)tag.pstate); - } - - if (tag.pstate == READY && rxlen >= 32) { - //received uid - if(end==true) { - Dbprintf("authentication failed!"); - return -1; - } - z = 0; - for (i = 0; i < 10; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) - response_bit[z] = 1; - z++; - } - } - for (i = 0; i < 32; i++) { - uid[i] = response_bit[i]; - } - - uid1 = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4) - | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7]; - uid2 = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | (uid[11] << 4) - | (uid[12] << 3) | (uid[13] << 2) | (uid[14] << 1) | uid[15]; - uid3 = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | (uid[19] << 4) - | (uid[20] << 3) | (uid[21] << 2) | (uid[22] << 1) | uid[23]; - uid4 = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) | (uid[27] << 4) - | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; - Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); - tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); - - //select uid - crc = CRC_PRESET; - calc_crc(&crc, 0x00, 5); - calc_crc(&crc, uid1, 8); - calc_crc(&crc, uid2, 8); - calc_crc(&crc, uid3, 8); - calc_crc(&crc, uid4, 8); - Dbprintf("crc: %02X", crc); - - //resetting response bit - for (i = 0; i < 100; i++) { - response_bit[i] = 0; - } - - //skip the first 5 - for (i = 5; i < 37; i++) { - response_bit[i] = uid[i - 5]; - } - //add crc value - for (j = 0; j < 8; j++) { - response_bit[i] = 0; - if ((crc & ((mask << 7) >> j)) != 0) - response_bit[i] = 1; - i++; - } - - k = 0; - for (i = 0; i < 6; i++) { - tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) - | (response_bit[k + 2] << 5) | (response_bit[k + 3] << 4) - | (response_bit[k + 4] << 3) | (response_bit[k + 5] << 2) - | (response_bit[k + 6] << 1) | response_bit[k + 7]; - k += 8; - } - *txlen = 45; - tag.pstate = INIT; - } else if (tag.pstate == INIT && rxlen > 24) { - // received configuration after select command - z = 0; - for (i = 0; i < 4; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) { - response_bit[z] = 1; - } - z++; - } - } - - //check wich memorysize this tag has - //CON0 - if (response_bit[6] == 0 && response_bit[7] == 0) - tag.max_page = 32 / 32; - if (response_bit[6] == 0 && response_bit[7] == 1) - tag.max_page = 256 / 32; - if (response_bit[6] == 1 && response_bit[7] == 0) - tag.max_page = 2048 / 32; - if (response_bit[6] == 1 && response_bit[7] == 1) //reserved but some tags got this setting - tag.max_page = 2048 / 32; - - //CON1 - tag.auth = response_bit[8]; - tag.TTFC = response_bit[9]; - //tag.TTFDR in response_bit[10] and response_bit[11] - //tag.TTFM in response_bit[12] and response_bit[13] - tag.LCON = response_bit[14]; - tag.LKP = response_bit[15]; - - //CON2 - tag.LCK7 = response_bit[16]; - tag.LCK6 = response_bit[17]; - tag.LCK5 = response_bit[18]; - tag.LCK4 = response_bit[19]; - tag.LCK3 = response_bit[20]; - tag.LCK2 = response_bit[21]; - tag.LCK1 = response_bit[22]; - tag.LCK0 = response_bit[23]; - - if (DEBUG) { - conf_pages[0] = ((response_bit[0] << 7) | (response_bit[1] << 6) - | (response_bit[2] << 5) | (response_bit[3] << 4) - | (response_bit[4] << 3) | (response_bit[5] << 2) - | (response_bit[6] << 1) | response_bit[7]); - conf_pages[1] = ((response_bit[8] << 7) | (response_bit[9] << 6) - | (response_bit[10] << 5) | (response_bit[11] << 4) - | (response_bit[12] << 3) | (response_bit[13] << 2) - | (response_bit[14] << 1) | response_bit[15]); - conf_pages[2] = ((response_bit[16] << 7) | (response_bit[17] << 6) - | (response_bit[18] << 5) | (response_bit[19] << 4) - | (response_bit[20] << 3) | (response_bit[21] << 2) - | (response_bit[22] << 1) | response_bit[23]); - Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); - Dbprintf("tag.max_page: %d, tag.auth: %d", tag.max_page, tag.auth); - } - - if (tag.auth == 1) { - //if the tag is in authentication mode try the key or challenge - *txlen = 64; - if(end!=true){ - if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY - state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); - /* - Dbprintf("key: %02X %02X\n\n", key, REV64(key)); - Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, REV32(tag.uid)); - Dbprintf("rnd: %02X %02X\n\n", rnd, REV32(rnd)); - */ - for (i = 0; i < 4; i++) { - auth_ks[i] = hitag2_byte(&state) ^ 0xff; - } - *txlen = 64; - tx[0] = rnd & 0xff; - tx[1] = (rnd >> 8) & 0xff; - tx[2] = (rnd >> 16) & 0xff; - tx[3] = (rnd >> 24) & 0xff; - - tx[4] = auth_ks[0]; - tx[5] = auth_ks[1]; - tx[6] = auth_ks[2]; - tx[7] = auth_ks[3]; - if (DEBUG) - 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 - for (i = 0; i < 8; i++) - tx[i]=((NrAr>>(56-(i*8)))&0xff); - } - end=true; - tag.pstate = AUTHENTICATE; - } else { - Dbprintf("authentication failed!"); - return -1; - } - } else if (tag.auth == 0) { - tag.pstate = SELECTED; - } - - } else if (tag.pstate == AUTHENTICATE && rxlen >= 32) { - //encrypted con2,password received. - if (DEBUG) { - Dbprintf("UID:::%X", tag.uid); - Dbprintf("RND:::%X", rnd); - } - - //decrypt password - pwdh0=0; - pwdl0=0; - pwdl1=0; - if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY - state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); - for (i = 0; i < 5; i++) { - hitag2_byte(&state); - } - pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) ^ hitag2_byte(&state); - pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) ^ hitag2_byte(&state); - pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ hitag2_byte(&state); - if (DEBUG) { - Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); - } - } - tag.pstate = SELECTED; //tag is now ready for read/write commands - } - - if (DEBUG) { - Dbprintf("END hitagS_handle_tag_auth - tagstate=%d", (int)tag.pstate); - } - - return 0; -} - -/* - * Emulates a Hitag S Tag with the given data from the .hts file - */ -void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { - int frame_count; - int response; - int overflow; - int i, j; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - bQuiet = false; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen = 0; - uint8_t con0, con1, con2; - BigBuf_free(); - -// Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - DbpString("Starting HitagS simulation"); - LED_D_ON(); - - tag.pstate = READY; - tag.tstate = NO_OP; - //read tag data into memory - if (tag_mem_supplied) { - DbpString("Loading hitagS memory..."); - for (i = 0; i < 64; i++) { - for (j = 0; j < 4; j++) { - tag.pages[i][j] = 0x0; - } - } - - for (i = 0; i < 64; i++) { - for (j = 0; j < 4; j++) { - tag.pages[i][j] = data[(i*4)+j]; - } - } - } - tag.uid = (tag.pages[0][3] << 24 | tag.pages[0][2] << 16 | tag.pages[0][1] << 8 | tag.pages[0][0]); - con0 = tag.pages[1][3]; - con1 = tag.pages[1][2]; - con2 = tag.pages[1][1]; - Dbprintf("UID: %X", tag.uid); - Dbprintf("Hitag S simulation started"); - - //0x01 plain mode - Reserved, CON2, CON1, CON0 - //0x01 auth mode - PWDH 0, CON2, CON1, CON0 - //0x02 auth mode - KEYH 1, KEYH 0, PWDL 1, PWDL 0 - //0x03 auth mode - KEYL 3, KEYL 2, KEYL 1, KEYL 0 - - //con0 - tag.max_page = 2048 / 32; - if ((con0 & 0x2) == 0 && (con0 & 0x1) == 1) - tag.max_page = 256 / 32; - if ((con0 & 0x2) == 0 && (con0 & 0x1) == 0) - tag.max_page = 32 / 32; - - //CON1 - tag.auth = ((con1 & 0x80) == 0x80) ? 1 : 0; - tag.TTFC = ((con1 & 0x40) == 0x40) ? 1 : 0; - //tag.TTFDR in response_bit[10] and response_bit[11] - //tag.TTFM in response_bit[12] and response_bit[13] - tag.LCON = ((con1 & 0x2) == 0x2) ? 1 : 0; - tag.LKP = ((con1 & 0x1) == 0x1) ? 1 : 0; - - //CON2 - tag.LCK7 = ((con2 & 0x80) == 0x80) ? 1 : 0; - tag.LCK6 = ((con2 & 0x40) == 0x40) ? 1 : 0; - tag.LCK5 = ((con2 & 0x20) == 0x20) ? 1 : 0; - tag.LCK4 = ((con2 & 0x10) == 0x10) ? 1 : 0; - tag.LCK3 = ((con2 & 0x8) == 0x8) ? 1 : 0; - tag.LCK2 = ((con2 & 0x4) == 0x4) ? 1 : 0; - tag.LCK1 = ((con2 & 0x2) == 0x2) ? 1 : 0; - tag.LCK0 = ((con2 & 0x1) == 0x1) ? 1 : 0; - - if (tag.auth == 1) { - //TODO check if this working :D - tag.key=(intptr_t)tag.pages[3]; - 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]; - } - - // Set up simulator mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Disable modulation at default, which means release resistance - LOW(GPIO_SSC_DOUT); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on 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; - - // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - frame_count = 0; - response = 0; - overflow = 0; - - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - while (!BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); - - // Receive frame, watch for at most T0*EOF periods - //HITAG_T_WAIT_MAX - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - // Check if rising edge in modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0) + overflow; - overflow = 0; - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture reader frame - if (ra >= HITAG_T_STOP) { - if (rxlen != 0) { - //DbpString("wierd0?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else { - // Ignore wierd value, is to small to mean anything - } - } - } - - // Check if frame was captured - if (rxlen > 0) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, true)) { - DbpString("Trace full"); - clear_trace(); - } - } - - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitagS_handle_reader_command(rx, rxlen, tx, &txlen); - - // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, - // 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 - while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_WAIT_1 - HITAG_T_LOW)) { } - - // Send and store the tag answer (if there is any) - if (txlen > 0) { - // Transmit the tag frame - hitag_tag_send_frame(tx, txlen); - - // Store the frame in the trace - if (!bQuiet) { - if (!LogTraceHitag(tx, txlen, 0, 0, false)) { - DbpString("Trace full"); - clear_trace(); - } - } - } - - // 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; - - LED_B_OFF(); - } - // Reset the frame length - rxlen = 0; - // Save the timer overflow, will be 0 when frame was received - 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; - } - Dbprintf("Hitag S simulation stopped"); - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); -} - -/* - * Authenticates to the Tag with the given key or challenge. - * If the key was given the password will be decrypted. - * Reads every page of a hitag S transpoder. - */ -void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int startPage, bool readBlock) { - int frame_count; - int i; - int sendNum = startPage; - tag.mode = tagMode; - - //int i, j, z; - //int response_bit[200]; - //unsigned char mask = 1; - - int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen = 0; - int lastbit; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop; - bool bQuitTraceFull = false; - - page_to_be_written = 0; - - //read given key/challenge - byte_t NrAr_[8]; - uint64_t key=0; - uint64_t NrAr=0; - byte_t key_[6]; - switch(htf) { - case 01: - case 03: { //RHTS_CHALLENGE - DbpString("Authenticating using nr,ar pair:"); - memcpy(NrAr_,htd->auth.NrAr,8); - Dbhexdump(8,NrAr_,false); - NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | - ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; - } break; - case 02: - case 04: { //RHTS_KEY - DbpString("Authenticating using key:"); - memcpy(key_,htd->crypto.key,6); - Dbhexdump(6,key_,false); - key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; - } break; - default: { - Dbprintf("Error , unknown function: %d",htf); - return; - } break; - } - - - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - bQuiet = false; - - LED_D_ON(); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - - // Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; - t_wait = 200; - - while (!bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); - - - // Add transmitted frame to total count - if (txlen > 0) { - frame_count++; - - if (tag.pstate == READY && rxlen < 1) { - //skip logging starting auths if no response - } else { - if (!bQuiet) { - // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { - if (bQuitTraceFull) { - DbpString("Trace full"); - break; - } else { - bQuiet = true; - } - } - } - } - } - - // Check if frame was captured and store it - if (rxlen > 0) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, false)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - // By default reset the transmission buffer - tx = txbuf; - txlen = 0; - - if (DEBUG >= 2) { - Dbprintf("FRO %d rxlen: %d, pstate=%d, tstate=%d", frame_count, rxlen, (int)tag.pstate, (int)tag.tstate); - } - - if (rxlen == 0) { - //start authentication - hitag_start_auth(tx, &txlen); - } else if (tag.pstate != SELECTED) { - if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1) { - Dbprintf("hitagS_handle_tag_auth - bStop = !false"); - bStop = !false; - } - } - - - - if (readBlock && tag.pstate == SELECTED && (tag.tstate == READING_BLOCK || tag.tstate == NO_OP) && rxlen > 0) { - i = hitag_read_block(htf, key, rx, &rxlen, tx, &txlen, sendNum); - if (i > 0) { sendNum+=4; } - if (sendNum+4 >= tag.max_page) { - bStop = !false; - } - } else if (!readBlock && tag.pstate == SELECTED && (tag.tstate == READING_PAGE || tag.tstate == NO_OP) && rxlen > 0) { - i = hitag_read_page(htf, key, rx, &rxlen, tx, &txlen, sendNum); - if (i > 0) { sendNum++; } - if (sendNum >= tag.max_page) { - bStop = !false; - } - } - - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occured halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) { } - - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); - - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - response = 0; - - // get tag id in anti-collision mode (proprietary data format, so switch off manchester and read at double the data rate, for 4 x the data bits) - hitag_receive_frame(rx, &rxlen, &response); - } - end=false; - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); -} - -void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock) { - if (tagMode == 1) { - Dbprintf("ReadHitagS in mode=ADVANCED, blockRead=%d, startPage=%d", readBlock, startPage); - ReadHitagSintern(htf, htd, ADVANCED, (int)startPage, readBlock); - } else if (tagMode == 2) { - Dbprintf("ReadHitagS in mode=FAST_ADVANCED, blockRead=%d, startPage=%d", readBlock, startPage); - ReadHitagSintern(htf, htd, FAST_ADVANCED, (int)startPage, readBlock); - } else { - Dbprintf("ReadHitagS in mode=STANDARD, blockRead=%d, startPage=%d", readBlock, startPage); - ReadHitagSintern(htf, htd, STANDARD, (int)startPage, readBlock); - } -} - - - -/* - * Authenticates to the Tag with the given Key or Challenge. - * Writes the given 32Bit data into page_ - */ -void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { - int frame_count; - int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen = 0; - int lastbit; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop; - bool bQuitTraceFull = false; - int page = page_; - unsigned char crc; - byte_t data[4]= {0,0,0,0}; - - //read given key/challenge, the page and the data - byte_t NrAr_[8]; - uint64_t key=0; - uint64_t NrAr=0; - byte_t key_[6]; - switch(htf) { - case 03: { //WHTS_CHALLENGE - memcpy(data,htd->auth.data,4); - DbpString("Authenticating using nr,ar pair:"); - memcpy(NrAr_,htd->auth.NrAr,8); - Dbhexdump(8,NrAr_,false); - NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | - ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; - } break; - case 04: { //WHTS_KEY - memcpy(data,htd->crypto.data,4); - DbpString("Authenticating using key:"); - memcpy(key_,htd->crypto.key,6); - Dbhexdump(6,key_,false); - key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; - } break; - default: { - Dbprintf("Error , unknown function: %d",htf); - return; - } break; - } - - Dbprintf("Page: %d",page_); - Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]); - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; - - tag.pstate = READY; - tag.tstate = NO_OP; - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - bQuiet = false; - - LED_D_ON(); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - - // Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK - | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG - | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; - t_wait = 200; - - while (!bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); - - // Check if frame was captured and store it - if (rxlen > 0) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, false)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - //check for valid input - /* - if (page == 0) { - Dbprintf("usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); - bStop = !false; - }*/ - - - // By default reset the transmission buffer - tx = txbuf; - txlen = 0; - - if (rxlen == 0 && tag.tstate == WRITING_PAGE_ACK) { - //no write access on this page - Dbprintf("no write access on page %d", page_); - bStop = !false; - } else if (rxlen == 0 && tag.tstate != WRITING_PAGE_DATA) { - //start the authetication - //tag.mode = ADVANCED; - tag.mode = STANDARD; - hitag_start_auth(tx, &txlen); - m = AC2K; - } else if (tag.pstate != SELECTED) { - //try to authenticate with the given key or challenge - if (hitagS_handle_tag_auth(htf,key,NrAr,rx, rxlen, tx, &txlen) == -1) { - bStop = !false; - } - m = MC4K; - } - - if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) { - //check if the given page exists - if (page > tag.max_page) { - Dbprintf("page number too big"); - bStop = !false; - } - //ask Tag for write permission - tag.tstate = WRITING_PAGE_ACK; - txlen = 20; - crc = CRC_PRESET; - tx[0] = 0x90 + (page / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((page % 16) * 16), 4); - tx[1] = 0x00 + ((page % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_ACK - && rxlen == 2 && rx[0] == 0x40) { - //ACK recieved to write the page. send data - tag.tstate = WRITING_PAGE_DATA; - txlen = 40; - crc = CRC_PRESET; - calc_crc(&crc, data[3], 8); - calc_crc(&crc, data[2], 8); - calc_crc(&crc, data[1], 8); - calc_crc(&crc, data[0], 8); - tx[0] = data[3]; - tx[1] = data[2]; - tx[2] = data[1]; - tx[3] = data[0]; - tx[4] = crc; - } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_DATA - && rxlen == 2 && rx[0] == 0x40) { - //received ACK - Dbprintf("Successful!"); - bStop = !false; - } - - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occured halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - - while (AT91C_BASE_TC0->TC_CV - < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) - ; - - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Add transmitted frame to total count - if (txlen > 0) { - frame_count++; - if (!bQuiet) { - // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { - if (bQuitTraceFull) { - DbpString("Trace full"); - break; - } else { - bQuiet = true; - } - } - } - } - - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - response = 0; - - hitag_receive_frame(rx, &rxlen, &response); - } - end=false; - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); -} - - -/* - * Tries to authenticate to a Hitag S Transponder with the given challenges from a .cc file. - * Displays all Challenges that failed. - * When collecting Challenges to break the key it is possible that some data - * is not received correctly due to Antenna problems. This function - * detects these challenges. - */ -void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode) { - int i, j, z, k; - byte_t uid_byte[4]; - int frame_count; - int response; - byte_t rx[HITAG_FRAME_LEN]; - byte_t unlocker[60][8]; - int u1 = 0; - size_t rxlen = 0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen = 0; - int lastbit; - int t_wait = HITAG_T_WAIT_MAX; - int STATE = 0; - bool bStop; - bool bQuitTraceFull = false; - int response_bit[200]; - unsigned char mask = 1; - unsigned char uid[32]; - unsigned char crc; - - if (tagMode == 1) { - Dbprintf("check_challenges in mode=ADVANCED"); - tag.mode = ADVANCED; - } else if (tagMode == 2) { - Dbprintf("check_challenges in mode=FAST_ADVANCED"); - tag.mode = FAST_ADVANCED; - } else { - Dbprintf("check_challenges in mode=STANDARD"); - tag.mode = STANDARD; - } - - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - // Reset the return status - bSuccessful = false; - - // Clean up trace and prepare it for storing frames - set_tracing(true); - clear_trace(); - - bQuiet = false; - - LED_D_ON(); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord( - FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - - // Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); - - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Reset the received frame, frame count and timing info - frame_count = 0; - response = 0; - lastbit = 1; - bStop = false; - - t_wait = 200; - - if (file_given) { - DbpString("Loading challenges..."); - memcpy((byte_t*)unlocker,data,60*8); - } - - while (file_given && !bStop && !BUTTON_PRESS()) { - // Watchdog hit - WDT_HIT(); - - // Check if frame was captured and store it - if (rxlen > 0) { - frame_count++; - if (!bQuiet) { - if (!LogTraceHitag(rx, rxlen, response, 0, false)) { - DbpString("Trace full"); - if (bQuitTraceFull) { - break; - } else { - bQuiet = true; - } - } - } - } - - tx = txbuf; - txlen = 0; - if (rxlen == 0) { - if (STATE == 2) { - // challenge failed - Dbprintf("Challenge failed: %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; - hitag_start_auth(tx, &txlen); - } else if (rxlen >= 32 && STATE == 0) { - //received uid - z = 0; - for (i = 0; i < 10; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) - response_bit[z] = 1; - z++; - } - } - for (i = 0; i < 32; i++) { - uid[i] = response_bit[i]; - } - - uid_byte[0] = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) - | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) - | (uid[6] << 1) | uid[7]; - uid_byte[1] = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) - | (uid[11] << 4) | (uid[12] << 3) | (uid[13] << 2) - | (uid[14] << 1) | uid[15]; - uid_byte[2] = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) - | (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2) - | (uid[22] << 1) | uid[23]; - uid_byte[3] = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) - | (uid[27] << 4) | (uid[28] << 3) | (uid[29] << 2) - | (uid[30] << 1) | uid[31]; - //Dbhexdump(10, rx, rxlen); - STATE = 1; - txlen = 45; - crc = CRC_PRESET; - calc_crc(&crc, 0x00, 5); - calc_crc(&crc, uid_byte[0], 8); - calc_crc(&crc, uid_byte[1], 8); - calc_crc(&crc, uid_byte[2], 8); - calc_crc(&crc, uid_byte[3], 8); - for (i = 0; i < 100; i++) { - response_bit[i] = 0; - } - for (i = 0; i < 5; i++) { - response_bit[i] = 0; - } - for (i = 5; i < 37; i++) { - response_bit[i] = uid[i - 5]; - } - for (j = 0; j < 8; j++) { - response_bit[i] = 0; - if ((crc & ((mask << 7) >> j)) != 0) - response_bit[i] = 1; - i++; - } - k = 0; - for (i = 0; i < 6; i++) { - tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) - | (response_bit[k + 2] << 5) - | (response_bit[k + 3] << 4) - | (response_bit[k + 4] << 3) - | (response_bit[k + 5] << 2) - | (response_bit[k + 6] << 1) | response_bit[k + 7]; - k += 8; - } - - - tag.pstate = INIT; - } else if (STATE == 1 && rxlen > 24) { - //received configuration - STATE = 2; - z = 0; - for (i = 0; i < 6; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) - response_bit[z] = 1; - z++; - } - } - txlen = 64; - - if (u1 >= (sizeof(unlocker) / sizeof(unlocker[0]))) - bStop = !false; - for (i = 0; i < 8; i++) - tx[i] = unlocker[u1][i]; - u1++; - - tag.pstate = SELECTED; - } else if (STATE == 2 && rxlen >= 32) { - STATE = 0; - } - - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occured halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) { } - - // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); - - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // Add transmitted frame to total count - if (txlen > 0) { - frame_count++; - if (!bQuiet) { - // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { - if (bQuitTraceFull) { - DbpString("Trace full"); - break; - } else { - bQuiet = true; - } - } - } - } - - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - response = 0; - - hitag_receive_frame(rx, &rxlen, &response); - } - LED_B_OFF(); - LED_D_OFF(); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); -} - -/** -Backward compatibility -*/ -void check_challenges(bool file_given, byte_t* data) { - check_challenges_cmd(file_given, data, 1); -} - -void ReadHitagS(hitag_function htf, hitag_data* htd) { - ReadHitagSintern(htf, htd, ADVANCED, 0, false); -} diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h deleted file mode 100644 index 8451b2cf..00000000 --- a/armsrc/hitagS.h +++ /dev/null @@ -1,26 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// HitagS emulation (preliminary test version) -// -// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg -// -//----------------------------------------------------------------------------- -// Some code was copied from Hitag2.c -//----------------------------------------------------------------------------- - -#ifndef HITAGS_H__ -#define HITAGS_H__ - -#include -#include -#include "hitag.h" - -void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock); -void SimulateHitagSTag(bool tag_mem_supplied, uint8_t* data); -void WritePageHitagS(hitag_function htf, hitag_data* htd, int page); -void check_challenges_cmd(bool file_given, uint8_t* data, uint64_t tagMode); - -#endif \ No newline at end of file diff --git a/armsrc/i2c.c b/armsrc/i2c.c deleted file mode 100644 index a17dd162..00000000 --- a/armsrc/i2c.c +++ /dev/null @@ -1,811 +0,0 @@ -//----------------------------------------------------------------------------- -// Willok, June 2018 -// Edits by Iceman, July 2018 -// -// 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. -//----------------------------------------------------------------------------- -// The main i2c code, for communications with smart card module -//----------------------------------------------------------------------------- - -#include "i2c.h" - -#include -#include -#include "string.h" //for memset memcmp -#include "proxmark3.h" -#include "mifareutil.h" // for MF_DBGLEVEL -#include "BigBuf.h" -#include "apps.h" -#include "usb_cdc.h" -#include "util.h" - - -#ifdef WITH_SMARTCARD -#include "smartcard.h" -#endif - - -#define GPIO_RST AT91C_PIO_PA1 -#define GPIO_SCL AT91C_PIO_PA5 -#define GPIO_SDA AT91C_PIO_PA7 - -#define SCL_H HIGH(GPIO_SCL) -#define SCL_L LOW(GPIO_SCL) -#define SDA_H HIGH(GPIO_SDA) -#define SDA_L LOW(GPIO_SDA) - -#define SCL_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SCL) -#define SDA_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SDA) - -#define I2C_ERROR "I2C_WaitAck Error" - -static volatile unsigned long c; - -// ֱʹѭʱһѭ 6 ָ48M Delay=1 Ϊ 200kbps -// timer. -// I2CSpinDelayClk(4) = 12.31us -// I2CSpinDelayClk(1) = 3.07us -static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { - for (c = delay * 2; c; c--) {}; -} - -// communication delay functions -#define I2C_DELAY_1CLK I2CSpinDelayClk(1) -#define I2C_DELAY_2CLK I2CSpinDelayClk(2) -#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) - -#define ISO7618_MAX_FRAME 255 - -// try i2c bus recovery at 100kHz = 5uS high, 5uS low -static void I2C_recovery(void) { - - DbpString("Performing i2c bus recovery"); - - // reset I2C - SDA_H; SCL_H; - - //9nth cycle acts as NACK - for (int i = 0; i < 10; i++) { - SCL_H; WaitUS(5); - SCL_L; WaitUS(5); - } - - //a STOP signal (SDA from low to high while CLK is high) - SDA_L; WaitUS(5); - SCL_H; WaitUS(2); - SDA_H; WaitUS(2); - - bool isok = (SCL_read && SDA_read); - if (!SDA_read) - DbpString("I2C bus recovery error: SDA still LOW"); - if (!SCL_read) - DbpString("I2C bus recovery error: SCL still LOW"); - if (isok) - DbpString("I2C bus recovery complete"); -} - -static void I2C_init(void) { - // Configure reset pin - AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; // disable pull up resistor - AT91C_BASE_PIOA->PIO_MDDR = GPIO_RST; // push-pull output (multidriver disabled) - - // Configure SCL and SDA pins - AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_SCL | GPIO_SDA); // enable pull up resistor - AT91C_BASE_PIOA->PIO_MDER |= (GPIO_SCL | GPIO_SDA); // open drain output (multidriver enabled) - requires external pull up resistor - - // set all three outputs to high - AT91C_BASE_PIOA->PIO_SODR |= (GPIO_SCL | GPIO_SDA | GPIO_RST); - - // configure all three pins as output, controlled by PIOA - AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST); - AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST); - - bool isok = (SCL_read && SDA_read); - if ( !isok ) - I2C_recovery(); - -} - -// set the reset state -static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) { - if (LineRST) - HIGH(GPIO_RST); - else - LOW(GPIO_RST); - - if (LineSCK) - HIGH(GPIO_SCL); - else - LOW(GPIO_SCL); - - if (LineSDA) - HIGH(GPIO_SDA); - else - LOW(GPIO_SDA); -} - -// Reset the SIM_Adapter, then enter the main program -// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter. -static void I2C_Reset_EnterMainProgram(void) { - StartTicks(); - I2C_init(); - I2C_SetResetStatus(0, 0, 0); - WaitMS(30); - I2C_SetResetStatus(1, 0, 0); - WaitMS(30); - I2C_SetResetStatus(1, 1, 1); - WaitMS(10); -} - -// Wait for the clock to go High. -static bool WaitSCL_H_delay(uint32_t delay) { - while (delay--) { - if (SCL_read) { - return true; - } - I2C_DELAY_1CLK; - } - return false; -} - -// 15000 * 3.07us = 46050us. 46.05ms -static bool WaitSCL_H(void) { - return WaitSCL_H_delay(15000); -} - -bool WaitSCL_L_delay(uint32_t delay) { - while (delay--) { - if (!SCL_read) { - return true; - } - I2C_DELAY_1CLK; - } - return false; -} - -bool WaitSCL_L(void) { - return WaitSCL_L_delay(15000); -} - -static bool I2C_Start(void) { - - I2C_DELAY_XCLK(4); - SDA_H; I2C_DELAY_1CLK; - SCL_H; - if (!WaitSCL_H()) return false; - - I2C_DELAY_2CLK; - - if (!SCL_read) return false; - if (!SDA_read) return false; - - SDA_L; I2C_DELAY_2CLK; - return true; -} - -// send i2c STOP -static void I2C_Stop(void) { - SCL_L; I2C_DELAY_2CLK; - SDA_L; I2C_DELAY_2CLK; - SCL_H; I2C_DELAY_2CLK; - if (!WaitSCL_H()) return; - SDA_H; - I2C_DELAY_XCLK(8); -} - -static bool I2C_WaitAck(void) { - SCL_L; I2C_DELAY_1CLK; - SDA_H; I2C_DELAY_1CLK; - SCL_H; - if (!WaitSCL_H()) - return false; - - I2C_DELAY_2CLK; - I2C_DELAY_2CLK; - if (SDA_read) { - SCL_L; - return false; - } - SCL_L; - return true; -} - -static void I2C_SendByte(uint8_t data) { - uint8_t bits = 8; - - while (bits--) { - SCL_L; - I2C_DELAY_1CLK; - - if (data & 0x80) - SDA_H; - else - SDA_L; - - data <<= 1; - - I2C_DELAY_1CLK; - - SCL_H; - if (!WaitSCL_H()) - return; - - I2C_DELAY_2CLK; - } - SCL_L; -} - -bool I2C_is_available(void) { - I2C_Reset_EnterMainProgram(); - if (!I2C_Start()) // some other device is active on the bus - return true; - I2C_SendByte(I2C_DEVICE_ADDRESS_MAIN & 0xFE); - if (!I2C_WaitAck()) { // no response from smartcard reader - I2C_Stop(); - return false; - } - I2C_Stop(); - return true; -} - -#ifdef WITH_SMARTCARD -// Reset the SIM_Adapter, then enter the bootloader program -// ReserveFor firmware update. -static void I2C_Reset_EnterBootloader(void) { - I2C_SetResetStatus(0, 1, 1); - WaitMS(100); - I2C_SetResetStatus(1, 1, 1); - WaitMS(10); -} - -// Wait max 1800ms or until SCL goes LOW. -// It timeout reading response from card -// Which ever comes first -bool WaitSCL_L_timeout(void){ - volatile uint16_t delay = 1800; - while ( delay-- ) { - // exit on SCL LOW - if (!SCL_read) - return true; - - WaitMS(1); - } - return (delay == 0); -} - -static bool I2C_WaitForSim() { - // wait for data from card - if (!WaitSCL_L_timeout()) - return false; - - // 8051 speaks with smart card. - // 1000*50*3.07 = 153.5ms - // 1byte transfer == 1ms with max frame being 256bytes - if (!WaitSCL_H_delay(10 * 1000 * 50)) - return false; - - return true; -} - -// Send i2c ACK -static void I2C_Ack(void) { - SCL_L; I2C_DELAY_2CLK; - SDA_L; I2C_DELAY_2CLK; - SCL_H; I2C_DELAY_2CLK; - if (!WaitSCL_H()) return; - SCL_L; I2C_DELAY_2CLK; -} - -// Send i2c NACK -static void I2C_NoAck(void) { - SCL_L; I2C_DELAY_2CLK; - SDA_H; I2C_DELAY_2CLK; - SCL_H; I2C_DELAY_2CLK; - if (!WaitSCL_H()) return; - SCL_L; I2C_DELAY_2CLK; -} - -static int16_t I2C_ReadByte(void) { - uint8_t bits = 8, b = 0; - - SDA_H; - while (bits--) { - b <<= 1; - SCL_L; - if (!WaitSCL_L()) return -2; - - I2C_DELAY_1CLK; - - SCL_H; - if (!WaitSCL_H()) return -1; - - I2C_DELAY_1CLK; - if (SDA_read) - b |= 0x01; - } - SCL_L; - return b; -} - -// Sends one byte ( command to be written, SlaveDevice address) -static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) { - bool bBreak = true; - do { - if (!I2C_Start()) - return false; - - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(device_cmd); - if (!I2C_WaitAck()) - break; - - bBreak = false; - } while (false); - - I2C_Stop(); - if (bBreak) { - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return false; - } - return true; -} - -// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ). -static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) { - bool bBreak = true; - do { - if (!I2C_Start()) - return false; - - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(device_cmd); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(data); - if (!I2C_WaitAck()) - break; - - bBreak = false; - } while (false); - - I2C_Stop(); - if (bBreak) { - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return false; - } - return true; -} - -//Sends a string of data (Array, length, command to be written , SlaveDevice address ). -// len = uint8 (max buffer to write 256bytes) -static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { - bool bBreak = true; - do { - if (!I2C_Start()) - return false; - - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(device_cmd); - if (!I2C_WaitAck()) - break; - - while (len) { - - I2C_SendByte(*data); - if (!I2C_WaitAck()) - break; - - len--; - data++; - } - - if (len == 0) - bBreak = false; - } while (false); - - I2C_Stop(); - if (bBreak) { - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return false; - } - return true; -} - -// read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ). -// len = uint8 (max buffer to read 256bytes) -static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { - - if ( !data || len == 0 ) - return 0; - - // extra wait 500us (514us measured) - // 200us (xx measured) - WaitUS(600); - bool bBreak = true; - uint16_t readcount = 0; - - do { - if (!I2C_Start()) - return 0; - - // 0xB0 / 0xC0 == i2c write - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(device_cmd); - if (!I2C_WaitAck()) - break; - - // 0xB1 / 0xC1 == i2c read - I2C_Start(); - I2C_SendByte(device_address | 1); - if (!I2C_WaitAck()) - break; - - bBreak = false; - } while (false); - - if (bBreak) { - I2C_Stop(); - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return 0; - } - - while (len) { - - int16_t tmp = I2C_ReadByte(); - if ( tmp < 0 ) - return tmp; - - *data = (uint8_t)tmp & 0xFF; - - len--; - - // ȡĵһֽΪ - // The first byte in response is the message length - if (!readcount && (len > *data)) { - len = *data; - } else { - data++; - } - readcount++; - - // acknowledgements. After last byte send NACK. - if (len == 0) - I2C_NoAck(); - else - I2C_Ack(); - } - - I2C_Stop(); - - // return bytecount - first byte (which is length byte) - return --readcount; -} - -static int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) { - //START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP - bool bBreak = true; - uint8_t readcount = 0; - - // sending - do { - if (!I2C_Start()) - return 0; - - // 0xB0 / 0xC0 i2c write - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(msb); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(lsb); - if (!I2C_WaitAck()) - break; - - // 0xB1 / 0xC1 i2c read - I2C_Start(); - I2C_SendByte(device_address | 1); - if (!I2C_WaitAck()) - break; - - bBreak = false; - } while (false); - - if (bBreak) { - I2C_Stop(); - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return 0; - } - - // reading - while (len) { - - int16_t tmp = I2C_ReadByte(); - if ( tmp < 0 ) - return tmp; - - *data = (uint8_t)tmp & 0xFF; - - data++; - readcount++; - len--; - - // acknowledgements. After last byte send NACK. - if (len == 0) - I2C_NoAck(); - else - I2C_Ack(); - } - - I2C_Stop(); - return readcount; -} - -static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) { - //START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP - bool bBreak = true; - - do { - if (!I2C_Start()) - return false; - - // 0xB0 == i2c write - I2C_SendByte(device_address & 0xFE); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(msb); - if (!I2C_WaitAck()) - break; - - I2C_SendByte(lsb); - if (!I2C_WaitAck()) - break; - - while (len) { - I2C_SendByte(*data); - if (!I2C_WaitAck()) - break; - - len--; - data++; - } - - if (len == 0) - bBreak = false; - } while (false); - - I2C_Stop(); - if (bBreak) { - if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - return false; - } - return true; -} - -void I2C_print_status(void) { - DbpString("Smart card module (ISO 7816)"); - uint8_t resp[] = {0,0,0,0}; - I2C_Reset_EnterMainProgram(); - uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN); - if ( len > 0 ) - Dbprintf(" version.................v%x.%02x", resp[0], resp[1]); - else - DbpString(" version.................FAILED"); -} - -// Will read response from smart card module, retries 3 times to get the data. -static bool sc_rx_bytes(uint8_t* dest, uint8_t *destlen) { - uint8_t i = 3; - int16_t len = 0; - while (i--) { - - I2C_WaitForSim(); - - len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN); - - if ( len > 1 ){ - break; - } else if ( len == 1 ) { - continue; - } else if ( len <= 0 ) { - return false; - } - } - // after three - if ( len <= 1 ) - return false; - - *destlen = (uint8_t)len & 0xFF; - return true; -} - -static bool GetATR(smart_card_atr_t *card_ptr) { - - if ( !card_ptr ) { - return false; - } - - card_ptr->atr_len = 0; - memset(card_ptr->atr, 0, sizeof(card_ptr->atr)); - - // Send ATR - // start [C0 01] stop start C1 len aa bb cc stop] - I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN); - - // wait for sim card to answer. - // 1byte = 1ms, max frame 256bytes. Should wait 256ms at least just in case. - if (!I2C_WaitForSim()) - return false; - - // read bytes from module - uint8_t len = sizeof(card_ptr->atr); - if ( !sc_rx_bytes(card_ptr->atr, &len) ) - return false; - - card_ptr->atr_len = len; - LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false); - - return true; -} - -void SmartCardAtr(void) { - smart_card_atr_t card; - LED_D_ON(); - clear_trace(); - set_tracing(true); - I2C_Reset_EnterMainProgram(); - bool isOK = GetATR( &card ); - cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); - set_tracing(false); - LEDsoff(); -} - -void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) { - - LED_D_ON(); - - uint8_t len = 0; - uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME); - smartcard_command_t flags = arg0; - - if ((flags & SC_CONNECT)) - clear_trace(); - - set_tracing(true); - - if ((flags & SC_CONNECT)) { - - I2C_Reset_EnterMainProgram(); - - if ((flags & SC_SELECT)) { - smart_card_atr_t card; - bool gotATR = GetATR( &card ); - //cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); - if ( !gotATR ) - goto OUT; - } - } - - if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { - - LogTrace(data, arg1, 0, 0, NULL, true); - - // Send raw bytes - // asBytes = A0 A4 00 00 02 - // arg1 = len 5 - bool res = I2C_BufferWrite(data, arg1, ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), I2C_DEVICE_ADDRESS_MAIN); - if ( !res && MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); - - // read bytes from module - len = ISO7618_MAX_FRAME; - res = sc_rx_bytes(resp, &len); - if ( res ) { - LogTrace(resp, len, 0, 0, NULL, false); - } else { - len = 0; - } - } -OUT: - cmd_send(CMD_ACK, len, 0, 0, resp, len); - BigBuf_free(); - set_tracing(false); - LEDsoff(); -} - -void SmartCardUpgrade(uint64_t arg0) { - - LED_C_ON(); - - #define I2C_BLOCK_SIZE 128 - // write. Sector0, with 11,22,33,44 - // erase is 128bytes, and takes 50ms to execute - - I2C_Reset_EnterBootloader(); - - bool isOK = true; - int16_t res = 0; - uint16_t length = arg0; - uint16_t pos = 0; - uint8_t *fwdata = BigBuf_get_addr(); - uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE); - - while (length) { - - uint8_t msb = (pos >> 8) & 0xFF; - uint8_t lsb = pos & 0xFF; - - Dbprintf("FW %02X%02X", msb, lsb); - - size_t size = MIN(I2C_BLOCK_SIZE, length); - - // write - res = I2C_WriteFW(fwdata+pos, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); - if ( !res ) { - DbpString("Writing failed"); - isOK = false; - break; - } - - // writing takes time. - WaitMS(50); - - // read - res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); - if ( res <= 0) { - DbpString("Reading back failed"); - isOK = false; - break; - } - - // cmp - if ( 0 != memcmp(fwdata+pos, verfiydata, size)) { - DbpString("not equal data"); - isOK = false; - break; - } - - length -= size; - pos += size; - } - cmd_send(CMD_ACK, isOK, pos, 0, 0, 0); - LED_C_OFF(); - BigBuf_free(); -} - -// unfinished (or not needed?) -//void SmartCardSetBaud(uint64_t arg0) { -//} - -void SmartCardSetClock(uint64_t arg0) { - LED_D_ON(); - set_tracing(true); - I2C_Reset_EnterMainProgram(); - - // Send SIM CLC - // start [C0 05 xx] stop - I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN); - - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - set_tracing(false); - LEDsoff(); -} - -#endif \ No newline at end of file diff --git a/armsrc/i2c.h b/armsrc/i2c.h deleted file mode 100644 index df66adef..00000000 --- a/armsrc/i2c.h +++ /dev/null @@ -1,39 +0,0 @@ -//----------------------------------------------------------------------------- -// Willok, June 2018 -// Edits by Iceman, July 2018 -// -// 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. -//----------------------------------------------------------------------------- -// The main i2c code, for communications with smart card module -//----------------------------------------------------------------------------- -#ifndef __I2C_H -#define __I2C_H - -#include -#include - -#define I2C_DEVICE_ADDRESS_BOOT 0xB0 -#define I2C_DEVICE_ADDRESS_MAIN 0xC0 - -#define I2C_DEVICE_CMD_GENERATE_ATR 0x01 -#define I2C_DEVICE_CMD_SEND 0x02 -#define I2C_DEVICE_CMD_READ 0x03 -#define I2C_DEVICE_CMD_SETBAUD 0x04 -#define I2C_DEVICE_CMD_SIM_CLC 0x05 -#define I2C_DEVICE_CMD_GETVERSION 0x06 -#define I2C_DEVICE_CMD_SEND_T0 0x07 - - -bool I2C_is_available(void); - -#ifdef WITH_SMARTCARD -void SmartCardAtr(void); -void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data); -void SmartCardUpgrade(uint64_t arg0); -void SmartCardSetClock(uint64_t arg0); -void I2C_print_status(void); -#endif - -#endif // __I2C_H diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 3f89ae85..e876132e 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -3,7 +3,6 @@ // Hagen Fritsch - June 2010 // Gerhard de Koning Gans - May 2011 // Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation -// piwi - 2019 // // 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 @@ -11,160 +10,1015 @@ //----------------------------------------------------------------------------- // Routines to support iClass. //----------------------------------------------------------------------------- +// Based on ISO14443a implementation. Still in experimental phase. // Contribution made during a security research at Radboud University Nijmegen -// +// // Please feel free to contribute and extend iClass support!! //----------------------------------------------------------------------------- - -#include "iclass.h" +// +// FIX: +// ==== +// We still have sometimes a demodulation error when snooping iClass communication. +// The resulting trace of a read-block-03 command may look something like this: +// +// + 22279: : 0c 03 e8 01 +// +// ...with an incorrect answer... +// +// + 85: 0: TAG ff! ff! ff! ff! ff! ff! ff! ff! bb 33 bb 00 01! 0e! 04! bb !crc +// +// We still left the error signalling bytes in the traces like 0xbb +// +// A correct trace should look like this: +// +// + 21112: : 0c 03 e8 01 +// + 85: 0: TAG ff ff ff ff ff ff ff ff ea f5 +// +//----------------------------------------------------------------------------- #include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" -#include "printf.h" #include "common.h" -#include "usb_cdc.h" -#include "iso14443a.h" -#include "iso15693.h" // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) #include "iso14443crc.h" -#include "iso15693tools.h" -#include "protocols.h" -#include "optimized_cipher.h" -#include "fpgaloader.h" -// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after -// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period. -// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating. -// 56,64us = 24 ssp_clk_cycles -#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) -// times in ssp_clk_cycles @ 3,3625MHz when acting as reader -#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER -// times in samples @ 212kHz when acting as reader -#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us -#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms -#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us +static int timeout = 4096; -#define ICLASS_BUFFER_SIZE 34 // we expect max 34 bytes as tag answer (response to READ4) +// CARD TO READER +// Sequence D: 11110000 modulation with subcarrier during first half +// Sequence E: 00001111 modulation with subcarrier during second half +// Sequence F: 00000000 no modulation with subcarrier +// READER TO CARD +// Sequence X: 00001100 drop after half a period +// Sequence Y: 00000000 no drop +// Sequence Z: 11000000 drop at start +#define SEC_X 0x0c +#define SEC_Y 0x00 +#define SEC_Z 0xc0 +static int SendIClassAnswer(uint8_t *resp, int respLen, int delay); -//============================================================================= -// A `sniffer' for iClass communication -// Both sides of communication! -//============================================================================= -void SnoopIClass(uint8_t jam_search_len, uint8_t *jam_search_string) { - SnoopIso15693(jam_search_len, jam_search_string); +//----------------------------------------------------------------------------- +// The software UART that receives commands from the reader, and its state +// variables. +//----------------------------------------------------------------------------- +static struct { + enum { + STATE_UNSYNCD, + STATE_START_OF_COMMUNICATION, + STATE_RECEIVING + } state; + uint16_t shiftReg; + int bitCnt; + int byteCnt; + int byteCntMax; + int posCnt; + int nOutOfCnt; + int OutOfCnt; + int syncBit; + int parityBits; + int samples; + int highCnt; + int swapper; + int counter; + int bitBuffer; + int dropPosition; + uint8_t *output; +} Uart; + +static RAMFUNC int OutOfNDecoding(int bit) +{ + //int error = 0; + int bitright; + + if(!Uart.bitBuffer) { + Uart.bitBuffer = bit ^ 0xFF0; + return FALSE; + } + else { + Uart.bitBuffer <<= 4; + Uart.bitBuffer ^= bit; + } + + /*if(Uart.swapper) { + Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; + Uart.byteCnt++; + Uart.swapper = 0; + if(Uart.byteCnt > 15) { return TRUE; } + } + else { + Uart.swapper = 1; + }*/ + + if(Uart.state != STATE_UNSYNCD) { + Uart.posCnt++; + + if((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) { + bit = 0x00; + } + else { + bit = 0x01; + } + if(((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) { + bitright = 0x00; + } + else { + bitright = 0x01; + } + if(bit != bitright) { bit = bitright; } + + + // So, now we only have to deal with *bit*, lets see... + if(Uart.posCnt == 1) { + // measurement first half bitperiod + if(!bit) { + // Drop in first half means that we are either seeing + // an SOF or an EOF. + + if(Uart.nOutOfCnt == 1) { + // End of Communication + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + if(Uart.byteCnt == 0) { + // Its not straightforward to show single EOFs + // So just leave it and do not return TRUE + Uart.output[Uart.byteCnt] = 0xf0; + Uart.byteCnt++; + + // Calculate the parity bit for the client... + Uart.parityBits = 1; + } + else { + return TRUE; + } + } + else if(Uart.state != STATE_START_OF_COMMUNICATION) { + // When not part of SOF or EOF, it is an error + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + //error = 4; + } + } + } + else { + // measurement second half bitperiod + // Count the bitslot we are in... (ISO 15693) + Uart.nOutOfCnt++; + + if(!bit) { + if(Uart.dropPosition) { + if(Uart.state == STATE_START_OF_COMMUNICATION) { + //error = 1; + } + else { + //error = 7; + } + // It is an error if we already have seen a drop in current frame + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + } + else { + Uart.dropPosition = Uart.nOutOfCnt; + } + } + + Uart.posCnt = 0; + + + if(Uart.nOutOfCnt == Uart.OutOfCnt && Uart.OutOfCnt == 4) { + Uart.nOutOfCnt = 0; + + if(Uart.state == STATE_START_OF_COMMUNICATION) { + if(Uart.dropPosition == 4) { + Uart.state = STATE_RECEIVING; + Uart.OutOfCnt = 256; + } + else if(Uart.dropPosition == 3) { + Uart.state = STATE_RECEIVING; + Uart.OutOfCnt = 4; + //Uart.output[Uart.byteCnt] = 0xdd; + //Uart.byteCnt++; + } + else { + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + } + Uart.dropPosition = 0; + } + else { + // RECEIVING DATA + // 1 out of 4 + if(!Uart.dropPosition) { + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + //error = 9; + } + else { + Uart.shiftReg >>= 2; + + // Swap bit order + Uart.dropPosition--; + //if(Uart.dropPosition == 1) { Uart.dropPosition = 2; } + //else if(Uart.dropPosition == 2) { Uart.dropPosition = 1; } + + Uart.shiftReg ^= ((Uart.dropPosition & 0x03) << 6); + Uart.bitCnt += 2; + Uart.dropPosition = 0; + + if(Uart.bitCnt == 8) { + Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff); + Uart.byteCnt++; + + // Calculate the parity bit for the client... + Uart.parityBits <<= 1; + Uart.parityBits ^= OddByteParity[(Uart.shiftReg & 0xff)]; + + Uart.bitCnt = 0; + Uart.shiftReg = 0; + } + } + } + } + else if(Uart.nOutOfCnt == Uart.OutOfCnt) { + // RECEIVING DATA + // 1 out of 256 + if(!Uart.dropPosition) { + Uart.state = STATE_UNSYNCD; + Uart.highCnt = 0; + //error = 3; + } + else { + Uart.dropPosition--; + Uart.output[Uart.byteCnt] = (Uart.dropPosition & 0xff); + Uart.byteCnt++; + + // Calculate the parity bit for the client... + Uart.parityBits <<= 1; + Uart.parityBits ^= OddByteParity[(Uart.dropPosition & 0xff)]; + + Uart.bitCnt = 0; + Uart.shiftReg = 0; + Uart.nOutOfCnt = 0; + Uart.dropPosition = 0; + } + } + + /*if(error) { + Uart.output[Uart.byteCnt] = 0xAA; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = error & 0xFF; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = 0xAA; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = (Uart.bitBuffer >> 8) & 0xFF; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = (Uart.syncBit >> 3) & 0xFF; + Uart.byteCnt++; + Uart.output[Uart.byteCnt] = 0xAA; + Uart.byteCnt++; + return TRUE; + }*/ + } + + } + else { + bit = Uart.bitBuffer & 0xf0; + bit >>= 4; + bit ^= 0x0F; // drops become 1s ;-) + if(bit) { + // should have been high or at least (4 * 128) / fc + // according to ISO this should be at least (9 * 128 + 20) / fc + if(Uart.highCnt == 8) { + // we went low, so this could be start of communication + // it turns out to be safer to choose a less significant + // syncbit... so we check whether the neighbour also represents the drop + Uart.posCnt = 1; // apparently we are busy with our first half bit period + Uart.syncBit = bit & 8; + Uart.samples = 3; + if(!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; } + else if(bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; } + if(!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; } + else if(bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; } + if(!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0; + if(Uart.syncBit && (Uart.bitBuffer & 8)) { + Uart.syncBit = 8; + + // the first half bit period is expected in next sample + Uart.posCnt = 0; + Uart.samples = 3; + } + } + else if(bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; } + + Uart.syncBit <<= 4; + Uart.state = STATE_START_OF_COMMUNICATION; + Uart.bitCnt = 0; + Uart.byteCnt = 0; + Uart.parityBits = 0; + Uart.nOutOfCnt = 0; + Uart.OutOfCnt = 4; // Start at 1/4, could switch to 1/256 + Uart.dropPosition = 0; + Uart.shiftReg = 0; + //error = 0; + } + else { + Uart.highCnt = 0; + } + } + else { + if(Uart.highCnt < 8) { + Uart.highCnt++; + } + } + } + + return FALSE; } +//============================================================================= +// Manchester +//============================================================================= + +static struct { + enum { + DEMOD_UNSYNCD, + DEMOD_START_OF_COMMUNICATION, + DEMOD_START_OF_COMMUNICATION2, + DEMOD_START_OF_COMMUNICATION3, + DEMOD_SOF_COMPLETE, + DEMOD_MANCHESTER_D, + DEMOD_MANCHESTER_E, + DEMOD_END_OF_COMMUNICATION, + DEMOD_END_OF_COMMUNICATION2, + DEMOD_MANCHESTER_F, + DEMOD_ERROR_WAIT + } state; + int bitCount; + int posCount; + int syncBit; + int parityBits; + uint16_t shiftReg; + int buffer; + int buffer2; + int buffer3; + int buff; + int samples; + int len; + enum { + SUB_NONE, + SUB_FIRST_HALF, + SUB_SECOND_HALF, + SUB_BOTH + } sub; + uint8_t *output; +} Demod; + +static RAMFUNC int ManchesterDecoding(int v) +{ + int bit; + int modulation; + int error = 0; + + bit = Demod.buffer; + Demod.buffer = Demod.buffer2; + Demod.buffer2 = Demod.buffer3; + Demod.buffer3 = v; + + if(Demod.buff < 3) { + Demod.buff++; + return FALSE; + } + + if(Demod.state==DEMOD_UNSYNCD) { + Demod.output[Demod.len] = 0xfa; + Demod.syncBit = 0; + //Demod.samples = 0; + Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part + + if(bit & 0x08) { + Demod.syncBit = 0x08; + } + + if(bit & 0x04) { + if(Demod.syncBit) { + bit <<= 4; + } + Demod.syncBit = 0x04; + } + + if(bit & 0x02) { + if(Demod.syncBit) { + bit <<= 2; + } + Demod.syncBit = 0x02; + } + + if(bit & 0x01 && Demod.syncBit) { + Demod.syncBit = 0x01; + } + + if(Demod.syncBit) { + Demod.len = 0; + Demod.state = DEMOD_START_OF_COMMUNICATION; + Demod.sub = SUB_FIRST_HALF; + Demod.bitCount = 0; + Demod.shiftReg = 0; + Demod.parityBits = 0; + Demod.samples = 0; + if(Demod.posCount) { + //if(trigger) LED_A_OFF(); // Not useful in this case... + switch(Demod.syncBit) { + case 0x08: Demod.samples = 3; break; + case 0x04: Demod.samples = 2; break; + case 0x02: Demod.samples = 1; break; + case 0x01: Demod.samples = 0; break; + } + // SOF must be long burst... otherwise stay unsynced!!! + if(!(Demod.buffer & Demod.syncBit) || !(Demod.buffer2 & Demod.syncBit)) { + Demod.state = DEMOD_UNSYNCD; + } + } + else { + // SOF must be long burst... otherwise stay unsynced!!! + if(!(Demod.buffer2 & Demod.syncBit) || !(Demod.buffer3 & Demod.syncBit)) { + Demod.state = DEMOD_UNSYNCD; + error = 0x88; + } + + } + error = 0; + + } + } + else { + modulation = bit & Demod.syncBit; + modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; + //modulation = ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; + + Demod.samples += 4; + + if(Demod.posCount==0) { + Demod.posCount = 1; + if(modulation) { + Demod.sub = SUB_FIRST_HALF; + } + else { + Demod.sub = SUB_NONE; + } + } + else { + Demod.posCount = 0; + /*(modulation && (Demod.sub == SUB_FIRST_HALF)) { + if(Demod.state!=DEMOD_ERROR_WAIT) { + Demod.state = DEMOD_ERROR_WAIT; + Demod.output[Demod.len] = 0xaa; + error = 0x01; + } + }*/ + //else if(modulation) { + if(modulation) { + if(Demod.sub == SUB_FIRST_HALF) { + Demod.sub = SUB_BOTH; + } + else { + Demod.sub = SUB_SECOND_HALF; + } + } + else if(Demod.sub == SUB_NONE) { + if(Demod.state == DEMOD_SOF_COMPLETE) { + Demod.output[Demod.len] = 0x0f; + Demod.len++; + Demod.parityBits <<= 1; + Demod.parityBits ^= OddByteParity[0x0f]; + Demod.state = DEMOD_UNSYNCD; +// error = 0x0f; + return TRUE; + } + else { + Demod.state = DEMOD_ERROR_WAIT; + error = 0x33; + } + /*if(Demod.state!=DEMOD_ERROR_WAIT) { + Demod.state = DEMOD_ERROR_WAIT; + Demod.output[Demod.len] = 0xaa; + error = 0x01; + }*/ + } + + switch(Demod.state) { + case DEMOD_START_OF_COMMUNICATION: + if(Demod.sub == SUB_BOTH) { + //Demod.state = DEMOD_MANCHESTER_D; + Demod.state = DEMOD_START_OF_COMMUNICATION2; + Demod.posCount = 1; + Demod.sub = SUB_NONE; + } + else { + Demod.output[Demod.len] = 0xab; + Demod.state = DEMOD_ERROR_WAIT; + error = 0xd2; + } + break; + case DEMOD_START_OF_COMMUNICATION2: + if(Demod.sub == SUB_SECOND_HALF) { + Demod.state = DEMOD_START_OF_COMMUNICATION3; + } + else { + Demod.output[Demod.len] = 0xab; + Demod.state = DEMOD_ERROR_WAIT; + error = 0xd3; + } + break; + case DEMOD_START_OF_COMMUNICATION3: + if(Demod.sub == SUB_SECOND_HALF) { +// Demod.state = DEMOD_MANCHESTER_D; + Demod.state = DEMOD_SOF_COMPLETE; + //Demod.output[Demod.len] = Demod.syncBit & 0xFF; + //Demod.len++; + } + else { + Demod.output[Demod.len] = 0xab; + Demod.state = DEMOD_ERROR_WAIT; + error = 0xd4; + } + break; + case DEMOD_SOF_COMPLETE: + case DEMOD_MANCHESTER_D: + case DEMOD_MANCHESTER_E: + // OPPOSITE FROM ISO14443 - 11110000 = 0 (1 in 14443) + // 00001111 = 1 (0 in 14443) + if(Demod.sub == SUB_SECOND_HALF) { // SUB_FIRST_HALF + Demod.bitCount++; + Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100; + Demod.state = DEMOD_MANCHESTER_D; + } + else if(Demod.sub == SUB_FIRST_HALF) { // SUB_SECOND_HALF + Demod.bitCount++; + Demod.shiftReg >>= 1; + Demod.state = DEMOD_MANCHESTER_E; + } + else if(Demod.sub == SUB_BOTH) { + Demod.state = DEMOD_MANCHESTER_F; + } + else { + Demod.state = DEMOD_ERROR_WAIT; + error = 0x55; + } + break; + + case DEMOD_MANCHESTER_F: + // Tag response does not need to be a complete byte! + if(Demod.len > 0 || Demod.bitCount > 0) { + if(Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF + Demod.shiftReg >>= (9 - Demod.bitCount); + Demod.output[Demod.len] = Demod.shiftReg & 0xff; + Demod.len++; + // No parity bit, so just shift a 0 + Demod.parityBits <<= 1; + } + + Demod.state = DEMOD_UNSYNCD; + return TRUE; + } + else { + Demod.output[Demod.len] = 0xad; + Demod.state = DEMOD_ERROR_WAIT; + error = 0x03; + } + break; + + case DEMOD_ERROR_WAIT: + Demod.state = DEMOD_UNSYNCD; + break; + + default: + Demod.output[Demod.len] = 0xdd; + Demod.state = DEMOD_UNSYNCD; + break; + } + + /*if(Demod.bitCount>=9) { + Demod.output[Demod.len] = Demod.shiftReg & 0xff; + Demod.len++; + + Demod.parityBits <<= 1; + Demod.parityBits ^= ((Demod.shiftReg >> 8) & 0x01); + + Demod.bitCount = 0; + Demod.shiftReg = 0; + }*/ + if(Demod.bitCount>=8) { + Demod.shiftReg >>= 1; + Demod.output[Demod.len] = (Demod.shiftReg & 0xff); + Demod.len++; + + // FOR ISO15639 PARITY NOT SEND OTA, JUST CALCULATE IT FOR THE CLIENT + Demod.parityBits <<= 1; + Demod.parityBits ^= OddByteParity[(Demod.shiftReg & 0xff)]; + + Demod.bitCount = 0; + Demod.shiftReg = 0; + } + + if(error) { + Demod.output[Demod.len] = 0xBB; + Demod.len++; + Demod.output[Demod.len] = error & 0xFF; + Demod.len++; + Demod.output[Demod.len] = 0xBB; + Demod.len++; + Demod.output[Demod.len] = bit & 0xFF; + Demod.len++; + Demod.output[Demod.len] = Demod.buffer & 0xFF; + Demod.len++; + // Look harder ;-) + Demod.output[Demod.len] = Demod.buffer2 & 0xFF; + Demod.len++; + Demod.output[Demod.len] = Demod.syncBit & 0xFF; + Demod.len++; + Demod.output[Demod.len] = 0xBB; + Demod.len++; + return TRUE; + } + + } + + } // end (state != UNSYNCED) + + return FALSE; +} + +//============================================================================= +// Finally, a `sniffer' for iClass communication +// Both sides of communication! +//============================================================================= + +//----------------------------------------------------------------------------- +// Record the sequence of commands sent by the reader to the tag, with +// triggering so that we start recording at the point that the tag is moved +// near the reader. +//----------------------------------------------------------------------------- +void RAMFUNC SnoopIClass(void) +{ +// DEFINED ABOVE +// #define RECV_CMD_OFFSET 3032 +// #define RECV_RES_OFFSET 3096 +// #define DMA_BUFFER_OFFSET 3160 +// #define DMA_BUFFER_SIZE 4096 +// #define TRACE_SIZE 3000 + + // We won't start recording the frames that we acquire until we trigger; + // a good trigger condition to get started is probably when we see a + // response from the tag. + //int triggered = FALSE; // FALSE to wait first for card + + // The command (reader -> tag) that we're receiving. + // The length of a received command will in most cases be no more than 18 bytes. + // So 32 should be enough! + uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + // The response (tag -> reader) that we're receiving. + uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); + + // As we receive stuff, we copy it from receivedCmd or receivedResponse + // into trace, along with its length and other annotations. + //uint8_t *trace = (uint8_t *)BigBuf; + + // reset traceLen to 0 + iso14a_set_tracing(TRUE); + iso14a_clear_trace(); + iso14a_set_trigger(FALSE); + + // The DMA buffer, used to stream samples from the FPGA + int8_t *dmaBuf = ((int8_t *)BigBuf) + DMA_BUFFER_OFFSET; + int lastRxCounter; + int8_t *upTo; + int smpl; + int maxBehindBy = 0; + + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; + rsamples = 0; + + memset(trace, 0x44, RECV_CMD_OFFSET); + + // Set up the demodulator for tag -> reader responses. + Demod.output = receivedResponse; + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; + + // Setup for the DMA. + FpgaSetupSsc(); + upTo = dmaBuf; + lastRxCounter = DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); + + // And the reader -> tag commands + memset(&Uart, 0, sizeof(Uart)); + Uart.output = receivedCmd; + Uart.byteCntMax = 32; // was 100 (greg)//////////////////////////////////////////////////////////////////////// + Uart.state = STATE_UNSYNCD; + + // And put the FPGA in the appropriate mode + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + int div = 0; + //int div2 = 0; + int decbyte = 0; + int decbyter = 0; + + // And now we loop, receiving samples. + for(;;) { + LED_A_ON(); + WDT_HIT(); + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & + (DMA_BUFFER_SIZE-1); + if(behindBy > maxBehindBy) { + maxBehindBy = behindBy; + if(behindBy > 400) { + Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); + goto done; + } + } + if(behindBy < 1) continue; + + LED_A_OFF(); + smpl = upTo[0]; + upTo++; + lastRxCounter -= 1; + if(upTo - dmaBuf > DMA_BUFFER_SIZE) { + upTo -= DMA_BUFFER_SIZE; + lastRxCounter += DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } + + //samples += 4; + samples += 1; + //div2++; + + //if(div2 > 3) { + //div2 = 0; + //decbyte ^= ((smpl & 0x01) << (3 - div)); + //decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1)) << (3 - div)); // better already... + //decbyte ^= (((smpl & 0x01) | ((smpl & 0x02) >> 1) | ((smpl & 0x04) >> 2)) << (3 - div)); // even better... + if(smpl & 0xF) { + decbyte ^= (1 << (3 - div)); + } + //decbyte ^= (MajorityNibble[(smpl & 0x0F)] << (3 - div)); + + // FOR READER SIDE COMMUMICATION... + //decbyte ^= ((smpl & 0x10) << (3 - div)); + decbyter <<= 2; + decbyter ^= (smpl & 0x30); + + div++; + + if((div + 1) % 2 == 0) { + smpl = decbyter; + if(OutOfNDecoding((smpl & 0xF0) >> 4)) { + rsamples = samples - Uart.samples; + LED_C_ON(); + //if(triggered) { + trace[traceLen++] = ((rsamples >> 0) & 0xff); + trace[traceLen++] = ((rsamples >> 8) & 0xff); + trace[traceLen++] = ((rsamples >> 16) & 0xff); + trace[traceLen++] = ((rsamples >> 24) & 0xff); + trace[traceLen++] = ((Uart.parityBits >> 0) & 0xff); + trace[traceLen++] = ((Uart.parityBits >> 8) & 0xff); + trace[traceLen++] = ((Uart.parityBits >> 16) & 0xff); + trace[traceLen++] = ((Uart.parityBits >> 24) & 0xff); + trace[traceLen++] = Uart.byteCnt; + memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); + traceLen += Uart.byteCnt; + if(traceLen > TRACE_SIZE) break; + //} + /* And ready to receive another command. */ + Uart.state = STATE_UNSYNCD; + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + Demod.state = DEMOD_UNSYNCD; + LED_B_OFF(); + Uart.byteCnt = 0; + } + decbyter = 0; + } + + if(div > 3) { + smpl = decbyte; + if(ManchesterDecoding(smpl & 0x0F)) { + rsamples = samples - Demod.samples; + LED_B_ON(); + + // timestamp, as a count of samples + trace[traceLen++] = ((rsamples >> 0) & 0xff); + trace[traceLen++] = ((rsamples >> 8) & 0xff); + trace[traceLen++] = ((rsamples >> 16) & 0xff); + trace[traceLen++] = 0x80 | ((rsamples >> 24) & 0xff); + trace[traceLen++] = ((Demod.parityBits >> 0) & 0xff); + trace[traceLen++] = ((Demod.parityBits >> 8) & 0xff); + trace[traceLen++] = ((Demod.parityBits >> 16) & 0xff); + trace[traceLen++] = ((Demod.parityBits >> 24) & 0xff); + // length + trace[traceLen++] = Demod.len; + memcpy(trace+traceLen, receivedResponse, Demod.len); + traceLen += Demod.len; + if(traceLen > TRACE_SIZE) break; + + //triggered = TRUE; + + // And ready to receive another response. + memset(&Demod, 0, sizeof(Demod)); + Demod.output = receivedResponse; + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + + div = 0; + decbyte = 0x00; + } + //} + + if(BUTTON_PRESS()) { + DbpString("cancelled_a"); + goto done; + } + } + + DbpString("COMMAND FINISHED"); + + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]); + +done: + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + Dbprintf("%x %x %x", Uart.byteCntMax, traceLen, (int)Uart.output[0]); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); +} void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { - int i; - for (i = 0; i < 8; i++) { + int i; + for(i = 0; i < 8; i++) { rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i+1)%8] << 5); } } +//----------------------------------------------------------------------------- +// Wait for commands from reader +// Stop when button is pressed +// Or return TRUE when command is captured +//----------------------------------------------------------------------------- +static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) +{ + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + + // Now run a `software UART' on the stream of incoming samples. + Uart.output = received; + Uart.byteCntMax = maxLen; + Uart.state = STATE_UNSYNCD; + + for(;;) { + WDT_HIT(); + + if(BUTTON_PRESS()) return FALSE; + + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + /*if(OutOfNDecoding((b & 0xf0) >> 4)) { + *len = Uart.byteCnt; + return TRUE; + }*/ + if(OutOfNDecoding(b & 0x0f)) { + *len = Uart.byteCnt; + return TRUE; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Prepare tag messages +//----------------------------------------------------------------------------- +static void CodeIClassTagAnswer(const uint8_t *cmd, int len) +{ + int i; -// Encode SOF only -static void CodeIClassTagSOF() { ToSendReset(); - ToSend[++ToSendMax] = 0x1D; - ToSendMax++; -} + // Send SOF + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; -static void AppendCrc(uint8_t *data, int len) { - ComputeCrc14443(CRC_ICLASS, data, len, data+len, data+len+1); -} + for(i = 0; i < len; i++) { + int j; + uint8_t b = cmd[i]; - -/** - * @brief Does the actual simulation - */ -int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { - - // free eventually allocated BigBuf memory - BigBuf_free_keep_EM(); - - uint16_t page_size = 32 * 8; - uint8_t current_page = 0; - - // maintain cipher states for both credit and debit key for each page - State cipher_state_KC[8]; - State cipher_state_KD[8]; - State *cipher_state = &cipher_state_KD[0]; - - uint8_t *emulator = BigBuf_get_EM_addr(); - uint8_t *csn = emulator; - - // CSN followed by two CRC bytes - uint8_t anticoll_data[10]; - uint8_t csn_data[10]; - memcpy(csn_data, csn, sizeof(csn_data)); - Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]); - - // Construct anticollision-CSN - rotateCSN(csn_data, anticoll_data); - - // Compute CRC on both CSNs - AppendCrc(anticoll_data, 8); - AppendCrc(csn_data, 8); - - uint8_t diversified_key_d[8] = { 0x00 }; - uint8_t diversified_key_c[8] = { 0x00 }; - uint8_t *diversified_key = diversified_key_d; - - // configuration block - uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; - - // e-Purse - uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - if (simulationMode == ICLASS_SIM_MODE_FULL) { - // initialize from page 0 - memcpy(conf_block, emulator + 8 * 1, 8); - memcpy(card_challenge_data, emulator + 8 * 2, 8); // e-purse - memcpy(diversified_key_d, emulator + 8 * 3, 8); // Kd - memcpy(diversified_key_c, emulator + 8 * 4, 8); // Kc - } - - AppendCrc(conf_block, 8); - - // save card challenge for sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - - if (conf_block[5] & 0x80) { - page_size = 256 * 8; - } - - // From PicoPass DS: - // When the page is in personalization mode this bit is equal to 1. - // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0: - // the page is then "in application mode". - bool personalization_mode = conf_block[7] & 0x80; - - // chip memory may be divided in 8 pages - uint8_t max_page = conf_block[4] & 0x10 ? 0 : 7; - - // Precalculate the cipher states, feeding it the CC - cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); - cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); - if (simulationMode == ICLASS_SIM_MODE_FULL) { - for (int i = 1; i < max_page; i++) { - uint8_t *epurse = emulator + i*page_size + 8*2; - uint8_t *Kd = emulator + i*page_size + 8*3; - uint8_t *Kc = emulator + i*page_size + 8*4; - cipher_state_KD[i] = opt_doTagMAC_1(epurse, Kd); - cipher_state_KC[i] = opt_doTagMAC_1(epurse, Kc); + // Data bits + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; + } else { + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x00; + } + b >>= 1; } } - int exitLoop = 0; + // Send EOF + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + + // Convert from last byte pos to length + ToSendMax++; +} + +// Only SOF +static void CodeIClassTagSOF() +{ + ToSendReset(); + + // Send SOF + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0xff; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xff; + + // Convert from last byte pos to length + ToSendMax++; +} + +//----------------------------------------------------------------------------- +// Simulate iClass Card +// Only CSN (Card Serial Number) +// +//----------------------------------------------------------------------------- +void SimulateIClass(uint8_t arg0, uint8_t *datain) +{ + uint8_t simType = arg0; + + // Enable and clear the trace + tracing = TRUE; + traceLen = 0; + memset(trace, 0x44, TRACE_SIZE); + + // CSN followed by two CRC bytes + uint8_t response2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t response3[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; + + // e-Purse + uint8_t response4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if(simType == 0) { + // Use the CSN from commandline + memcpy(response3, datain, 8); + } + + // Construct anticollision-CSN + rotateCSN(response3,response2); + + // Compute CRC on both CSNs + ComputeCrc14443(CRC_ICLASS, response2, 8, &response2[8], &response2[9]); + ComputeCrc14443(CRC_ICLASS, response3, 8, &response3[8], &response3[9]); + // Reader 0a // Tag 0f // Reader 0c @@ -172,757 +1026,454 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Reader 81 anticoll. CSN // Tag CSN - uint8_t *modulated_response; - int modulated_response_size = 0; - uint8_t *trace_data = NULL; - int trace_data_size = 0; + uint8_t *resp; + int respLen; + uint8_t* respdata = NULL; + int respsize = 0; + uint8_t sof = 0x0f; - // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(1); - int resp_sof_Len; + // Respond SOF -- takes 8 bytes + uint8_t *resp1 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); + int resp1Len; // Anticollision CSN (rotated CSN) - // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_malloc(22); - int resp_anticoll_len; + // 176: Takes 16 bytes for SOF/EOF and 10 * 16 = 160 bytes (2 bytes/bit) + uint8_t *resp2 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 10); + int resp2Len; - // CSN (block 0) - // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(22); - int resp_csn_len; + // CSN + // 176: Takes 16 bytes for SOF/EOF and 10 * 16 = 160 bytes (2 bytes/bit) + uint8_t *resp3 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 190); + int resp3Len; - // configuration (block 1) picopass 2ks - uint8_t *resp_conf = BigBuf_malloc(22); - int resp_conf_len; + // e-Purse + // 144: Takes 16 bytes for SOF/EOF and 8 * 16 = 128 bytes (2 bytes/bit) + uint8_t *resp4 = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET + 370); + int resp4Len; - // e-Purse (block 2) - // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_malloc(18); - int resp_cc_len; - - // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only - uint8_t *resp_ff = BigBuf_malloc(22); - int resp_ff_len; - uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; - AppendCrc(ff_data, 8); - - // Application Issuer Area (block 5) - uint8_t *resp_aia = BigBuf_malloc(22); - int resp_aia_len; - uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; - AppendCrc(aia_data, 8); - - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + // + 1720.. + uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + memset(receivedCmd, 0x44, RECV_CMD_SIZE); int len; // Prepare card messages + ToSendMax = 0; - // First card answer: SOF only + // First card answer: SOF CodeIClassTagSOF(); - memcpy(resp_sof, ToSend, ToSendMax); - resp_sof_Len = ToSendMax; + memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax; // Anticollision CSN - CodeIso15693AsTag(anticoll_data, sizeof(anticoll_data)); - memcpy(resp_anticoll, ToSend, ToSendMax); - resp_anticoll_len = ToSendMax; + CodeIClassTagAnswer(response2, sizeof(response2)); + memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax; - // CSN (block 0) - CodeIso15693AsTag(csn_data, sizeof(csn_data)); - memcpy(resp_csn, ToSend, ToSendMax); - resp_csn_len = ToSendMax; + // CSN + CodeIClassTagAnswer(response3, sizeof(response3)); + memcpy(resp3, ToSend, ToSendMax); resp3Len = ToSendMax; - // Configuration (block 1) - CodeIso15693AsTag(conf_block, sizeof(conf_block)); - memcpy(resp_conf, ToSend, ToSendMax); - resp_conf_len = ToSendMax; + // e-Purse + CodeIClassTagAnswer(response4, sizeof(response4)); + memcpy(resp4, ToSend, ToSendMax); resp4Len = ToSendMax; - // e-Purse (block 2) - CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); - resp_cc_len = ToSendMax; + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); - // Kd, Kc (blocks 3 and 4) - CodeIso15693AsTag(ff_data, sizeof(ff_data)); - memcpy(resp_ff, ToSend, ToSendMax); - resp_ff_len = ToSendMax; + // To control where we are in the protocol + int cmdsRecvd = 0; - // Application Issuer Area (block 5) - CodeIso15693AsTag(aia_data, sizeof(aia_data)); - memcpy(resp_aia, ToSend, ToSendMax); - resp_aia_len = ToSendMax; - - //This is used for responding to READ-block commands or other data which is dynamically generated - uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer - uint8_t *data_response = BigBuf_malloc( (32 + 2) * 2 + 2); - - bool buttonPressed = false; - enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; - - while (!exitLoop) { - WDT_HIT(); - - uint32_t reader_eof_time = 0; - len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); - if (len < 0) { - buttonPressed = true; + LED_A_ON(); + for(;;) { + LED_B_OFF(); + if(!GetIClassCommandFromReader(receivedCmd, &len, 100)) { + DbpString("button press"); break; } - // Now look at the reader command and provide appropriate responses - // default is no response: - modulated_response = NULL; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; - - if (receivedCmd[0] == ICLASS_CMD_ACTALL && len == 1) { - // Reader in anticollision phase - if (chip_state != HALTED) { - modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; - chip_state = ACTIVATED; - } - - } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // identify - // Reader asks for anticollision CSN - if (chip_state == SELECTED || chip_state == ACTIVATED) { - modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); - } - - } else if (receivedCmd[0] == ICLASS_CMD_SELECT && len == 9) { - // Reader selects anticollision CSN. + // Okay, look at the command now. + if(receivedCmd[0] == 0x0a) { + // Reader in anticollission phase + resp = resp1; respLen = resp1Len; //order = 1; + respdata = &sof; + respsize = sizeof(sof); + //resp = resp2; respLen = resp2Len; order = 2; + //DbpString("Hello request from reader:"); + } else if(receivedCmd[0] == 0x0c) { + // Reader asks for anticollission CSN + resp = resp2; respLen = resp2Len; //order = 2; + respdata = response2; + respsize = sizeof(response2); + //DbpString("Reader requests anticollission CSN:"); + } else if(receivedCmd[0] == 0x81) { + // Reader selects anticollission CSN. // Tag sends the corresponding real CSN - if (chip_state == ACTIVATED || chip_state == SELECTED) { - if (!memcmp(receivedCmd+1, anticoll_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } else { - chip_state = IDLE; - } - } else if (chip_state == HALTED) { - // RESELECT with CSN - if (!memcmp(receivedCmd+1, csn_data, 8)) { - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - chip_state = SELECTED; - } - } - - } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block - uint16_t blockNo = receivedCmd[1]; - if (chip_state == SELECTED) { - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - // provide defaults for blocks 0 ... 5 - switch (blockNo) { - case 0: // csn (block 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - break; - case 1: // configuration (block 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_block; - trace_data_size = sizeof(conf_block); - break; - case 2: // e-purse (block 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - break; - case 3: - case 4: // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - break; - case 5: // Application Issuer Area (block 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - break; - // default: don't respond - } - } else if (simulationMode == ICLASS_SIM_MODE_FULL) { - if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + current_page*page_size + 8*blockNo, 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } - } - } - - } else if ((receivedCmd[0] == ICLASS_CMD_READCHECK_KD - || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && receivedCmd[1] == 0x02 && len == 2) { - // Read e-purse (88 02 || 18 02) - if (chip_state == SELECTED) { - if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD){ - cipher_state = &cipher_state_KD[current_page]; - diversified_key = diversified_key_d; - } else { - cipher_state = &cipher_state_KC[current_page]; - diversified_key = diversified_key_c; - } - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - } - - } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC - || receivedCmd[0] == ICLASS_CMD_CHECK_KD) && len == 9) { + resp = resp3; respLen = resp3Len; //order = 3; + respdata = response3; + respsize = sizeof(response3); + //DbpString("Reader selects anticollission CSN:"); + } else if(receivedCmd[0] == 0x88) { + // Read e-purse (88 02) + resp = resp4; respLen = resp4Len; //order = 4; + respdata = response4; + respsize = sizeof(response4); + LED_B_ON(); + } else if(receivedCmd[0] == 0x05) { // Reader random and reader MAC!!! - if (chip_state == SELECTED) { - if (simulationMode == ICLASS_SIM_MODE_FULL) { - //NR, from reader, is in receivedCmd+1 - opt_doTagMAC_2(*cipher_state, receivedCmd+1, data_generic_trace, diversified_key); - trace_data = data_generic_trace; - trace_data_size = 4; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - //exitLoop = true; - } else { // Not fullsim, we don't respond - // We do not know what to answer, so lets keep quiet - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - if (reader_mac_buf != NULL) { - // save NR and MAC for sim 2,4 - memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); - } - exitLoop = true; - } - } - } + // Lets store this ;-) +/* + Dbprintf(" CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + response3[0], response3[1], response3[2], + response3[3], response3[4], response3[5], + response3[6], response3[7]); +*/ + Dbprintf("READER AUTH (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x", + len, + receivedCmd[0], receivedCmd[1], receivedCmd[2], + receivedCmd[3], receivedCmd[4], receivedCmd[5], + receivedCmd[6], receivedCmd[7], receivedCmd[8]); - } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { - if (chip_state == SELECTED) { - // Reader ends the session - modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; - chip_state = HALTED; - } - - } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 - //Read 4 blocks - if (chip_state == SELECTED) { - uint8_t blockNo = receivedCmd[1]; - memcpy(data_generic_trace, emulator + current_page*page_size + blockNo*8, 8 * 4); - AppendCrc(data_generic_trace, 8 * 4); - trace_data = data_generic_trace; - trace_data_size = 8 * 4 + 2; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } - - } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { - // We're expected to respond with the data+crc, exactly what's already in the receivedCmd - // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - if (chip_state == SELECTED) { - uint8_t blockNo = receivedCmd[1]; - if (blockNo == 2) { // update e-purse - memcpy(card_challenge_data, receivedCmd+2, 8); - CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); - resp_cc_len = ToSendMax; - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); - if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + current_page*page_size + 8*2, card_challenge_data, 8); - } - } else if (blockNo == 3) { // update Kd - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_key_d[i] = receivedCmd[2 + i]; - } else { - diversified_key_d[i] ^= receivedCmd[2 + i]; - } - } - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); - if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + current_page*page_size + 8*3, diversified_key_d, 8); - } - } else if (blockNo == 4) { // update Kc - for (int i = 0; i < 8; i++) { - if (personalization_mode) { - diversified_key_c[i] = receivedCmd[2 + i]; - } else { - diversified_key_c[i] ^= receivedCmd[2 + i]; - } - } - cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); - if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + current_page*page_size + 8*4, diversified_key_c, 8); - } - } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update any other data block - memcpy(emulator + current_page*page_size + 8*blockNo, receivedCmd+2, 8); - } - memcpy(data_generic_trace, receivedCmd + 2, 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } - - } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { - // Pagesel - // Chips with a single page will not answer to this command - // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC - if (chip_state == SELECTED) { - if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { - current_page = receivedCmd[1]; - memcpy(data_generic_trace, emulator + current_page*page_size + 8*1, 8); - memcpy(diversified_key_d, emulator + current_page*page_size + 8*3, 8); - memcpy(diversified_key_c, emulator + current_page*page_size + 8*4, 8); - cipher_state = &cipher_state_KD[current_page]; - personalization_mode = data_generic_trace[7] & 0x80; - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } - } - - } else if (receivedCmd[0] == 0x26 && len == 5) { - // standard ISO15693 INVENTORY command. Ignore. - - } else { - // don't know how to handle this command - char debug_message[250]; // should be enough - sprintf(debug_message, "Unhandled command (len = %d) received from reader:", len); - for (int i = 0; i < len && strlen(debug_message) < sizeof(debug_message) - 3 - 1; i++) { - sprintf(debug_message + strlen(debug_message), " %02x", receivedCmd[i]); - } - Dbprintf("%s", debug_message); // Do not respond + // We do not know what to answer, so lets keep quit + resp = resp1; respLen = 0; //order = 5; + respdata = NULL; + respsize = 0; + } else if(receivedCmd[0] == 0x00 && len == 1) { + // Reader ends the session + resp = resp1; respLen = 0; //order = 0; + respdata = NULL; + respsize = 0; + } else { + // Never seen this command before + Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x", + len, + receivedCmd[0], receivedCmd[1], receivedCmd[2], + receivedCmd[3], receivedCmd[4], receivedCmd[5], + receivedCmd[6], receivedCmd[7], receivedCmd[8]); + // Do not respond + resp = resp1; respLen = 0; //order = 0; + respdata = NULL; + respsize = 0; } - /** - A legit tag has about 273,4us delay between reader EOT and tag SOF. - **/ - if (modulated_response_size > 0) { - uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; - TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace_ISO15693(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size*32*64, NULL, false); + if(cmdsRecvd > 999) { + DbpString("1000 commands later..."); + break; + } + else { + cmdsRecvd++; } - } - - if (buttonPressed) - { - DbpString("Button pressed"); - } - return buttonPressed; -} - -/** - * @brief SimulateIClass simulates an iClass card. - * @param arg0 type of simulation - * - 0 uses the first 8 bytes in usb data as CSN - * - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified - * in the usb data. This mode collects MAC from the reader, in order to do an offline - * attack on the keys. For more info, see "dismantling iclass" and proxclone.com. - * - Other : Uses the default CSN (031fec8af7ff12e0) - * @param arg1 - number of CSN's contained in datain (applicable for mode 2 only) - * @param arg2 - * @param datain - */ -void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - - LED_A_ON(); - - Iso15693InitTag(); - - uint32_t simType = arg0; - uint32_t numberOfCSNS = arg1; - - // Enable and clear the trace - set_tracing(true); - clear_trace(); - //Use the emulator memory for SIM - uint8_t *emulator = BigBuf_get_EM_addr(); - - if (simType == ICLASS_SIM_MODE_CSN) { - // Use the CSN from commandline - memcpy(emulator, datain, 8); - doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); - } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) { - //Default CSN - uint8_t csn[] = {0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0}; - memcpy(emulator, csn, 8); - doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); - } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { - uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; - Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); - // In this mode, a number of csns are within datain. We'll simulate each one, one at a time - // in order to collect MAC's from the reader. This can later be used in an offline-attack - // in order to obtain the keys, as in the "dismantling iclass"-paper. - int i; - for (i = 0; i < numberOfCSNS && i*16+16 <= USB_CMD_DATA_SIZE; i++) { - // The usb data is 512 bytes, fitting 32 responses (8 byte CC + 4 Byte NR + 4 Byte MAC = 16 Byte response). - memcpy(emulator, datain+(i*8), 8); - if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses+i*16)) { - // Button pressed - break; + if(respLen > 0) { + SendIClassAnswer(resp, respLen, 21); + } + + if (tracing) { + LogTrace(receivedCmd,len, rsamples, Uart.parityBits, TRUE); + if (respdata != NULL) { + LogTrace(respdata,respsize, rsamples, SwapBits(GetParity(respdata,respsize),respsize), FALSE); + } + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); + break; } - Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x", - datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], - datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); - Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", - mac_responses[i*16+ 8], mac_responses[i*16+ 9], mac_responses[i*16+10], mac_responses[i*16+11], - mac_responses[i*16+12], mac_responses[i*16+13], mac_responses[i*16+14], mac_responses[i*16+15]); - SpinDelay(100); // give the reader some time to prepare for next CSN } - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); - } else if (simType == ICLASS_SIM_MODE_FULL) { - //This is 'full sim' mode, where we use the emulator storage for data. - doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL); - } else { - // We may want a mode here where we hardcode the csns to use (from proxclone). - // That will speed things up a little, but not required just yet. - Dbprintf("The mode is not implemented, reserved for future use"); + + memset(receivedCmd, 0x44, RECV_CMD_SIZE); } - Dbprintf("Done..."); - + Dbprintf("%x", cmdsRecvd); LED_A_OFF(); + LED_B_OFF(); } +static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) +{ + int i = 0, u = 0, d = 0; + uint8_t b = 0; + // return 0; + // Modulate Manchester + // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD424); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(); + + // send cycle + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + if(d < delay) { + b = 0x00; + d++; + } + else if(i >= respLen) { + b = 0x00; + u++; + } else { + b = resp[i]; + u++; + if(u > 1) { i++; u = 0; } + } + AT91C_BASE_SSC->SSC_THR = b; + + if(u > 4) break; + } + if(BUTTON_PRESS()) { + break; + } + } + + return 0; +} /// THE READER CODE -static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { +//----------------------------------------------------------------------------- +// Transmit the command (to the tag) that was placed in ToSend[]. +//----------------------------------------------------------------------------- +static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) +{ + int c; - CodeIso15693AsReader(frame, len); - TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint32_t end_time = *start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF - LogTrace_ISO15693(frame, len, *start_time*4, end_time*4, NULL, true); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(); + + if (wait) + if(*wait < 10) + *wait = 10; + + for(c = 0; c < *wait;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! + c++; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + uint8_t sendbyte; + bool firstpart = TRUE; + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + + // DOUBLE THE SAMPLES! + if(firstpart) { + sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); + } + else { + sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); + c++; + } + if(sendbyte == 0xff) { + sendbyte = 0xfe; + } + AT91C_BASE_SSC->SSC_THR = sendbyte; + firstpart = !firstpart; + + if(c >= len) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + if (samples) *samples = (c + *wait) << 3; } -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, - uint8_t expected_size, uint8_t tries, uint32_t start_time, uint32_t timeout, uint32_t *eof_time) { - while (tries-- > 0) { - ReaderTransmitIClass(command, cmdsize, &start_time); - if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, timeout, eof_time)) { - return true; - } +//----------------------------------------------------------------------------- +// Prepare iClass reader command to send to FPGA +//----------------------------------------------------------------------------- +void CodeIClassCommand(const uint8_t * cmd, int len) +{ + int i, j, k; + uint8_t b; + + ToSendReset(); + + // Start of Communication: 1 out of 4 + ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x0f; + ToSend[++ToSendMax] = 0x00; + + // Modulate the bytes + for (i = 0; i < len; i++) { + b = cmd[i]; + for(j = 0; j < 4; j++) { + for(k = 0; k < 4; k++) { + if(k == (b & 3)) { + ToSend[++ToSendMax] = 0x0f; } - return false;//Error + else { + ToSend[++ToSendMax] = 0x00; + } + } + b >>= 2; + } + } + + // End of Communication + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x00; + + // Convert from last character reference to length + ToSendMax++; } +void ReaderTransmitIClass(uint8_t* frame, int len) +{ + int wait = 0; + int samples = 0; + int par = 0; -/** - * @brief Selects an iclass tag - * @param card_data where the CSN is stored for return - * @return false = fail - * true = success - */ -static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { - uint8_t act_all[] = { 0x0a }; - uint8_t identify[] = { 0x0c }; - uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // This is tied to other size changes + // uint8_t* frame_addr = ((uint8_t*)BigBuf) + 2024; + CodeIClassCommand(frame,len); - uint8_t resp[ICLASS_BUFFER_SIZE]; + // Select the card + TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait); + if(trigger) + LED_A_ON(); - uint32_t start_time = GetCountSspClk(); - - // Send act_all - ReaderTransmitIClass(act_all, 1, &start_time); - // Card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false; //Fail - - //Send Identify - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(identify, 1, &start_time); - //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return false; //Fail - - //Copy the Anti-collision CSN to our select-packet - memcpy(&select[1], resp, 8); - //Select the card - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(select, sizeof(select), &start_time); - //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC - len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return false; //Fail - - //Success - we got CSN - //Save CSN in response data - memcpy(card_data, resp, 8); - - return true; + // Store reader command in buffer + if (tracing) LogTrace(frame,len,rsamples,par,TRUE); } +//----------------------------------------------------------------------------- +// Wait a certain time for tag response +// If a response is captured return TRUE +// If it takes too long return FALSE +//----------------------------------------------------------------------------- +static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) //uint8_t *buffer +{ + // buffer needs to be 512 bytes + int c; -// Select an iClass tag and read all blocks which are always readable without authentication -void ReaderIClass(uint8_t flags) { + // Set FPGA mode to "reader listen mode", no modulation (listen + // only, since we are receiving, not transmitting). + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - LED_A_ON(); + // Now get the answer from the card + Demod.output = receivedResponse; + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; - uint8_t card_data[6 * 8] = {0}; - memset(card_data, 0xFF, sizeof(card_data)); - uint8_t resp[ICLASS_BUFFER_SIZE]; - //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; - //Read e-purse block CRC(0x02) => 0x61 0x10 - uint8_t readEpurse[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x02, 0x61, 0x10}; - //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t b; + if (elapsed) *elapsed = 0; - uint8_t result_status = 0; + bool skip = FALSE; - if (flags & FLAG_ICLASS_READER_INIT) { - Iso15693InitReader(); - } + c = 0; + for(;;) { + WDT_HIT(); - if (flags & FLAG_ICLASS_READER_CLEARTRACE) { - set_tracing(true); - clear_trace(); - StartCountSspClk(); - } + if(BUTTON_PRESS()) return FALSE; - uint32_t start_time = 0; - uint32_t eof_time = 0; - - if (selectIclassTag(resp, &eof_time)) { - result_status = FLAG_ICLASS_READER_CSN; - memcpy(card_data, resp, 8); - - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - - //Read block 1, config - if (flags & FLAG_ICLASS_READER_CONF) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - Dbprintf("Failed to read config block"); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!! + if (elapsed) (*elapsed)++; } - - //Read block 2, e-purse - if (flags & FLAG_ICLASS_READER_CC) { - if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CC; - memcpy(card_data + (8*2), resp, 8); - } else { - Dbprintf("Failed to read e-purse"); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } - - //Read block 5, AA - if (flags & FLAG_ICLASS_READER_AA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data + (8*5), resp, 8); - } else { - Dbprintf("Failed to read AA block"); + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + if(c < timeout) { c++; } else { return FALSE; } + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + skip = !skip; + if(skip) continue; + /*if(ManchesterDecoding((b>>4) & 0xf)) { + *samples = ((c - 1) << 3) + 4; + return TRUE; + }*/ + if(ManchesterDecoding(b & 0x0f)) { + *samples = c << 3; + return TRUE; } } } - - cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - - LED_A_OFF(); } - -void iClass_Check(uint8_t *NRMAC) { - uint8_t check[9] = {ICLASS_CMD_CHECK_KD, 0x00}; - uint8_t resp[4]; - memcpy(check+1, NRMAC, 8); - uint32_t eof_time; - bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); +int ReaderReceiveIClass(uint8_t* receivedAnswer) +{ + int samples = 0; + if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return FALSE; + rsamples += samples; + if (tracing) LogTrace(receivedAnswer,Demod.len,rsamples,Demod.parityBits,FALSE); + if(samples == 0) return FALSE; + return Demod.len; } +// Reader iClass Anticollission +void ReaderIClass(uint8_t arg0) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -void iClass_Readcheck(uint8_t block, bool use_credit_key) { - uint8_t readcheck[2] = {ICLASS_CMD_READCHECK_KD, block}; - if (use_credit_key) { - readcheck[0] = ICLASS_CMD_READCHECK_KC; - } - uint8_t resp[8]; - uint32_t eof_time; - bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 3, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); -} + uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + // Reset trace buffer + memset(trace, 0x44, RECV_CMD_OFFSET); + traceLen = 0; -static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { - uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? - uint8_t bl = blockNo; - uint16_t rdCrc = iclass_crc16(&bl, 1); - readcmd[2] = rdCrc >> 8; - readcmd[3] = rdCrc & 0xff; - uint8_t resp[10]; - uint32_t eof_time; - - bool isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - memcpy(readdata, resp, sizeof(resp)); - - return isOK; -} - - -void iClass_ReadBlk(uint8_t blockno) { - - LED_A_ON(); - - uint8_t readblockdata[10]; - bool isOK = iClass_ReadBlock(blockno, readblockdata); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // Setup SSC + FpgaSetupSsc(); + // Start from off (no field generated) + // Signal field is off with the appropriate LED LED_D_OFF(); - cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - LED_A_OFF(); -} + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - -void iClass_Dump(uint8_t startblock, uint8_t numblks) { + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); LED_A_ON(); - uint8_t readblockdata[USB_CMD_DATA_SIZE+2] = {0}; - bool isOK = false; - uint16_t blkCnt = 0; - - if (numblks > USB_CMD_DATA_SIZE / 8) { - numblks = USB_CMD_DATA_SIZE / 8; - } - - for (blkCnt = 0; blkCnt < numblks; blkCnt++) { - isOK = iClass_ReadBlock(startblock+blkCnt, readblockdata+8*blkCnt); - if (!isOK) { - Dbprintf("Block %02X failed to read", startblock+blkCnt); + for(;;) { + + if(traceLen > TRACE_SIZE) { + DbpString("Trace full"); break; } - } + + if (BUTTON_PRESS()) break; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + // Send act_all + ReaderTransmitIClass(act_all, 1); + // Card present? + if(ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(identify, 1); + if(ReaderReceiveIClass(resp) == 10) { + // Select card + memcpy(&select[1],resp,8); + ReaderTransmitIClass(select, sizeof(select)); - cmd_send(CMD_ACK, isOK, blkCnt, 0, readblockdata, blkCnt*8); - - LED_A_OFF(); -} - - -static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { - - uint8_t write[16] = {ICLASS_CMD_UPDATE, blockNo}; - memcpy(write+2, data, 12); // data + mac - AppendCrc(write+1, 13); - uint8_t resp[10]; - bool isOK = false; - uint32_t eof_time = 0; - - isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 3, 0, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); - if (!isOK) { - return false; + if(ReaderReceiveIClass(resp) == 10) { + Dbprintf(" Selected CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + resp[0], resp[1], resp[2], + resp[3], resp[4], resp[5], + resp[6], resp[7]); + } + // Card selected, whats next... ;-) + } + } + WDT_HIT(); } - uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - if (blockNo == 2) { - if (memcmp(data+4, resp, 4) || memcmp(data, resp+4, 4)) { // check response. e-purse update swaps first and second half - return false; - } - } else if (blockNo == 3 || blockNo == 4) { - if (memcmp(all_ff, resp, 8)) { // check response. Key updates always return 0xffffffffffffffff - return false; - } - } else { - if (memcmp(data, resp, 8)) { // check response. All other updates return unchanged data - return false; - } - } - - return true; -} - - -void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { - - LED_A_ON(); - - bool isOK = iClass_WriteBlock_ext(blockNo, data); - if (isOK) { - Dbprintf("Write block [%02x] successful", blockNo); - } else { - Dbprintf("Write block [%02x] failed", blockNo); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); LED_A_OFF(); } -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { - - LED_A_ON(); - - int written = 0; - int total_blocks = (endblock - startblock) + 1; - - for (uint8_t block = startblock; block <= endblock; block++) { - // block number - if (iClass_WriteBlock_ext(block, data + (block-startblock)*12)) { - Dbprintf("Write block [%02x] successful", block); - written++; - } else { - Dbprintf("Write block [%02x] failed", block); - } - } - - if (written == total_blocks) - Dbprintf("Clone complete"); - else - Dbprintf("Clone incomplete"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - LED_A_OFF(); -} diff --git a/armsrc/iclass.h b/armsrc/iclass.h deleted file mode 100644 index 541e1a2c..00000000 --- a/armsrc/iclass.h +++ /dev/null @@ -1,32 +0,0 @@ -//----------------------------------------------------------------------------- -// Gerhard de Koning Gans - May 2008 -// Hagen Fritsch - June 2010 -// Gerhard de Koning Gans - May 2011 -// Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support iClass. -//----------------------------------------------------------------------------- - -#ifndef ICLASS_H__ -#define ICLASS_H__ - -#include -#include - -extern void SnoopIClass(uint8_t jam_search_len, uint8_t *jam_search_string); -extern void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void ReaderIClass(uint8_t arg0); -extern void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC); -extern void IClass_iso14443A_GetPublic(uint8_t arg0); -extern void iClass_Readcheck(uint8_t block, bool use_credit_key); -extern void iClass_Check(uint8_t *MAC); -extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); -extern void iClass_ReadBlk(uint8_t blockNo); -extern void iClass_Dump(uint8_t blockno, uint8_t numblks); -extern void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); - -#endif diff --git a/armsrc/iso14443.c b/armsrc/iso14443.c new file mode 100644 index 00000000..5e8eddd2 --- /dev/null +++ b/armsrc/iso14443.c @@ -0,0 +1,1235 @@ +//----------------------------------------------------------------------------- +// Jonathan Westhues, split Nov 2006 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 14443. This includes both the reader software and +// the `fake tag' modes. At the moment only the Type B modulation is +// supported. +//----------------------------------------------------------------------------- + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "iso14443crc.h" + +//static void GetSamplesFor14443(int weTx, int n); + +#define DEMOD_TRACE_SIZE 4096 +#define READER_TAG_BUFFER_SIZE 2048 +#define TAG_READER_BUFFER_SIZE 2048 +#define DEMOD_DMA_BUFFER_SIZE 1024 + +//============================================================================= +// An ISO 14443 Type B tag. We listen for commands from the reader, using +// a UART kind of thing that's implemented in software. When we get a +// frame (i.e., a group of bytes between SOF and EOF), we check the CRC. +// If it's good, then we can do something appropriate with it, and send +// a response. +//============================================================================= + +//----------------------------------------------------------------------------- +// Code up a string of octets at layer 2 (including CRC, we don't generate +// that here) so that they can be transmitted to the reader. Doesn't transmit +// them yet, just leaves them ready to send in ToSend[]. +//----------------------------------------------------------------------------- +static void CodeIso14443bAsTag(const uint8_t *cmd, int len) +{ + int i; + + ToSendReset(); + + // Transmit a burst of ones, as the initial thing that lets the + // reader get phase sync. This (TR1) must be > 80/fs, per spec, + // but tag that I've tried (a Paypass) exceeds that by a fair bit, + // so I will too. + for(i = 0; i < 20; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Send SOF. + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + for(i = 0; i < 2; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + for(i = 0; i < len; i++) { + int j; + uint8_t b = cmd[i]; + + // Start bit + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + + // Data bits + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + b >>= 1; + } + + // Stop bit + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Send SOF. + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + } + for(i = 0; i < 10; i++) { + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + } + + // Convert from last byte pos to length + ToSendMax++; + + // Add a few more for slop + ToSendMax += 2; +} + +//----------------------------------------------------------------------------- +// The software UART that receives commands from the reader, and its state +// variables. +//----------------------------------------------------------------------------- +static struct { + enum { + STATE_UNSYNCD, + STATE_GOT_FALLING_EDGE_OF_SOF, + STATE_AWAITING_START_BIT, + STATE_RECEIVING_DATA, + STATE_ERROR_WAIT + } state; + uint16_t shiftReg; + int bitCnt; + int byteCnt; + int byteCntMax; + int posCnt; + uint8_t *output; +} Uart; + +/* Receive & handle a bit coming from the reader. + * + * LED handling: + * LED A -> ON once we have received the SOF and are expecting the rest. + * LED A -> OFF once we have received EOF or are in error state or unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + */ +static int Handle14443UartBit(int bit) +{ + switch(Uart.state) { + case STATE_UNSYNCD: + LED_A_OFF(); + if(!bit) { + // we went low, so this could be the beginning + // of an SOF + Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF; + Uart.posCnt = 0; + Uart.bitCnt = 0; + } + break; + + case STATE_GOT_FALLING_EDGE_OF_SOF: + Uart.posCnt++; + if(Uart.posCnt == 2) { + if(bit) { + if(Uart.bitCnt >= 10) { + // we've seen enough consecutive + // zeros that it's a valid SOF + Uart.posCnt = 0; + Uart.byteCnt = 0; + Uart.state = STATE_AWAITING_START_BIT; + LED_A_ON(); // Indicate we got a valid SOF + } else { + // didn't stay down long enough + // before going high, error + Uart.state = STATE_ERROR_WAIT; + } + } else { + // do nothing, keep waiting + } + Uart.bitCnt++; + } + if(Uart.posCnt >= 4) Uart.posCnt = 0; + if(Uart.bitCnt > 14) { + // Give up if we see too many zeros without + // a one, too. + Uart.state = STATE_ERROR_WAIT; + } + break; + + case STATE_AWAITING_START_BIT: + Uart.posCnt++; + if(bit) { + if(Uart.posCnt > 25) { + // stayed high for too long between + // characters, error + Uart.state = STATE_ERROR_WAIT; + } + } else { + // falling edge, this starts the data byte + Uart.posCnt = 0; + Uart.bitCnt = 0; + Uart.shiftReg = 0; + Uart.state = STATE_RECEIVING_DATA; + LED_A_ON(); // Indicate we're receiving + } + break; + + case STATE_RECEIVING_DATA: + Uart.posCnt++; + if(Uart.posCnt == 2) { + // time to sample a bit + Uart.shiftReg >>= 1; + if(bit) { + Uart.shiftReg |= 0x200; + } + Uart.bitCnt++; + } + if(Uart.posCnt >= 4) { + Uart.posCnt = 0; + } + if(Uart.bitCnt == 10) { + if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001)) + { + // this is a data byte, with correct + // start and stop bits + Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff; + Uart.byteCnt++; + + if(Uart.byteCnt >= Uart.byteCntMax) { + // Buffer overflowed, give up + Uart.posCnt = 0; + Uart.state = STATE_ERROR_WAIT; + } else { + // so get the next byte now + Uart.posCnt = 0; + Uart.state = STATE_AWAITING_START_BIT; + } + } else if(Uart.shiftReg == 0x000) { + // this is an EOF byte + LED_A_OFF(); // Finished receiving + return TRUE; + } else { + // this is an error + Uart.posCnt = 0; + Uart.state = STATE_ERROR_WAIT; + } + } + break; + + case STATE_ERROR_WAIT: + // We're all screwed up, so wait a little while + // for whatever went wrong to finish, and then + // start over. + Uart.posCnt++; + if(Uart.posCnt > 10) { + Uart.state = STATE_UNSYNCD; + } + break; + + default: + Uart.state = STATE_UNSYNCD; + break; + } + + // This row make the error blew circular buffer in hf 14b snoop + //if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error + + return FALSE; +} + +//----------------------------------------------------------------------------- +// Receive a command (from the reader to us, where we are the simulated tag), +// and store it in the given buffer, up to the given maximum length. Keeps +// spinning, waiting for a well-framed command, until either we get one +// (returns TRUE) or someone presses the pushbutton on the board (FALSE). +// +// Assume that we're called with the SSC (to the FPGA) and ADC path set +// correctly. +//----------------------------------------------------------------------------- +static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) +{ + uint8_t mask; + int i, bit; + + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + + + // Now run a `software UART' on the stream of incoming samples. + Uart.output = received; + Uart.byteCntMax = maxLen; + Uart.state = STATE_UNSYNCD; + + for(;;) { + WDT_HIT(); + + if(BUTTON_PRESS()) return FALSE; + + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + + mask = 0x80; + for(i = 0; i < 8; i++, mask >>= 1) { + bit = (b & mask); + if(Handle14443UartBit(bit)) { + *len = Uart.byteCnt; + return TRUE; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Main loop of simulated tag: receive commands from reader, decide what +// response to send, and send it. +//----------------------------------------------------------------------------- +void SimulateIso14443Tag(void) +{ + static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + static const uint8_t response1[] = { + 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22, + 0x00, 0x21, 0x85, 0x5e, 0xd7 + }; + + uint8_t *resp; + int respLen; + + uint8_t *resp1 = (((uint8_t *)BigBuf) + 800); + int resp1Len; + + uint8_t *receivedCmd = (uint8_t *)BigBuf; + int len; + + int i; + + int cmdsRecvd = 0; + + memset(receivedCmd, 0x44, 400); + + CodeIso14443bAsTag(response1, sizeof(response1)); + memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax; + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + cmdsRecvd = 0; + + for(;;) { + uint8_t b1, b2; + + if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) { + Dbprintf("button pressed, received %d commands", cmdsRecvd); + break; + } + + // Good, look at the command now. + + if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) { + resp = resp1; respLen = resp1Len; + } else { + Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); + // And print whether the CRC fails, just for good measure + ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2); + if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) { + // Not so good, try again. + DbpString("+++CRC fail"); + } else { + DbpString("CRC passes"); + } + break; + } + + memset(receivedCmd, 0x44, 32); + + cmdsRecvd++; + + if(cmdsRecvd > 0x30) { + DbpString("many commands later..."); + break; + } + + if(respLen <= 0) continue; + + // Modulate BPSK + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); + AT91C_BASE_SSC->SSC_THR = 0xff; + FpgaSetupSsc(); + + // Transmit the response. + i = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + uint8_t b = resp[i]; + + AT91C_BASE_SSC->SSC_THR = b; + + i++; + if(i > respLen) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + } + } +} + +//============================================================================= +// An ISO 14443 Type B reader. We take layer two commands, code them +// appropriately, and then send them to the tag. We then listen for the +// tag's response, which we leave in the buffer to be demodulated on the +// PC side. +//============================================================================= + +static struct { + enum { + DEMOD_UNSYNCD, + DEMOD_PHASE_REF_TRAINING, + DEMOD_AWAITING_FALLING_EDGE_OF_SOF, + DEMOD_GOT_FALLING_EDGE_OF_SOF, + DEMOD_AWAITING_START_BIT, + DEMOD_RECEIVING_DATA, + DEMOD_ERROR_WAIT + } state; + int bitCount; + int posCount; + int thisBit; + int metric; + int metricN; + uint16_t shiftReg; + uint8_t *output; + int len; + int sumI; + int sumQ; +} Demod; + +/* + * Handles reception of a bit from the tag + * + * LED handling: + * LED C -> ON once we have received the SOF and are expecting the rest. + * LED C -> OFF once we have received EOF or are unsynced + * + * Returns: true if we received a EOF + * false if we are still waiting for some more + * + */ +static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) +{ + int v; + + // The soft decision on the bit uses an estimate of just the + // quadrant of the reference angle, not the exact angle. +#define MAKE_SOFT_DECISION() { \ + if(Demod.sumI > 0) { \ + v = ci; \ + } else { \ + v = -ci; \ + } \ + if(Demod.sumQ > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } + + switch(Demod.state) { + case DEMOD_UNSYNCD: + v = ci; + if(v < 0) v = -v; + if(cq > 0) { + v += cq; + } else { + v -= cq; + } + if(v > 40) { + Demod.posCount = 0; + Demod.state = DEMOD_PHASE_REF_TRAINING; + Demod.sumI = 0; + Demod.sumQ = 0; + } + break; + + case DEMOD_PHASE_REF_TRAINING: + if(Demod.posCount < 8) { + Demod.sumI += ci; + Demod.sumQ += cq; + } else if(Demod.posCount > 100) { + // error, waited too long + Demod.state = DEMOD_UNSYNCD; + } else { + MAKE_SOFT_DECISION(); + if(v < 0) { + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; + Demod.posCount = 0; + } + } + Demod.posCount++; + break; + + case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: + MAKE_SOFT_DECISION(); + if(v < 0) { + Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; + Demod.posCount = 0; + } else { + if(Demod.posCount > 100) { + Demod.state = DEMOD_UNSYNCD; + } + } + Demod.posCount++; + break; + + case DEMOD_GOT_FALLING_EDGE_OF_SOF: + MAKE_SOFT_DECISION(); + if(v > 0) { + if(Demod.posCount < 12) { + Demod.state = DEMOD_UNSYNCD; + } else { + LED_C_ON(); // Got SOF + Demod.state = DEMOD_AWAITING_START_BIT; + Demod.posCount = 0; + Demod.len = 0; + Demod.metricN = 0; + Demod.metric = 0; + } + } else { + if(Demod.posCount > 100) { + Demod.state = DEMOD_UNSYNCD; + } + } + Demod.posCount++; + break; + + case DEMOD_AWAITING_START_BIT: + MAKE_SOFT_DECISION(); + if(v > 0) { + if(Demod.posCount > 10) { + Demod.state = DEMOD_UNSYNCD; + } + } else { + Demod.bitCount = 0; + Demod.posCount = 1; + Demod.thisBit = v; + Demod.shiftReg = 0; + Demod.state = DEMOD_RECEIVING_DATA; + } + break; + + case DEMOD_RECEIVING_DATA: + MAKE_SOFT_DECISION(); + if(Demod.posCount == 0) { + Demod.thisBit = v; + Demod.posCount = 1; + } else { + Demod.thisBit += v; + + if(Demod.thisBit > 0) { + Demod.metric += Demod.thisBit; + } else { + Demod.metric -= Demod.thisBit; + } + (Demod.metricN)++; + + Demod.shiftReg >>= 1; + if(Demod.thisBit > 0) { + Demod.shiftReg |= 0x200; + } + + Demod.bitCount++; + if(Demod.bitCount == 10) { + uint16_t s = Demod.shiftReg; + if((s & 0x200) && !(s & 0x001)) { + uint8_t b = (s >> 1); + Demod.output[Demod.len] = b; + Demod.len++; + Demod.state = DEMOD_AWAITING_START_BIT; + } else if(s == 0x000) { + // This is EOF + LED_C_OFF(); + Demod.state = DEMOD_UNSYNCD; + return TRUE; + } else { + Demod.state = DEMOD_UNSYNCD; + } + } + Demod.posCount = 0; + } + break; + + default: + Demod.state = DEMOD_UNSYNCD; + break; + } + + if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized... + return FALSE; +} + +/* + * Demodulate the samples we received from the tag + * weTx: set to 'TRUE' if we behave like a reader + * set to 'FALSE' if we behave like a snooper + * quiet: set to 'TRUE' to disable debug output + */ +static void GetSamplesFor14443Demod(int weTx, int n, int quiet) +{ + int max = 0; + int gotFrame = FALSE; + +//# define DMA_BUFFER_SIZE 8 + int8_t *dmaBuf; + + int lastRxCounter; + int8_t *upTo; + + int ci, cq; + + int samples = 0; + + // Clear out the state of the "UART" that receives from the tag. + memset(BigBuf, 0x00, 400); + Demod.output = (uint8_t *)BigBuf; + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; + + // And the UART that receives from the reader + Uart.output = (((uint8_t *)BigBuf) + 1024); + Uart.byteCntMax = 100; + Uart.state = STATE_UNSYNCD; + + // Setup for the DMA. + dmaBuf = (int8_t *)(BigBuf + 32); + upTo = dmaBuf; + lastRxCounter = DEMOD_DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t *)dmaBuf, DEMOD_DMA_BUFFER_SIZE); + + // Signal field is ON with the appropriate LED: + if (weTx) LED_D_ON(); else LED_D_OFF(); + // And put the FPGA in the appropriate mode + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | + (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); + + for(;;) { + int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; + if(behindBy > max) max = behindBy; + + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DEMOD_DMA_BUFFER_SIZE-1)) + > 2) + { + ci = upTo[0]; + cq = upTo[1]; + upTo += 2; + if(upTo - dmaBuf > DEMOD_DMA_BUFFER_SIZE) { + upTo -= DEMOD_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = DEMOD_DMA_BUFFER_SIZE; + } + lastRxCounter -= 2; + if(lastRxCounter <= 0) { + lastRxCounter += DEMOD_DMA_BUFFER_SIZE; + } + + samples += 2; + + Handle14443UartBit(1); + Handle14443UartBit(1); + + if(Handle14443SamplesDemod(ci, cq)) { + gotFrame = 1; + } + } + + if(samples > 2000) { + break; + } + } + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len); +} + +//----------------------------------------------------------------------------- +// Read the tag's response. We just receive a stream of slightly-processed +// samples from the FPGA, which we will later do some signal processing on, +// to get the bits. +//----------------------------------------------------------------------------- +/*static void GetSamplesFor14443(int weTx, int n) +{ + uint8_t *dest = (uint8_t *)BigBuf; + int c; + + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | + (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + dest[c++] = (uint8_t)b; + + if(c >= n) { + break; + } + } + } +}*/ + +//----------------------------------------------------------------------------- +// Transmit the command (to the tag) that was placed in ToSend[]. +//----------------------------------------------------------------------------- +static void TransmitFor14443(void) +{ + int c; + + FpgaSetupSsc(); + + while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + } + + // Signal field is ON with the appropriate Red LED + LED_D_ON(); + // Signal we are transmitting with the Green LED + LED_B_ON(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + + for(c = 0; c < 10;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0xff; + c++; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + c++; + if(c >= ToSendMax) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + LED_B_OFF(); // Finished sending +} + +//----------------------------------------------------------------------------- +// Code a layer 2 command (string of octets, including CRC) into ToSend[], +// so that it is ready to transmit to the tag using TransmitFor14443(). +//----------------------------------------------------------------------------- +static void CodeIso14443bAsReader(const uint8_t *cmd, int len) +{ + int i, j; + uint8_t b; + + ToSendReset(); + + // Establish initial reference level + for(i = 0; i < 40; i++) { + ToSendStuffBit(1); + } + // Send SOF + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + } + + for(i = 0; i < len; i++) { + // Stop bits/EGT + ToSendStuffBit(1); + ToSendStuffBit(1); + // Start bit + ToSendStuffBit(0); + // Data bits + b = cmd[i]; + for(j = 0; j < 8; j++) { + if(b & 1) { + ToSendStuffBit(1); + } else { + ToSendStuffBit(0); + } + b >>= 1; + } + } + // Send EOF + ToSendStuffBit(1); + for(i = 0; i < 10; i++) { + ToSendStuffBit(0); + } + for(i = 0; i < 8; i++) { + ToSendStuffBit(1); + } + + // And then a little more, to make sure that the last character makes + // it out before we switch to rx mode. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } + + // Convert from last character reference to length + ToSendMax++; +} + +//----------------------------------------------------------------------------- +// Read an ISO 14443 tag. We send it some set of commands, and record the +// responses. +// The command name is misleading, it actually decodes the reponse in HEX +// into the output buffer (read the result using hexsamples, not hisamples) +// +// obsolete function only for test +//----------------------------------------------------------------------------- +void AcquireRawAdcSamplesIso14443(uint32_t parameter) +{ + uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + + SendRawCommand14443B(sizeof(cmd1),1,1,cmd1); +} + +//----------------------------------------------------------------------------- +// Read a SRI512 ISO 14443 tag. +// +// SRI512 tags are just simple memory tags, here we're looking at making a dump +// of the contents of the memory. No anticollision algorithm is done, we assume +// we have a single tag in the field. +// +// I tried to be systematic and check every answer of the tag, every CRC, etc... +//----------------------------------------------------------------------------- +void ReadSTMemoryIso14443(uint32_t dwLast) +{ + uint8_t i = 0x00; + + // Make sure that we start from off, since the tags are stateful; + // confusing things will happen if we don't reset them between reads. + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + SpinDelay(200); + + // First command: wake up the tag using the INITIATE command + uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b}; + CodeIso14443bAsReader(cmd1, sizeof(cmd1)); + TransmitFor14443(); +// LED_A_ON(); + GetSamplesFor14443Demod(TRUE, 2000,TRUE); +// LED_A_OFF(); + + if (Demod.len == 0) { + DbpString("No response from tag"); + return; + } else { + Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x", + Demod.output[0], Demod.output[1],Demod.output[2]); + } + // There is a response, SELECT the uid + DbpString("Now SELECT tag:"); + cmd1[0] = 0x0E; // 0x0E is SELECT + cmd1[1] = Demod.output[0]; + ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); + CodeIso14443bAsReader(cmd1, sizeof(cmd1)); + TransmitFor14443(); +// LED_A_ON(); + GetSamplesFor14443Demod(TRUE, 2000,TRUE); +// LED_A_OFF(); + if (Demod.len != 3) { + Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); + return; + } + // Check the CRC of the answer: + ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { + DbpString("CRC Error reading select response."); + return; + } + // Check response from the tag: should be the same UID as the command we just sent: + if (cmd1[1] != Demod.output[0]) { + Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]); + return; + } + // Tag is now selected, + // First get the tag's UID: + cmd1[0] = 0x0B; + ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); + CodeIso14443bAsReader(cmd1, 3); // Only first three bytes for this one + TransmitFor14443(); +// LED_A_ON(); + GetSamplesFor14443Demod(TRUE, 2000,TRUE); +// LED_A_OFF(); + if (Demod.len != 10) { + Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); + return; + } + // The check the CRC of the answer (use cmd1 as temporary variable): + ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { + Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); + // Do not return;, let's go on... (we should retry, maybe ?) + } + Dbprintf("Tag UID (64 bits): %08x %08x", + (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); + + // Now loop to read all 16 blocks, address from 0 to last block + Dbprintf("Tag memory dump, block 0 to %d",dwLast); + cmd1[0] = 0x08; + i = 0x00; + dwLast++; + for (;;) { + if (i == dwLast) { + DbpString("System area block (0xff):"); + i = 0xff; + } + cmd1[1] = i; + ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); + CodeIso14443bAsReader(cmd1, sizeof(cmd1)); + TransmitFor14443(); +// LED_A_ON(); + GetSamplesFor14443Demod(TRUE, 2000,TRUE); +// LED_A_OFF(); + if (Demod.len != 6) { // Check if we got an answer from the tag + DbpString("Expected 6 bytes from tag, got less..."); + return; + } + // The check the CRC of the answer (use cmd1 as temporary variable): + ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); + if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { + Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); + // Do not return;, let's go on... (we should retry, maybe ?) + } + // Now print out the memory location: + Dbprintf("Address=%x, Contents=%x, CRC=%x", i, + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], + (Demod.output[4]<<8)+Demod.output[5]); + if (i == 0xff) { + break; + } + i++; + } +} + + +//============================================================================= +// Finally, the `sniffer' combines elements from both the reader and +// simulated tag, to show both sides of the conversation. +//============================================================================= + +//----------------------------------------------------------------------------- +// Record the sequence of commands sent by the reader to the tag, with +// triggering so that we start recording at the point that the tag is moved +// near the reader. +//----------------------------------------------------------------------------- +/* + * Memory usage for this function, (within BigBuf) + * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE + * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE + * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE + * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DEMOD_DMA_BUFFER_SIZE + */ +void RAMFUNC SnoopIso14443(void) +{ + // We won't start recording the frames that we acquire until we trigger; + // a good trigger condition to get started is probably when we see a + // response from the tag. + int triggered = TRUE; + + // The command (reader -> tag) that we're working on receiving. + uint8_t *receivedCmd = (uint8_t *)(BigBuf) + DEMOD_TRACE_SIZE; + // The response (tag -> reader) that we're working on receiving. + uint8_t *receivedResponse = (uint8_t *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE; + + // As we receive stuff, we copy it from receivedCmd or receivedResponse + // into trace, along with its length and other annotations. + uint8_t *trace = (uint8_t *)BigBuf; + int traceLen = 0; + + // The DMA buffer, used to stream samples from the FPGA. + int8_t *dmaBuf = (int8_t *)(BigBuf) + DEMOD_TRACE_SIZE + READER_TAG_BUFFER_SIZE + TAG_READER_BUFFER_SIZE; + int lastRxCounter; + int8_t *upTo; + int ci, cq; + int maxBehindBy = 0; + + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; + + // Initialize the trace buffer + memset(trace, 0x44, DEMOD_TRACE_SIZE); + + // Set up the demodulator for tag -> reader responses. + Demod.output = receivedResponse; + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; + + // And the reader -> tag commands + memset(&Uart, 0, sizeof(Uart)); + Uart.output = receivedCmd; + Uart.byteCntMax = 100; + Uart.state = STATE_UNSYNCD; + + // Print some debug information about the buffer sizes + Dbprintf("Snooping buffers initialized:"); + Dbprintf(" Trace: %i bytes", DEMOD_TRACE_SIZE); + Dbprintf(" Reader -> tag: %i bytes", READER_TAG_BUFFER_SIZE); + Dbprintf(" tag -> Reader: %i bytes", TAG_READER_BUFFER_SIZE); + Dbprintf(" DMA: %i bytes", DEMOD_DMA_BUFFER_SIZE); + + // And put the FPGA in the appropriate mode + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | + FPGA_HF_READER_RX_XCORR_SNOOP); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + + // Setup for the DMA. + FpgaSetupSsc(); + upTo = dmaBuf; + lastRxCounter = DEMOD_DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t *)dmaBuf, DEMOD_DMA_BUFFER_SIZE); + + LED_A_ON(); + + // And now we loop, receiving samples. + for(;;) { + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & + (DEMOD_DMA_BUFFER_SIZE-1); + if(behindBy > maxBehindBy) { + maxBehindBy = behindBy; + if(behindBy > (DEMOD_DMA_BUFFER_SIZE-2)) { // TODO: understand whether we can increase/decrease as we want or not? + Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); + goto done; + } + } + if(behindBy < 2) continue; + + ci = upTo[0]; + cq = upTo[1]; + upTo += 2; + lastRxCounter -= 2; + if(upTo - dmaBuf > DEMOD_DMA_BUFFER_SIZE) { + upTo -= DEMOD_DMA_BUFFER_SIZE; + lastRxCounter += DEMOD_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = DEMOD_DMA_BUFFER_SIZE; + } + + samples += 2; + +#define HANDLE_BIT_IF_BODY \ + if(triggered) { \ + trace[traceLen++] = ((samples >> 0) & 0xff); \ + trace[traceLen++] = ((samples >> 8) & 0xff); \ + trace[traceLen++] = ((samples >> 16) & 0xff); \ + trace[traceLen++] = ((samples >> 24) & 0xff); \ + trace[traceLen++] = 0; \ + trace[traceLen++] = 0; \ + trace[traceLen++] = 0; \ + trace[traceLen++] = 0; \ + trace[traceLen++] = Uart.byteCnt; \ + memcpy(trace+traceLen, receivedCmd, Uart.byteCnt); \ + traceLen += Uart.byteCnt; \ + if(traceLen > 1000) break; \ + } \ + /* And ready to receive another command. */ \ + memset(&Uart, 0, sizeof(Uart)); \ + Uart.output = receivedCmd; \ + Uart.byteCntMax = 100; \ + Uart.state = STATE_UNSYNCD; \ + /* And also reset the demod code, which might have been */ \ + /* false-triggered by the commands from the reader. */ \ + memset(&Demod, 0, sizeof(Demod)); \ + Demod.output = receivedResponse; \ + Demod.state = DEMOD_UNSYNCD; \ + + if(Handle14443UartBit(ci & 1)) { + HANDLE_BIT_IF_BODY + } + if(Handle14443UartBit(cq & 1)) { + HANDLE_BIT_IF_BODY + } + + if(Handle14443SamplesDemod(ci, cq)) { + // timestamp, as a count of samples + trace[traceLen++] = ((samples >> 0) & 0xff); + trace[traceLen++] = ((samples >> 8) & 0xff); + trace[traceLen++] = ((samples >> 16) & 0xff); + trace[traceLen++] = 0x80 | ((samples >> 24) & 0xff); + // correlation metric (~signal strength estimate) + if(Demod.metricN != 0) { + Demod.metric /= Demod.metricN; + } + trace[traceLen++] = ((Demod.metric >> 0) & 0xff); + trace[traceLen++] = ((Demod.metric >> 8) & 0xff); + trace[traceLen++] = ((Demod.metric >> 16) & 0xff); + trace[traceLen++] = ((Demod.metric >> 24) & 0xff); + // length + trace[traceLen++] = Demod.len; + memcpy(trace+traceLen, receivedResponse, Demod.len); + traceLen += Demod.len; + if(traceLen > DEMOD_TRACE_SIZE) { + DbpString("Reached trace limit"); + goto done; + } + + triggered = TRUE; + LED_A_OFF(); + LED_B_ON(); + + // And ready to receive another response. + memset(&Demod, 0, sizeof(Demod)); + Demod.output = receivedResponse; + Demod.state = DEMOD_UNSYNCD; + } + WDT_HIT(); + + if(BUTTON_PRESS()) { + DbpString("cancelled"); + goto done; + } + } + +done: + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + DbpString("Snoop statistics:"); + Dbprintf(" Max behind by: %i", maxBehindBy); + Dbprintf(" Uart State: %x", Uart.state); + Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt); + Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax); + Dbprintf(" Trace length: %i", traceLen); +} + +/* + * Send raw command to tag ISO14443B + * @Input + * datalen len of buffer data + * recv bool when true wait for data from tag and send to client + * powerfield bool leave the field on when true + * data buffer with byte to send + * + * @Output + * none + * + */ + +void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[]) +{ + if(!powerfield) + { + // Make sure that we start from off, since the tags are stateful; + // confusing things will happen if we don't reset them between reads. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelay(200); + } + + if(!GETBIT(GPIO_LED_D)) + { + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Now give it time to spin up. + // Signal field is on with the appropriate LED + LED_D_ON(); + FpgaWriteConfWord( + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + SpinDelay(200); + } + + CodeIso14443bAsReader(data, datalen); + TransmitFor14443(); + if(recv) + { + uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE); + GetSamplesFor14443Demod(TRUE, 2000, TRUE); + cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen); + } + if(!powerfield) + { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + } +} + diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 8686cea7..9afe0788 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -10,83 +10,22 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#include "iso14443a.h" - -#include -#include -#include - #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "usb_cdc.h" +#include "string.h" +#include "cmd.h" + #include "iso14443crc.h" -#include "crapto1/crapto1.h" +#include "iso14443a.h" +#include "crapto1.h" #include "mifareutil.h" -#include "mifaresniff.h" -#include "BigBuf.h" -#include "protocols.h" -#include "parity.h" -#include "fpgaloader.h" - -typedef struct { - enum { - DEMOD_UNSYNCD, - // DEMOD_HALF_SYNCD, - // DEMOD_MOD_FIRST_HALF, - // DEMOD_NOMOD_FIRST_HALF, - DEMOD_MANCHESTER_DATA - } state; - uint16_t twoBits; - uint16_t highCnt; - uint16_t bitCount; - uint16_t collisionPos; - uint16_t syncBit; - uint8_t parityBits; - uint8_t parityLen; - uint16_t shiftReg; - uint16_t samples; - uint16_t len; - uint32_t startTime, endTime; - uint8_t *output; - uint8_t *parity; -} tDemod; - -typedef enum { - MOD_NOMOD = 0, - MOD_SECOND_HALF, - MOD_FIRST_HALF, - MOD_BOTH_HALVES - } Modulation_t; - -typedef struct { - enum { - STATE_UNSYNCD, - STATE_START_OF_COMMUNICATION, - STATE_MILLER_X, - STATE_MILLER_Y, - STATE_MILLER_Z, - // DROP_NONE, - // DROP_FIRST_HALF, - } state; - uint16_t shiftReg; - int16_t bitCount; - uint16_t len; - uint16_t byteCntMax; - uint16_t posCnt; - uint16_t syncBit; - uint8_t parityBits; - uint8_t parityLen; - uint32_t fourBits; - uint32_t startTime, endTime; - uint8_t *output; - uint8_t *parity; -} tUart; static uint32_t iso14a_timeout; -#define MAX_ISO14A_TIMEOUT 524288 - +uint8_t *trace = (uint8_t *) BigBuf+TRACE_OFFSET; int rsamples = 0; +int traceLen = 0; +int tracing = TRUE; uint8_t trigger = 0; // the block number for the ISO14443-4 PCB static uint8_t iso14_pcb_blocknum = 0; @@ -96,9 +35,9 @@ static uint8_t iso14_pcb_blocknum = 0; // // minimum time between the start bits of consecutive transfers from reader to tag: 7000 carrier (13.56Mhz) cycles #define REQUEST_GUARD_TIME (7000/16 + 1) -// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles -#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) -// bool LastCommandWasRequest = false; +// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles +#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) +// bool LastCommandWasRequest = FALSE; // // Total delays including SSC-Transfers between ARM and FPGA. These are in carrier clock cycles (1/13,56MHz) @@ -109,8 +48,8 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until bit_to_arm is assigned from curbit // 8*16 ticks for the transfer from FPGA to ARM // 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer -#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) +// - 8*16 ticks because we measure the time of the previous transfer +#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // When the PM acts as a reader and is sending, it takes // 4*16 ticks until we can write data to the sending hold register @@ -127,10 +66,10 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until the SSC samples the first data // 7*16 ticks to complete the transfer from FPGA to ARM // 8 ticks until the next ssp_clk rising edge -// 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer +// 4*16 ticks until we measure the time +// - 8*16 ticks because we measure the time of the previous transfer #define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16) - + // The FPGA will report its internal sending delay in uint16_t FpgaSendQueueDelay; // the 5 first bits are the number of bits buffered in mod_sig_buf @@ -138,13 +77,13 @@ uint16_t FpgaSendQueueDelay; #define DELAY_FPGA_QUEUE (FpgaSendQueueDelay<<1) // When the PM acts as tag and is sending, it takes -// 4*16 + 8 ticks until we can write data to the sending hold register +// 4*16 ticks until we can write data to the sending hold register // 8*16 ticks until the SHR is transferred to the Sending Shift Register -// 8 ticks later the FPGA samples the first data -// + 16 ticks until assigned to mod_sig -// + 1 tick to assign mod_sig_coil +// 8 ticks until the first transfer starts +// 8 ticks later the FPGA samples the data // + a varying number of ticks in the FPGA Delay Queue (mod_sig_buf) -#define DELAY_ARM2AIR_AS_TAG (4*16 + 8 + 8*16 + 8 + 16 + 1 + DELAY_FPGA_QUEUE) +// + 1 tick to assign mod_sig_coil +#define DELAY_ARM2AIR_AS_TAG (4*16 + 8*16 + 8 + 8 + DELAY_FPGA_QUEUE + 1) // When the PM acts as sniffer and is receiving tag data, it takes // 3 ticks A/D conversion @@ -152,22 +91,22 @@ uint16_t FpgaSendQueueDelay; // 8 ticks (on average) until the result is stored in to_arm // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) - +#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) + // When the PM acts as sniffer and is receiving reader data, it takes -// 2 ticks delay in analogue RF receiver (for the falling edge of the +// 2 ticks delay in analogue RF receiver (for the falling edge of the // start bit, which marks the start of the communication) // 3 ticks A/D conversion // 8 ticks on average until the data is stored in to_arm. // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) +#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) //variables used for timing purposes: //these are in ssp_clk cycles: -static uint32_t NextTransferTime; -static uint32_t LastTimeProxToAirStart; -static uint32_t LastProxToAirDuration; +uint32_t NextTransferTime; +uint32_t LastTimeProxToAirStart; +uint32_t LastProxToAirDuration; @@ -179,55 +118,70 @@ static uint32_t LastProxToAirDuration; // Sequence X: 00001100 drop after half a period // Sequence Y: 00000000 no drop // Sequence Z: 11000000 drop at start -#define SEC_D 0xf0 -#define SEC_E 0x0f -#define SEC_F 0x00 -#define SEC_X 0x0c -#define SEC_Y 0x00 -#define SEC_Z 0xc0 +#define SEC_D 0xf0 +#define SEC_E 0x0f +#define SEC_F 0x00 +#define SEC_X 0x0c +#define SEC_Y 0x00 +#define SEC_Z 0xc0 + +const uint8_t OddByteParity[256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 +}; + void iso14a_set_trigger(bool enable) { trigger = enable; } - -void iso14a_set_timeout(uint32_t timeout) { - // adjust timeout by FPGA delays and 2 additional ssp_frames to detect SOF - iso14a_timeout = timeout + (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) + 2; - if (MF_DBGLEVEL >= 3) Dbprintf("ISO14443A Timeout set to %" PRIu32 " (%dms)", timeout, timeout / 106); +void iso14a_clear_trace() { + memset(trace, 0x44, TRACE_SIZE); + traceLen = 0; } +void iso14a_set_tracing(bool enable) { + tracing = enable; +} -uint32_t iso14a_get_timeout(void) { - return iso14a_timeout - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/(16*8) - 2; +void iso14a_set_timeout(uint32_t timeout) { + iso14a_timeout = timeout; } //----------------------------------------------------------------------------- // Generate the parity value for a byte sequence // //----------------------------------------------------------------------------- -void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) +byte_t oddparity (const byte_t bt) { - uint16_t paritybit_cnt = 0; - uint16_t paritybyte_cnt = 0; - uint8_t parityBits = 0; + return OddByteParity[bt]; +} - for (uint16_t i = 0; i < iLen; i++) { - // Generate the parity bits - parityBits |= ((oddparity8(pbtCmd[i])) << (7-paritybit_cnt)); - if (paritybit_cnt == 7) { - par[paritybyte_cnt] = parityBits; // save 8 Bits parity - parityBits = 0; // and advance to next Parity Byte - paritybyte_cnt++; - paritybit_cnt = 0; - } else { - paritybit_cnt++; - } +uint32_t GetParity(const uint8_t * pbtCmd, int iLen) +{ + int i; + uint32_t dwPar = 0; + + // Generate the parity bits + for (i = 0; i < iLen; i++) { + // and save them to a 32Bit word + dwPar |= ((OddByteParity[pbtCmd[i]]) << i); } - - // save remaining parity bits - par[paritybyte_cnt] = parityBits; - + return dwPar; } void AppendCrc14443a(uint8_t* data, int len) @@ -235,185 +189,177 @@ void AppendCrc14443a(uint8_t* data, int len) ComputeCrc14443(CRC_14443_A,data,len,data+len,data+len+1); } -static void AppendCrc14443b(uint8_t* data, int len) +// The function LogTrace() is also used by the iClass implementation in iClass.c +bool RAMFUNC LogTrace(const uint8_t * btBytes, uint8_t iLen, uint32_t timestamp, uint32_t dwParity, bool bReader) { - ComputeCrc14443(CRC_14443_B,data,len,data+len,data+len+1); + // Return when trace is full + if (traceLen + sizeof(timestamp) + sizeof(dwParity) + iLen >= TRACE_SIZE) { + tracing = FALSE; // don't trace any more + return FALSE; + } + + // Trace the random, i'm curious + trace[traceLen++] = ((timestamp >> 0) & 0xff); + trace[traceLen++] = ((timestamp >> 8) & 0xff); + trace[traceLen++] = ((timestamp >> 16) & 0xff); + trace[traceLen++] = ((timestamp >> 24) & 0xff); + if (!bReader) { + trace[traceLen - 1] |= 0x80; + } + trace[traceLen++] = ((dwParity >> 0) & 0xff); + trace[traceLen++] = ((dwParity >> 8) & 0xff); + trace[traceLen++] = ((dwParity >> 16) & 0xff); + trace[traceLen++] = ((dwParity >> 24) & 0xff); + trace[traceLen++] = iLen; + if (btBytes != NULL && iLen != 0) { + memcpy(trace + traceLen, btBytes, iLen); + } + traceLen += iLen; + return TRUE; } - //============================================================================= // ISO 14443 Type A - Miller decoder //============================================================================= // Basics: // This decoder is used when the PM3 acts as a tag. -// The reader will generate "pauses" by temporarily switching of the field. -// At the PM3 antenna we will therefore measure a modulated antenna voltage. +// The reader will generate "pauses" by temporarily switching of the field. +// At the PM3 antenna we will therefore measure a modulated antenna voltage. // The FPGA does a comparison with a threshold and would deliver e.g.: // ........ 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 ....... // The Miller decoder needs to identify the following sequences: -// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") -// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") -// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") +// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") +// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") +// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: the interpretation of Sequence Y and Z depends on the preceding sequence. //----------------------------------------------------------------------------- static tUart Uart; // Lookup-Table to decide if 4 raw bits are a modulation. -// We accept the following: -// 0001 - a 3 tick wide pause -// 0011 - a 2 tick wide pause, or a three tick wide pause shifted left -// 0111 - a 2 tick wide pause shifted left -// 1001 - a 2 tick wide pause shifted right +// We accept two or three consecutive "0" in any position with the rest "1" const bool Mod_Miller_LUT[] = { - false, true, false, true, false, false, false, true, - false, true, false, false, false, false, false, false + TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, + TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }; -#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x000000F0) >> 4]) -#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x0000000F)]) +#define IsMillerModulationNibble1(b) (Mod_Miller_LUT[(b & 0x00F0) >> 4]) +#define IsMillerModulationNibble2(b) (Mod_Miller_LUT[(b & 0x000F)]) -static void UartReset() { +void UartReset() +{ Uart.state = STATE_UNSYNCD; Uart.bitCount = 0; - Uart.len = 0; // number of decoded data bytes - Uart.parityLen = 0; // number of decoded parity bytes - Uart.shiftReg = 0; // shiftreg to hold decoded data bits - Uart.parityBits = 0; // holds 8 parity bits -} - -static void UartInit(uint8_t *data, uint8_t *parity) { - Uart.output = data; - Uart.parity = parity; - Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.len = 0; // number of decoded data bytes + Uart.shiftReg = 0; // shiftreg to hold decoded data bits + Uart.parityBits = 0; // + Uart.twoBits = 0x0000; // buffer for 2 Bits + Uart.highCnt = 0; Uart.startTime = 0; Uart.endTime = 0; - UartReset(); } + // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time -static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { +static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) +{ - Uart.fourBits = (Uart.fourBits << 8) | bit; - - if (Uart.state == STATE_UNSYNCD) { // not yet synced - - Uart.syncBit = 9999; // not set - // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from - // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111) - // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern - // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) - #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 - #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 - if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 3)) == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 4)) == ISO14443A_STARTBIT_PATTERN >> 4) Uart.syncBit = 3; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 5)) == ISO14443A_STARTBIT_PATTERN >> 5) Uart.syncBit = 2; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 6)) == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; - else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 7)) == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; - - if (Uart.syncBit != 9999) { // found a sync bit - Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); - Uart.startTime -= Uart.syncBit; - Uart.endTime = Uart.startTime; - Uart.state = STATE_START_OF_COMMUNICATION; - LED_B_ON(); + Uart.twoBits = (Uart.twoBits << 8) | bit; + + if (Uart.state == STATE_UNSYNCD) { // not yet synced + if (Uart.highCnt < 7) { // wait for a stable unmodulated signal + if (Uart.twoBits == 0xffff) { + Uart.highCnt++; + } else { + Uart.highCnt = 0; + } + } else { + Uart.syncBit = 0xFFFF; // not set + // look for 00xx1111 (the start bit) + if ((Uart.twoBits & 0x6780) == 0x0780) Uart.syncBit = 7; + else if ((Uart.twoBits & 0x33C0) == 0x03C0) Uart.syncBit = 6; + else if ((Uart.twoBits & 0x19E0) == 0x01E0) Uart.syncBit = 5; + else if ((Uart.twoBits & 0x0CF0) == 0x00F0) Uart.syncBit = 4; + else if ((Uart.twoBits & 0x0678) == 0x0078) Uart.syncBit = 3; + else if ((Uart.twoBits & 0x033C) == 0x003C) Uart.syncBit = 2; + else if ((Uart.twoBits & 0x019E) == 0x001E) Uart.syncBit = 1; + else if ((Uart.twoBits & 0x00CF) == 0x000F) Uart.syncBit = 0; + if (Uart.syncBit != 0xFFFF) { + Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); + Uart.startTime -= Uart.syncBit; + Uart.endTime = Uart.startTime; + Uart.state = STATE_START_OF_COMMUNICATION; + } } } else { - if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error - LED_B_OFF(); + if (IsMillerModulationNibble1(Uart.twoBits >> Uart.syncBit)) { + if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) { // Modulation in both halves - error UartReset(); - } else { // Modulation in first half = Sequence Z = logic "0" - if (Uart.state == STATE_MILLER_X) { // error - must not follow after X - LED_B_OFF(); + Uart.highCnt = 6; + } else { // Modulation in first half = Sequence Z = logic "0" + if (Uart.state == STATE_MILLER_X) { // error - must not follow after X UartReset(); + Uart.highCnt = 6; } else { Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg Uart.state = STATE_MILLER_Z; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 6; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits - Uart.parityBits = 0; - } } } } } else { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" + if (IsMillerModulationNibble2(Uart.twoBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg Uart.state = STATE_MILLER_X; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 2; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the new parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the new parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits - Uart.parityBits = 0; - } } - } else { // no modulation in both halves - Sequence Y - if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication - LED_B_OFF(); + } else { // no modulation in both halves - Sequence Y + if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication Uart.state = STATE_UNSYNCD; - Uart.bitCount--; // last "0" was part of EOC sequence - Uart.shiftReg <<= 1; // drop it - if(Uart.bitCount > 0) { // if we decoded some bits - Uart.shiftReg >>= (9 - Uart.bitCount); // right align them - Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output - Uart.parityBits <<= 1; // add a (void) parity bit - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it - return true; - } else if (Uart.len & 0x0007) { // there are some parity bits to store - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them - } - if (Uart.len) { - return true; // we are finished with decoding the raw data sequence - } else { - UartReset(); // Nothing received - start over - } - } - if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC - LED_B_OFF(); - UartReset(); - } else { // a logic "0" - Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg - Uart.state = STATE_MILLER_Y; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.len == 0 && Uart.bitCount > 0) { // if we decoded some bits + Uart.shiftReg >>= (9 - Uart.bitCount); // add them to the output Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // no parity bit - add "0" + Uart.bitCount--; // last "0" was part of the EOC sequence + } + return TRUE; + } + if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC + UartReset(); + Uart.highCnt = 6; + } else { // a logic "0" + Uart.bitCount++; + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.state = STATE_MILLER_Y; + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits - Uart.parityBits = 0; - } } } } } + + } - } - - return false; // not finished yet, need more data + return FALSE; // not finished yet, need more data } @@ -427,10 +373,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { // at the reader antenna will be modulated as well. The FPGA detects the modulation for us and would deliver e.g. the following: // ........ 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ....... // The Manchester decoder needs to identify the following sequences: -// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") -// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 -// 8 ticks unmodulated: Sequence F = end of communication -// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D +// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") +// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 +// 8 ticks unmodulated: Sequence F = end of communication +// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: parameter offset is used to determine the position of the parity bits (required for the anticollision command only) static tDemod Demod; @@ -438,49 +384,44 @@ static tDemod Demod; // Lookup-Table to decide if 4 raw bits are a modulation. // We accept three or four "1" in any position const bool Mod_Manchester_LUT[] = { - false, false, false, false, false, false, false, true, - false, false, false, true, false, true, true, true + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, + FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE }; #define IsManchesterModulationNibble1(b) (Mod_Manchester_LUT[(b & 0x00F0) >> 4]) #define IsManchesterModulationNibble2(b) (Mod_Manchester_LUT[(b & 0x000F)]) -static void DemodReset() { +void DemodReset() +{ Demod.state = DEMOD_UNSYNCD; - Demod.len = 0; // number of decoded data bytes - Demod.parityLen = 0; - Demod.shiftReg = 0; // shiftreg to hold decoded data bits - Demod.parityBits = 0; // - Demod.collisionPos = 0; // Position of collision bit - Demod.twoBits = 0xffff; // buffer for 2 Bits + Demod.len = 0; // number of decoded data bytes + Demod.shiftReg = 0; // shiftreg to hold decoded data bits + Demod.parityBits = 0; // + Demod.collisionPos = 0; // Position of collision bit + Demod.twoBits = 0xffff; // buffer for 2 Bits Demod.highCnt = 0; Demod.startTime = 0; Demod.endTime = 0; } -static void DemodInit(uint8_t *data, uint8_t *parity) { - Demod.output = data; - Demod.parity = parity; - DemodReset(); -} - // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time -static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time) { +static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time) +{ Demod.twoBits = (Demod.twoBits << 8) | bit; - + if (Demod.state == DEMOD_UNSYNCD) { - if (Demod.highCnt < 2) { // wait for a stable unmodulated signal + if (Demod.highCnt < 2) { // wait for a stable unmodulated signal if (Demod.twoBits == 0x0000) { Demod.highCnt++; } else { Demod.highCnt = 0; } } else { - Demod.syncBit = 0xFFFF; // not set - if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; + Demod.syncBit = 0xFFFF; // not set + if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; else if ((Demod.twoBits & 0x3B80) == 0x3800) Demod.syncBit = 6; else if ((Demod.twoBits & 0x1DC0) == 0x1C00) Demod.syncBit = 5; else if ((Demod.twoBits & 0x0EE0) == 0x0E00) Demod.syncBit = 4; @@ -491,74 +432,59 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non if (Demod.syncBit != 0xFFFF) { Demod.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Demod.startTime -= Demod.syncBit; - Demod.bitCount = offset; // number of decoded data bits + Demod.bitCount = offset; // number of decoded data bits Demod.state = DEMOD_MANCHESTER_DATA; - LED_C_ON(); } } } else { - if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision + if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision if (!Demod.collisionPos) { Demod.collisionPos = (Demod.len << 3) + Demod.bitCount; } - } // modulation in first half only - Sequence D = 1 + } // modulation in first half only - Sequence D = 1 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg - if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg + if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the parity bit - Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit + Demod.parityBits <<= 1; // make room for the parity bit + Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits - Demod.parityBits = 0; - } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1) - 4; - } else { // no modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 + } else { // no modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg - if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg + if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the new parity bit + Demod.parityBits <<= 1; // make room for the new parity bit Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if ((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 - Demod.parityBits = 0; - } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); - } else { // no modulation in both halves - End of communication - LED_C_OFF(); - if(Demod.bitCount > 0) { // there are some remaining data bits - Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits - Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output - Demod.parityBits <<= 1; // add a (void) parity bit - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them - return true; - } else if (Demod.len & 0x0007) { // there are some parity bits to store - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them - } - if (Demod.len) { - return true; // we are finished with decoding the raw data sequence - } else { // nothing received. Start over + } else { // no modulation in both halves - End of communication + if (Demod.len > 0 || Demod.bitCount > 0) { // received something + if(Demod.bitCount > 0) { // if we decoded bits + Demod.shiftReg >>= (9 - Demod.bitCount); // add the remaining decoded bits to the output + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; + // No parity bit, so just shift a 0 + Demod.parityBits <<= 1; + } + return TRUE; // we are finished with decoding the raw data sequence + } else { // nothing received. Start over DemodReset(); } } } + + } - } - - return false; // not finished yet, need more data + return FALSE; // not finished yet, need more data } //============================================================================= @@ -575,61 +501,57 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // param: // bit 0 - trigger from first card answer // bit 1 - trigger from first reader 7-bit request - + LEDsoff(); - LED_A_ON(); - - iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); - - // The command (reader -> tag) that we're receiving. - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); - - // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedResponsePar = BigBuf_malloc(MAX_PARITY_SIZE); - - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - // init trace buffer - clear_trace(); - set_tracing(true); - - uint8_t *data = dmaBuf; - uint8_t previous_data = 0; - int maxDataLen = 0; - int dataLen = 0; - bool TagIsActive = false; - bool ReaderIsActive = false; - - // Set up the demodulator for tag -> reader responses. - DemodInit(receivedResponse, receivedResponsePar); - - // Set up the demodulator for the reader -> tag commands - UartInit(receivedCmd, receivedCmdPar); - - // Setup and start DMA. - FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); + iso14a_clear_trace(); // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a // response from the tag. - // triggered == false -- to wait first for card - bool triggered = !(param & 0x03); + // triggered == FALSE -- to wait first for card + bool triggered = !(param & 0x03); + + // The command (reader -> tag) that we're receiving. + // The length of a received command will in most cases be no more than 18 bytes. + // So 32 should be enough! + uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); + // The response (tag -> reader) that we're receiving. + uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); + // As we receive stuff, we copy it from receivedCmd or receivedResponse + // into trace, along with its length and other annotations. + //uint8_t *trace = (uint8_t *)BigBuf; + + // The DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = ((uint8_t *)BigBuf) + DMA_BUFFER_OFFSET; + uint8_t *data = dmaBuf; + uint8_t previous_data = 0; + int maxDataLen = 0; + int dataLen = 0; + bool TagIsActive = FALSE; + bool ReaderIsActive = FALSE; + + iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); + + // Set up the demodulator for tag -> reader responses. + Demod.output = receivedResponse; + + // Set up the demodulator for the reader -> tag commands + Uart.output = receivedCmd; + + // Setup and start DMA. + FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); + // And now we loop, receiving samples. - for (uint32_t rsamples = 0; true; ) { + for(uint32_t rsamples = 0; TRUE; ) { - if (BUTTON_PRESS()) { + if(BUTTON_PRESS()) { DbpString("cancelled by button"); break; } + LED_A_ON(); WDT_HIT(); int register readBufDataP = data - dmaBuf; @@ -642,7 +564,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // test for length of buffer if(dataLen > maxDataLen) { maxDataLen = dataLen; - if(dataLen > (9 * DMA_BUFFER_SIZE / 10)) { + if(dataLen > 400) { Dbprintf("blew circular buffer! dataLen=%d", dataLen); break; } @@ -661,47 +583,46 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder + LED_A_OFF(); + + if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder - if(!TagIsActive) { // no need to try decoding reader data if the tag is sending + if(!TagIsActive) { // no need to try decoding reader data if the tag is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if (MillerDecoding(readerdata, (rsamples-1)*4)) { + LED_C_ON(); + // check - if there is a short 7bit request from reader - if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) { - triggered = true; - } + if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = TRUE; + if(triggered) { - if (!LogTrace(receivedCmd, - Uart.len, - Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.parity, - true)) break; + if (!LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, Uart.parityBits, TRUE)) break; + if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break; } /* And ready to receive another command. */ UartReset(); /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ DemodReset(); + LED_B_OFF(); } ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); - if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { - if (!LogTrace(receivedResponse, - Demod.len, - Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, - Demod.parity, - false)) break; - if ((!triggered) && (param & 0x01)) triggered = true; + if(ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { + LED_B_ON(); + + if (!LogTrace(receivedResponse, Demod.len, Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.parityBits, FALSE)) break; + if (!LogTrace(NULL, 0, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, 0, FALSE)) break; + + if ((!triggered) && (param & 0x01)) triggered = TRUE; + // And ready to receive another response. DemodReset(); - // And reset the Miller decoder including itS (now outdated) input buffer - UartInit(receivedCmd, receivedCmdPar); - } + LED_C_OFF(); + } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } } @@ -714,18 +635,21 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { } } // main cycle - FpgaDisableSscDma(); - LEDsoff(); - DbpString("COMMAND FINISHED"); + + FpgaDisableSscDma(); Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); - Dbprintf("traceLen=%d, Uart.output[0]=%08x", BigBuf_get_traceLen(), (uint32_t)Uart.output[0]); + Dbprintf("traceLen=%d, Uart.output[0]=%08x", traceLen, (uint32_t)Uart.output[0]); + LEDsoff(); } //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *parity) { +static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity) +{ + int i; + ToSendReset(); // Correction bit, might be removed when not needed @@ -737,16 +661,17 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); - + // Send startbit ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; - for (uint16_t i = 0; i < len; i++) { + for(i = 0; i < len; i++) { + int j; uint8_t b = cmd[i]; // Data bits - for (uint16_t j = 0; j < 8; j++) { + for(j = 0; j < 8; j++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; } else { @@ -756,7 +681,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par } // Get the parity bit - if (parity[i>>3] & (0x80>>(i&0x0007))) { + if ((dwParity >> i) & 0x01) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; } else { @@ -772,8 +697,13 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendMax++; } +static void CodeIso14443aAsTag(const uint8_t *cmd, int len){ + CodeIso14443aAsTagPar(cmd, len, GetParity(cmd, len)); +} -static void Code4bitAnswerAsTag(uint8_t cmd) { + +static void Code4bitAnswerAsTag(uint8_t cmd) +{ int i; ToSendReset(); @@ -792,7 +722,7 @@ static void Code4bitAnswerAsTag(uint8_t cmd) { ToSend[++ToSendMax] = SEC_D; uint8_t b = cmd; - for (i = 0; i < 4; i++) { + for(i = 0; i < 4; i++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; @@ -810,80 +740,67 @@ static void Code4bitAnswerAsTag(uint8_t cmd) { ToSendMax++; } - -static uint8_t *LastReaderTraceTime = NULL; - -static void EmLogTraceReader(void) { - // remember last reader trace start to fix timing info later - LastReaderTraceTime = BigBuf_get_addr() + BigBuf_get_traceLen(); - LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); -} - - -static void FixLastReaderTraceTime(uint32_t tag_StartTime) { - uint32_t reader_EndTime = Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG; - uint32_t reader_StartTime = Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG; - uint16_t reader_modlen = reader_EndTime - reader_StartTime; - uint16_t approx_fdt = tag_StartTime - reader_EndTime; - uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; - reader_StartTime = tag_StartTime - exact_fdt - reader_modlen; - LastReaderTraceTime[0] = (reader_StartTime >> 0) & 0xff; - LastReaderTraceTime[1] = (reader_StartTime >> 8) & 0xff; - LastReaderTraceTime[2] = (reader_StartTime >> 16) & 0xff; - LastReaderTraceTime[3] = (reader_StartTime >> 24) & 0xff; -} - - -static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Parity, uint32_t ProxToAirDuration) { - uint32_t tag_StartTime = LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG; - uint32_t tag_EndTime = (LastTimeProxToAirStart + ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG; - LogTrace(tag_data, tag_len, tag_StartTime, tag_EndTime, tag_Parity, false); - FixLastReaderTraceTime(tag_StartTime); -} - - //----------------------------------------------------------------------------- // Wait for commands from reader // Stop when button is pressed -// Or return true when command is captured +// Or return TRUE when command is captured //----------------------------------------------------------------------------- -static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) { - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); +static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen) +{ + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Now run a `software UART' on the stream of incoming samples. - UartInit(received, parity); + // Now run a `software UART' on the stream of incoming samples. + UartReset(); + Uart.output = received; // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - for (;;) { - WDT_HIT(); + for(;;) { + WDT_HIT(); - if(BUTTON_PRESS()) return false; - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(BUTTON_PRESS()) return FALSE; + + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; if(MillerDecoding(b, 0)) { *len = Uart.len; - EmLogTraceReader(); - return true; + return TRUE; } - } - } + } + } } - +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, bool correctionNeeded); +int EmSend4bitEx(uint8_t resp, bool correctionNeeded); int EmSend4bit(uint8_t resp); -static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par); -int EmSendCmd(uint8_t *resp, uint16_t respLen); -int EmSendPrecompiledCmd(tag_response_info_t *response_info); +int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par); +int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par); +int EmSendCmdEx(uint8_t *resp, int respLen, bool correctionNeeded); +int EmSendCmd(uint8_t *resp, int respLen); +int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par); +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint32_t reader_Parity, + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint32_t tag_Parity); +static uint8_t* free_buffer_pointer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); -static bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffer_size) { +typedef struct { + uint8_t* response; + size_t response_n; + uint8_t* modulation; + size_t modulation_n; + uint32_t ProxToAirDuration; +} tag_response_info_t; + +void reset_free_buffer() { + free_buffer_pointer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); +} + +bool prepare_tag_modulation(tag_response_info_t* response_info, size_t max_buffer_size) { // Example response, answer to MIFARE Classic read block will be 16 bytes + 2 CRC = 18 bytes // This will need the following byte array for a modulation sequence // 144 data bits (18 * 8) @@ -894,49 +811,41 @@ static bool prepare_tag_modulation(tag_response_info_t* response_info, size_t ma // ----------- + // 166 bytes, since every bit that needs to be send costs us a byte // - - + // Prepare the tag modulation bits from the message - GetParity(response_info->response, response_info->response_n, &(response_info->par)); - CodeIso14443aAsTagPar(response_info->response,response_info->response_n, &(response_info->par)); - + CodeIso14443aAsTag(response_info->response,response_info->response_n); + // Make sure we do not exceed the free buffer space if (ToSendMax > max_buffer_size) { - Dbprintf("Out of memory, when modulating bits for tag answer:"); - Dbhexdump(response_info->response_n, response_info->response, false); - return false; + Dbprintf("Out of memory, when modulating bits for tag answer:"); + Dbhexdump(response_info->response_n,response_info->response,false); + return false; } - + // Copy the byte array, used for this modulation to the buffer position - memcpy(response_info->modulation, ToSend, ToSendMax); - + memcpy(response_info->modulation,ToSend,ToSendMax); + // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them response_info->modulation_n = ToSendMax; response_info->ProxToAirDuration = LastProxToAirDuration; - + return true; } - -// "precompile" responses. There are 7 predefined responses with a total of 28 bytes data to transmit. -// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) -// 28 * 8 data bits, 28 * 1 parity bits, 7 start bits, 7 stop bits, 7 correction bits for the modulation -// -> need 273 bytes buffer -#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 273 - -bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_t **buffer, size_t *max_buffer_size) { - +bool prepare_allocated_tag_modulation(tag_response_info_t* response_info) { // Retrieve and store the current buffer index - response_info->modulation = *buffer; - + response_info->modulation = free_buffer_pointer; + + // Determine the maximum size we can use from our buffer + size_t max_buffer_size = (((uint8_t *)BigBuf)+FREE_BUFFER_OFFSET+FREE_BUFFER_SIZE)-free_buffer_pointer; + // Forward the prepare tag modulation function to the inner function - if (prepare_tag_modulation(response_info, *max_buffer_size)) { - // Update the free buffer offset and the remaining buffer size - *buffer += ToSendMax; - *max_buffer_size -= ToSendMax; - return true; + if (prepare_tag_modulation(response_info,max_buffer_size)) { + // Update the free buffer offset + free_buffer_pointer += ToSendMax; + return true; } else { - return false; + return false; } } @@ -944,13 +853,17 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_ // Main loop of simulated tag: receive commands from reader, decide what // response to send, and send it. //----------------------------------------------------------------------------- -void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) { +void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) +{ + // Enable and clear the trace + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); uint8_t sak; // The first response contains the ATQA (note: bytes are transmitted in reverse order). uint8_t response1[2]; - + switch (tagType) { case 1: { // MIFARE Classic // Says: I am Mifare 1k - original line @@ -976,24 +889,17 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) response1[1] = 0x00; sak = 0x28; } break; - case 5: { // MIFARE TNP3XXX - // Says: I am a toy - response1[0] = 0x01; - response1[1] = 0x0f; - sak = 0x01; - } break; default: { Dbprintf("Error: unkown tagtype (%d)",tagType); return; } break; } - + // The second response contains the (mandatory) first 24 bits of the UID - uint8_t response2[5] = {0x00}; + uint8_t response2[5]; // Check if the uid uses the (optional) part - uint8_t response2a[5] = {0x00}; - + uint8_t response2a[5]; if (uid_2nd) { response2[0] = 0x88; num_to_bytes(uid_1st,3,response2+1); @@ -1014,21 +920,17 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) response2[4] = response2[0] ^ response2[1] ^ response2[2] ^ response2[3]; // Prepare the mandatory SAK (for 4 and 7 byte UID) - uint8_t response3[3] = {0x00}; + uint8_t response3[3]; response3[0] = sak; ComputeCrc14443(CRC_14443_A, response3, 1, &response3[1], &response3[2]); // Prepare the optional second SAK (for 7 byte UID), drop the cascade bit - uint8_t response3a[3] = {0x00}; + uint8_t response3a[3]; response3a[0] = sak & 0xFB; ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce - uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: - // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, - // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 - // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) - // TC(1) = 0x02: CID supported, NAD not supported + uint8_t response6[] = { 0x04, 0x58, 0x00, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS ComputeCrc14443(CRC_14443_A, response6, 4, &response6[4], &response6[5]); #define TAG_RESPONSE_COUNT 7 @@ -1054,27 +956,17 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) .modulation = dynamic_modulation_buffer, .modulation_n = 0 }; - - // We need to listen to the high-frequency, peak-detected path. - iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); - - BigBuf_free_keep_EM(); - - // allocate buffers: - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); - uint8_t *free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); - size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; - // clear trace - clear_trace(); - set_tracing(true); - + + // Reset the offset pointer of the free buffer + reset_free_buffer(); + // Prepare the responses of the anticollision phase // there will be not enough time to do this at the moment the reader sends it REQA for (size_t i=0; i 0) { // Copy the CID from the reader query dynamic_response_info.response[1] = receivedCmd[1]; @@ -1185,9 +1095,13 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) // Add CRC bytes, always used in ISO 14443A-4 compliant cards AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n); dynamic_response_info.response_n += 2; - + if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { Dbprintf("Error preparing tag response"); + if (tracing) { + LogTrace(receivedCmd, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + } break; } p_response = &dynamic_response_info; @@ -1207,10 +1121,21 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) cmdsRecvd++; if (p_response != NULL) { - EmSendPrecompiledCmd(p_response); + EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n, receivedCmd[0] == 0x52); + // do the tracing for the previous reader request and this tag answer: + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.parityBits, + p_response->response, + p_response->response_n, + LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + p_response->ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, + SwapBits(GetParity(p_response->response, p_response->response_n), p_response->response_n)); } - - if (!get_tracing()) { + + if (!tracing) { Dbprintf("Trace Full. Simulation stopped."); break; } @@ -1218,17 +1143,17 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); LED_A_OFF(); - BigBuf_free_keep_EM(); } // prepare a delayed transfer. This simply shifts ToSend[] by a number // of bits specified in the delay parameter. -static void PrepareDelayedTransfer(uint16_t delay) { +void PrepareDelayedTransfer(uint16_t delay) +{ uint8_t bitmask = 0; uint8_t bits_to_shift = 0; uint8_t bits_shifted = 0; - + delay &= 0x07; if (delay) { for (uint16_t i = 0; i < delay; i++) { @@ -1249,35 +1174,45 @@ static void PrepareDelayedTransfer(uint16_t delay) { // Transmit the command (to the tag) that was placed in ToSend[]. // Parameter timing: // if NULL: transfer at next possible time, taking into account -// request guard time, startup frame guard time and frame delay time -// if == 0: transfer immediately and return time of transfer +// request guard time and frame delay time +// if == 0: transfer immediately and return time of transfer // if != 0: delay transfer until time specified //------------------------------------------------------------------------------------- -static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { - LED_B_ON(); - LED_D_ON(); +static void TransmitFor14443a(const uint8_t *cmd, int len, uint32_t *timing) +{ + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); uint32_t ThisTransferTime = 0; if (timing) { - if (*timing == 0) { // Measure time + if(*timing == 0) { // Measure time *timing = (GetCountSspClk() + 8) & 0xfffffff8; } else { - PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) + PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) } - if (MF_DBGLEVEL >= 4 && GetCountSspClk() >= (*timing & 0xfffffff8)) Dbprintf("TransmitFor14443a: Missed timing"); - while (GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) + if(MF_DBGLEVEL >= 4 && GetCountSspClk() >= (*timing & 0xfffffff8)) Dbprintf("TransmitFor14443a: Missed timing"); + while(GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) LastTimeProxToAirStart = *timing; } else { ThisTransferTime = ((MAX(NextTransferTime, GetCountSspClk()) & 0xfffffff8) + 8); - while (GetCountSspClk() < ThisTransferTime); + while(GetCountSspClk() < ThisTransferTime); LastTimeProxToAirStart = ThisTransferTime; } + + // clear TXRDY + AT91C_BASE_SSC->SSC_THR = SEC_Y; + + // for(uint16_t c = 0; c < 10;) { // standard delay for each transfer (allow tag to be ready after last transmission) + // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + // AT91C_BASE_SSC->SSC_THR = SEC_Y; + // c++; + // } + // } uint16_t c = 0; - for (;;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = cmd[c]; c++; if(c >= len) { @@ -1285,16 +1220,17 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing } } } - + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); - LED_B_OFF(); + } //----------------------------------------------------------------------------- // Prepare reader command (in bits, support short frames) to send to FPGA //----------------------------------------------------------------------------- -static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, const uint8_t *parity) { +void CodeIso14443aBitsAsReaderPar(const uint8_t * cmd, int bits, uint32_t dwParity) +{ int i, j; int last; uint8_t b; @@ -1333,10 +1269,10 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons b >>= 1; } - // Only transmit parity bit if we transmitted a complete byte - if (j == 8 && parity != NULL) { + // Only transmit (last) parity bit if we transmitted a complete byte + if (j == 8) { // Get the parity bit - if (parity[i>>3] & (0x80 >> (i&0x0007))) { + if ((dwParity >> i) & 0x01) { // Sequence X ToSend[++ToSendMax] = SEC_X; LastProxToAirDuration = 8 * (ToSendMax+1) - 2; @@ -1371,509 +1307,464 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons ToSendMax++; } +//----------------------------------------------------------------------------- +// Prepare reader command to send to FPGA +//----------------------------------------------------------------------------- +void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) +{ + CodeIso14443aBitsAsReaderPar(cmd,len*8,dwParity); +} //----------------------------------------------------------------------------- // Wait for commands from reader // Stop when button is pressed (return 1) or field was gone (return 2) // Or return 0 when command is captured //----------------------------------------------------------------------------- -int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) { - uint32_t field_off_time = -1; - uint32_t samples = 0; - int ret = 0; - uint8_t b = 0;; - uint8_t dmaBuf[DMA_BUFFER_SIZE]; - uint8_t *upTo = dmaBuf; - +static int EmGetCmd(uint8_t *received, int *len) +{ *len = 0; - // Run a 'software UART' on the stream of incoming samples. - UartInit(received, parity); - - // start ADC - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - - // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN - while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3) - 8 - 3) /* wait */ ; + uint32_t timer = 0, vtime = 0; + int analogCnt = 0; + int analogAVG = 0; // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // clear receive register, measure time of next transfer - uint32_t temp = AT91C_BASE_SSC->SSC_RHR; (void) temp; - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; - uint32_t start_time = GetCountSspClk() & 0xfffffff8; + // Set ADC to read field strength + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(32) | + ADC_MODE_STARTUP_TIME(16) | + ADC_MODE_SAMPLE_HOLD_TIME(8); + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF); + // start ADC + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + + // Now run a 'software UART' on the stream of incoming samples. + UartReset(); + Uart.output = received; - // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE); + // Clear RXRDY: + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; for(;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE-1); + WDT_HIT(); - if (behindBy == 0) continue; + if (BUTTON_PRESS()) return 1; - b = *upTo++; - - if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if(behindBy > (9*DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - ret = 1; - break; + // test if the field exists + 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 ((33000 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { + vtime = GetTickCount(); + if (!timer) timer = vtime; + // 50ms no field --> card to idle state + if (vtime - timer > 50) return 2; + } else + if (timer) timer = 0; + analogCnt = 0; + analogAVG = 0; } } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers - } - if (BUTTON_PRESS()) { - ret = 1; - break; - } - - // check reader's HF field - if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) { - if ((MAX_ADC_HF_VOLTAGE_LOW * AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]) >> 10 < MF_MINFIELDV) { - if (GetTickCount() - field_off_time > 50) { - ret = 2; // reader has switched off HF field for more than 50ms. Timeout - break; - } - } else { - field_off_time = GetTickCount(); // HF field is still there. Reset timer + // receive and test the miller decoding + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(MillerDecoding(b, 0)) { + *len = Uart.len; + return 0; } - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; // restart ADC - } + } - if (MillerDecoding(b, start_time + samples*8)) { - *len = Uart.len; - EmLogTraceReader(); - ret = 0; - break; - } - - samples++; } - - FpgaDisableSscDma(); - return ret; } -static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { - LED_C_ON(); - +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, bool correctionNeeded) +{ uint8_t b; uint16_t i = 0; - bool correctionNeeded; - + uint32_t ThisTransferTime; + // Modulate Manchester FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); // include correction bit if necessary - if (Uart.bitCount == 7) - { - // Short tags (7 bits) don't have parity, determine the correct value from MSB - correctionNeeded = Uart.output[0] & 0x40; + if (Uart.parityBits & 0x01) { + correctionNeeded = TRUE; } - else - { - // Look at the last parity bit - correctionNeeded = Uart.parity[(Uart.len-1)/8] & (0x80 >> ((Uart.len-1) & 7)); - } - - if (correctionNeeded) { + if(correctionNeeded) { // 1236, so correction bit needed i = 0; } else { i = 1; } - // clear receiving shift register and holding register + // clear receiving shift register and holding register + while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; - + // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) - for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never + while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); if (AT91C_BASE_SSC->SSC_RHR) break; } - LastTimeProxToAirStart = (GetCountSspClk() & 0xfffffff8) + (correctionNeeded?8:0); + while ((ThisTransferTime = GetCountSspClk()) & 0x00000007); + + // Clear TXRDY: + AT91C_BASE_SSC->SSC_THR = SEC_F; // send cycle - for (; i < respLen; ) { + for(; i <= respLen; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = resp[i++]; FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } - + if(BUTTON_PRESS()) { break; } } - LED_C_OFF(); + // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: + for (i = 0; i < 2 ; ) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = SEC_F; + FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + } + } + + LastTimeProxToAirStart = ThisTransferTime + (correctionNeeded?8:0); + return 0; } +int EmSend4bitEx(uint8_t resp, bool correctionNeeded){ + Code4bitAnswerAsTag(resp); + int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); + // do the tracing for the previous reader request and this tag answer: + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.parityBits, + &resp, + 1, + LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, + SwapBits(GetParity(&resp, 1), 1)); + return res; +} int EmSend4bit(uint8_t resp){ - Code4bitAnswerAsTag(resp); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // Log this tag answer and fix timing of previous reader command: - EmLogTraceTag(&resp, 1, NULL, LastProxToAirDuration); - return res; + return EmSend4bitEx(resp, false); } - -static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ +int EmSendCmdExPar(uint8_t *resp, int respLen, bool correctionNeeded, uint32_t par){ CodeIso14443aAsTagPar(resp, respLen, par); - int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // Log this tag answer and fix timing of previous reader command: - EmLogTraceTag(resp, respLen, par, LastProxToAirDuration); + int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); + // do the tracing for the previous reader request and this tag answer: + EmLogTrace(Uart.output, + Uart.len, + Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, + Uart.parityBits, + resp, + respLen, + LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG, + (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG, + SwapBits(GetParity(resp, respLen), respLen)); return res; } - -int EmSendCmd(uint8_t *resp, uint16_t respLen){ - uint8_t par[MAX_PARITY_SIZE]; - GetParity(resp, respLen, par); - return EmSendCmdExPar(resp, respLen, par); +int EmSendCmdEx(uint8_t *resp, int respLen, bool correctionNeeded){ + return EmSendCmdExPar(resp, respLen, correctionNeeded, GetParity(resp, respLen)); } - -int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ - return EmSendCmdExPar(resp, respLen, par); +int EmSendCmd(uint8_t *resp, int respLen){ + return EmSendCmdExPar(resp, respLen, false, GetParity(resp, respLen)); } - -int EmSendPrecompiledCmd(tag_response_info_t *response_info) { - int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n); - // Log this tag answer and fix timing of previous reader command: - EmLogTraceTag(response_info->response, response_info->response_n, &(response_info->par), response_info->ProxToAirDuration); - return ret; +int EmSendCmdPar(uint8_t *resp, int respLen, uint32_t par){ + return EmSendCmdExPar(resp, respLen, false, par); } +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint32_t reader_Parity, + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint32_t tag_Parity) +{ + if (tracing) { + // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from + // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. + // with n >= 9. The start of the tags answer can be measured and therefore the end of the received command be calculated: + uint16_t reader_modlen = reader_EndTime - reader_StartTime; + uint16_t approx_fdt = tag_StartTime - reader_EndTime; + uint16_t exact_fdt = (approx_fdt - 20 + 32)/64 * 64 + 20; + reader_EndTime = tag_StartTime - exact_fdt; + reader_StartTime = reader_EndTime - reader_modlen; + if (!LogTrace(reader_data, reader_len, reader_StartTime, reader_Parity, TRUE)) { + return FALSE; + } else if (!LogTrace(NULL, 0, reader_EndTime, 0, TRUE)) { + return FALSE; + } else if (!LogTrace(tag_data, tag_len, tag_StartTime, tag_Parity, FALSE)) { + return FALSE; + } else { + return (!LogTrace(NULL, 0, tag_EndTime, 0, FALSE)); + } + } else { + return TRUE; + } +} //----------------------------------------------------------------------------- // Wait a certain time for tag response -// If a response is captured return true -// If it takes too long return false +// If a response is captured return TRUE +// If it takes too long return FALSE //----------------------------------------------------------------------------- -static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { - uint32_t c; - +static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t offset, int maxLen) +{ + uint16_t c; + // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - + // Now get the answer from the card - DemodInit(receivedResponse, receivedResponsePar); + DemodReset(); + Demod.output = receivedResponse; // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + c = 0; - for (;;) { + for(;;) { WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if (ManchesterDecoding(b, offset, 0)) { + if(ManchesterDecoding(b, offset, 0)) { NextTransferTime = MAX(NextTransferTime, Demod.endTime - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/16 + FRAME_DELAY_TIME_PICC_TO_PCD); - return true; - } else if (c++ > iso14a_timeout && Demod.state == DEMOD_UNSYNCD) { - return false; + return TRUE; + } else if(c++ > iso14a_timeout) { + return FALSE; } } } } +void ReaderTransmitBitsPar(uint8_t* frame, int bits, uint32_t par, uint32_t *timing) +{ -void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { - - CodeIso14443aBitsAsReaderPar(frame, bits, par); - + CodeIso14443aBitsAsReaderPar(frame,bits,par); + // Send command to tag TransmitFor14443a(ToSend, ToSendMax, timing); - if (trigger) + if(trigger) LED_A_ON(); - + // Log reader command in trace buffer - LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true); + if (tracing) { + LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, par, TRUE); + LogTrace(NULL, 0, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, 0, TRUE); + } } - -void ReaderTransmitPar(uint8_t* frame, uint16_t len, uint8_t *par, uint32_t *timing) { - ReaderTransmitBitsPar(frame, len*8, par, timing); +void ReaderTransmitPar(uint8_t* frame, int len, uint32_t par, uint32_t *timing) +{ + ReaderTransmitBitsPar(frame,len*8,par, timing); } - -static void ReaderTransmitBits(uint8_t* frame, uint16_t len, uint32_t *timing) { +void ReaderTransmitBits(uint8_t* frame, int len, uint32_t *timing) +{ // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len/8, par); - ReaderTransmitBitsPar(frame, len, par, timing); + ReaderTransmitBitsPar(frame,len,GetParity(frame,len/8), timing); } - -void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) { +void ReaderTransmit(uint8_t* frame, int len, uint32_t *timing) +{ // Generate parity and redirect - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len, par); - ReaderTransmitBitsPar(frame, len*8, par, timing); + ReaderTransmitBitsPar(frame,len*8,GetParity(frame,len), timing); } - -static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity) { - if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, offset)) return false; - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); +int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset) +{ + if (!GetIso14443aAnswerFromTag(receivedAnswer,offset,160)) return FALSE; + if (tracing) { + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.parityBits, FALSE); + LogTrace(NULL, 0, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, 0, FALSE); + } return Demod.len; } +int ReaderReceive(uint8_t* receivedAnswer) +{ + return ReaderReceiveOffset(receivedAnswer, 0); +} -int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) { - if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return false; - - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); +int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr) +{ + if (!GetIso14443aAnswerFromTag(receivedAnswer,0,160)) return FALSE; + if (tracing) { + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.parityBits, FALSE); + LogTrace(NULL, 0, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, 0, FALSE); + } + *parptr = Demod.parityBits; return Demod.len; } +/* performs iso14443a anticollision procedure + * fills the uid pointer unless NULL + * fills resp_data unless NULL */ +int iso14443a_select_card(byte_t* uid_ptr, iso14a_card_select_t* p_hi14a_card, uint32_t* cuid_ptr) { + uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP + uint8_t sel_all[] = { 0x93,0x20 }; + uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 + uint8_t* resp = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); // was 3560 - tied to other size changes + byte_t uid_resp[4]; + size_t uid_resp_len; -static void iso14a_set_ATS_times(uint8_t *ats) { + uint8_t sak = 0x04; // cascade uid + int cascade_level = 0; + int len; + + // Broadcast for a card, WUPA (0x52) will force response from all cards in the field + ReaderTransmitBitsPar(wupa,7,0, NULL); + + // Receive the ATQA + if(!ReaderReceive(resp)) return 0; + // Dbprintf("atqa: %02x %02x",resp[0],resp[1]); - uint8_t tb1; - uint8_t fwi, sfgi; - uint32_t fwt, sfgt; + if(p_hi14a_card) { + memcpy(p_hi14a_card->atqa, resp, 2); + p_hi14a_card->uidlen = 0; + memset(p_hi14a_card->uid,0,10); + } - if (ats[0] > 1) { // there is a format byte T0 - if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) - if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) - tb1 = ats[3]; - } else { - tb1 = ats[2]; + // clear uid + if (uid_ptr) { + memset(uid_ptr,0,10); + } + + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in + // which case we need to make a cascade 2 request and select - this is a long UID + // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. + for(; sak & 0x04; cascade_level++) { + // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) + sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; + + // SELECT_ALL + ReaderTransmit(sel_all,sizeof(sel_all), NULL); + if (!ReaderReceive(resp)) return 0; + + if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit + memset(uid_resp, 0, 4); + uint16_t uid_resp_bits = 0; + uint16_t collision_answer_offset = 0; + // anti-collision-loop: + while (Demod.collisionPos) { + Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); + for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point + uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; + uid_resp[uid_resp_bits & 0xf8] |= UIDbit << (uid_resp_bits % 8); } - fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) - if (fwi != 15) { - fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc - iso14a_set_timeout(fwt/(8*16)); - } - sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) - if (sfgi != 0 && sfgi != 15) { - sfgt = 256 * 16 * (1 << sfgi); // startup frame guard time (SFGT) in 1/fc - NextTransferTime = MAX(NextTransferTime, Demod.endTime + (sfgt - DELAY_AIR2ARM_AS_READER - DELAY_ARM2AIR_AS_READER)/16); + uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position + uid_resp_bits++; + // construct anticollosion command: + sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits + for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { + sel_uid[2+i] = uid_resp[i]; } + collision_answer_offset = uid_resp_bits%8; + ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); + if (!ReaderReceiveOffset(resp, collision_answer_offset)) return 0; } + // finally, add the last bits and BCC of the UID + for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { + uint16_t UIDbit = (resp[i/8] >> (i%8)) & 0x01; + uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); + } + + } else { // no collision, use the response to SELECT_ALL as current uid + memcpy(uid_resp,resp,4); } + uid_resp_len = 4; + // Dbprintf("uid: %02x %02x %02x %02x",uid_resp[0],uid_resp[1],uid_resp[2],uid_resp[3]); + + // calculate crypto UID. Always use last 4 Bytes. + if(cuid_ptr) { + *cuid_ptr = bytes_to_num(uid_resp, 4); + } + + // Construct SELECT UID command + sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) + memcpy(sel_uid+2,uid_resp,4); // the UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + AppendCrc14443a(sel_uid,7); // calculate and add CRC + ReaderTransmit(sel_uid,sizeof(sel_uid), NULL); + + // Receive the SAK + if (!ReaderReceive(resp)) return 0; + sak = resp[0]; + + // Test if more parts of the uid are comming + if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { + // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: + // http://www.nxp.com/documents/application_note/AN10927.pdf + memcpy(uid_resp, uid_resp + 1, 3); + uid_resp_len = 3; + } + + if(uid_ptr) { + memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); + } + + if(p_hi14a_card) { + memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); + p_hi14a_card->uidlen += uid_resp_len; + } + } + + if(p_hi14a_card) { + p_hi14a_card->sak = sak; + p_hi14a_card->ats_len = 0; + } + + if( (sak & 0x20) == 0) { + return 2; // non iso14443a compliant tag + } + + // Request for answer to select + AppendCrc14443a(rats, 2); + ReaderTransmit(rats, sizeof(rats), NULL); + + if (!(len = ReaderReceive(resp))) return 0; + + if(p_hi14a_card) { + memcpy(p_hi14a_card->ats, resp, sizeof(p_hi14a_card->ats)); + p_hi14a_card->ats_len = len; + } + + // reset the PCB block number + iso14_pcb_blocknum = 0; + return 1; } - -static int GetATQA(uint8_t *resp, uint8_t *resp_par) { - -#define WUPA_RETRY_TIMEOUT 10 // 10ms - uint8_t wupa[] = {ISO14443A_CMD_WUPA}; // 0x26 - REQA 0x52 - WAKE-UP - - uint32_t save_iso14a_timeout = iso14a_get_timeout(); - iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. - - uint32_t start_time = GetTickCount(); - int len; - - // we may need several tries if we did send an unknown command or a wrong authentication before... - do { - // Broadcast for a card, WUPA (0x52) will force response from all cards in the field - ReaderTransmitBitsPar(wupa, 7, NULL, NULL); - // Receive the ATQA - len = ReaderReceive(resp, resp_par); - } while (len == 0 && GetTickCount() <= start_time + WUPA_RETRY_TIMEOUT); - - iso14a_set_timeout(save_iso14a_timeout); - return len; -} - - -// performs iso14443a anticollision (optional) and card select procedure -// fills the uid and cuid pointer unless NULL -// fills the card info record unless NULL -// if anticollision is false, then the UID must be provided in uid_ptr[] -// and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) -// requests ATS unless no_rats is true -int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { - uint8_t sel_all[] = { 0x93,0x20 }; - uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 - uint8_t resp[MAX_FRAME_SIZE]; // theoretically. A usual RATS will be much smaller - uint8_t resp_par[MAX_PARITY_SIZE]; - uint8_t uid_resp[4]; - size_t uid_resp_len; - - uint8_t sak = 0x04; // cascade uid - int cascade_level = 0; - int len; - - // init card struct - if (p_hi14a_card) { - p_hi14a_card->uidlen = 0; - memset(p_hi14a_card->uid, 0, 10); - p_hi14a_card->ats_len = 0; - } - - if (!GetATQA(resp, resp_par)) { - return 0; - } - - if (p_hi14a_card) { - memcpy(p_hi14a_card->atqa, resp, 2); - } - - if (anticollision) { - // clear uid - if (uid_ptr) { - memset(uid_ptr,0,10); - } - } - - // check for proprietary anticollision: - if ((resp[0] & 0x1F) == 0) { - return 3; - } - - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in - // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3rd bit (from the right) is set in the SAK. - for (; sak & 0x04; cascade_level++) { - // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) - sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; - - if (anticollision) { - // SELECT_ALL - ReaderTransmit(sel_all, sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) { - return 0; - } - - if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit - memset(uid_resp, 0, 4); - uint16_t uid_resp_bits = 0; - uint16_t collision_answer_offset = 0; - // anti-collision-loop: - while (Demod.collisionPos) { - Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); - for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point - uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; - uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8); - } - uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position - uid_resp_bits++; - // construct anticollosion command: - sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits - for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { - sel_uid[2+i] = uid_resp[i]; - } - collision_answer_offset = uid_resp_bits%8; - ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); - if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) { - return 0; - } - } - // finally, add the last bits and BCC of the UID - for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { - uint16_t UIDbit = (resp[i/8] >> (i%8)) & 0x01; - uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); - } - - } else { // no collision, use the response to SELECT_ALL as current uid - memcpy(uid_resp, resp, 4); - } - } else { - if (cascade_level < num_cascades - 1) { - uid_resp[0] = 0x88; - memcpy(uid_resp+1, uid_ptr+cascade_level*3, 3); - } else { - memcpy(uid_resp, uid_ptr+cascade_level*3, 4); - } - } - uid_resp_len = 4; - - // calculate crypto UID. Always use last 4 Bytes. - if(cuid_ptr) { - *cuid_ptr = bytes_to_num(uid_resp, 4); - } - - // Construct SELECT UID command - sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC - AppendCrc14443a(sel_uid, 7); // calculate and add CRC - ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); - - // Receive the SAK - if (!ReaderReceive(resp, resp_par)) { - return 0; - } - sak = resp[0]; - - // Test if more parts of the uid are coming - if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { - // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: - // http://www.nxp.com/documents/application_note/AN10927.pdf - uid_resp[0] = uid_resp[1]; - uid_resp[1] = uid_resp[2]; - uid_resp[2] = uid_resp[3]; - uid_resp_len = 3; - } - - if(uid_ptr && anticollision) { - memcpy(uid_ptr + (cascade_level*3), uid_resp, uid_resp_len); - } - - if(p_hi14a_card) { - memcpy(p_hi14a_card->uid + (cascade_level*3), uid_resp, uid_resp_len); - p_hi14a_card->uidlen += uid_resp_len; - } - } - - if(p_hi14a_card) { - p_hi14a_card->sak = sak; - } - - // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) - if( (sak & 0x20) == 0) return 2; - - if (!no_rats) { - // Request for answer to select - AppendCrc14443a(rats, 2); - ReaderTransmit(rats, sizeof(rats), NULL); - - if (!(len = ReaderReceive(resp, resp_par))) { - return 0; - } - - if(p_hi14a_card) { - memcpy(p_hi14a_card->ats, resp, len); - p_hi14a_card->ats_len = len; - } - - // reset the PCB block number - iso14_pcb_blocknum = 0; - - // set default timeout and delay next transfer based on ATS - iso14a_set_ATS_times(resp); - - } - return 1; -} - - void iso14443a_setup(uint8_t fpga_minor_mode) { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); + FpgaSetupSsc(); // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1886,236 +1777,102 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { } FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); - // Set ADC to read field strength - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; - AT91C_BASE_ADC->ADC_MR = - ADC_MODE_PRESCALE(63) | - ADC_MODE_STARTUP_TIME(1) | - ADC_MODE_SAMPLE_HOLD_TIME(15); - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW); - // Start the timer StartCountSspClk(); - + DemodReset(); UartReset(); - LastTimeProxToAirStart = 0; - FpgaSendQueueDelay = 0; - LastProxToAirDuration = 20; // arbitrary small value. Avoid lock in EmGetCmd() NextTransferTime = 2*DELAY_ARM2AIR_AS_READER; - iso14a_set_timeout(1060); // 10ms default + iso14a_set_timeout(1050); // 10ms default } -/* Peter Fillmore 2015 -Added card id field to the function - info from ISO14443A standard -b1 = Block Number -b2 = RFU (always 1) -b3 = depends on block -b4 = Card ID following if set to 1 -b5 = depends on block type -b6 = depends on block type -b7,b8 = block type. -Coding of I-BLOCK: -b8 b7 b6 b5 b4 b3 b2 b1 -0 0 0 x x x 1 x -b5 = chaining bit -Coding of R-block: -b8 b7 b6 b5 b4 b3 b2 b1 -1 0 1 x x 0 1 x -b5 = ACK/NACK -Coding of S-block: -b8 b7 b6 b5 b4 b3 b2 b1 -1 1 x x x 0 1 0 -b5,b6 = 00 - DESELECT - 11 - WTX -*/ -int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) { - uint8_t parity[MAX_PARITY_SIZE]; - uint8_t real_cmd[cmd_len + 4]; - - if (cmd_len) { - // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 - real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) - if (send_chaining) { - real_cmd[0] |= 0x10; - } - // put block number into the PCB - real_cmd[0] |= iso14_pcb_blocknum; - memcpy(real_cmd + 1, cmd, cmd_len); - } else { - // R-block. ACK - real_cmd[0] = 0xA2; // r-block + ACK - real_cmd[0] |= iso14_pcb_blocknum; - } - AppendCrc14443a(real_cmd, cmd_len + 1); - - ReaderTransmit(real_cmd, cmd_len + 3, NULL); - - size_t len = ReaderReceive(data, parity); - uint8_t *data_bytes = (uint8_t *) data; - - if (!len) { +int iso14_apdu(uint8_t * cmd, size_t cmd_len, void * data) { + uint8_t real_cmd[cmd_len+4]; + real_cmd[0] = 0x0a; //I-Block + // put block number into the PCB + real_cmd[0] |= iso14_pcb_blocknum; + real_cmd[1] = 0x00; //CID: 0 //FIXME: allow multiple selected cards + memcpy(real_cmd+2, cmd, cmd_len); + AppendCrc14443a(real_cmd,cmd_len+2); + + ReaderTransmit(real_cmd, cmd_len+4, NULL); + size_t len = ReaderReceive(data); + uint8_t * data_bytes = (uint8_t *) data; + if (!len) return 0; //DATA LINK ERROR - } else { - // S-Block WTX - while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { - uint32_t save_iso14a_timeout = iso14a_get_timeout(); - // temporarily increase timeout - iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT)); - // Transmit WTX back - // byte1 - WTXM [1..59]. command FWT=FWT*WTXM - data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b - // now need to fix CRC. - AppendCrc14443a(data_bytes, len - 2); - // transmit S-Block - ReaderTransmit(data_bytes, len, NULL); - // retrieve the result again (with increased timeout) - len = ReaderReceive(data, parity); - data_bytes = data; - // restore timeout - iso14a_set_timeout(save_iso14a_timeout); - } - - // if we received an I- or R(ACK)-Block with a block number equal to the - // current block number, toggle the current block number - if (len >= 3 // PCB+CRC = 3 bytes - && ((data_bytes[0] & 0xC0) == 0 // I-Block - || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 - && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers - { - iso14_pcb_blocknum ^= 1; - } - - // if we received I-block with chaining we need to send ACK and receive another block of data - if (res) - *res = data_bytes[0]; - - // crc check - if (len >= 3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) { - return -1; - } - - } - - if (len) { - // cut frame byte - len -= 1; - // memmove(data_bytes, data_bytes + 1, len); - for (int i = 0; i < len; i++) - data_bytes[i] = data_bytes[i + 1]; + // 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 + && ((data_bytes[0] & 0xC0) == 0 // I-Block + || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers + { + iso14_pcb_blocknum ^= 1; } return len; } - //----------------------------------------------------------------------------- // Read an ISO 14443a tag. Send out commands and store answers. // //----------------------------------------------------------------------------- -void ReaderIso14443a(UsbCommand *c) { - +void ReaderIso14443a(UsbCommand *c) +{ iso14a_command_t param = c->arg[0]; uint8_t *cmd = c->d.asBytes; - size_t len = c->arg[1] & 0xffff; - size_t lenbits = c->arg[1] >> 16; - uint32_t timeout = c->arg[2]; + size_t len = c->arg[1]; + size_t lenbits = c->arg[2]; uint32_t arg0 = 0; - uint8_t buf[USB_CMD_DATA_SIZE] = {0}; - uint8_t par[MAX_PARITY_SIZE]; - bool cantSELECT = false; - - set_tracing(true); - - if (param & ISO14A_CLEAR_TRACE) { - clear_trace(); + byte_t buf[USB_CMD_DATA_SIZE]; + + if(param & ISO14A_CONNECT) { + iso14a_clear_trace(); } - if (param & ISO14A_REQUEST_TRIGGER) { - iso14a_set_trigger(true); + iso14a_set_tracing(TRUE); + + if(param & ISO14A_REQUEST_TRIGGER) { + iso14a_set_trigger(TRUE); } - if (param & ISO14A_CONNECT) { - LED_A_ON(); + if(param & ISO14A_CONNECT) { iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); if(!(param & ISO14A_NO_SELECT)) { iso14a_card_select_t *card = (iso14a_card_select_t*)buf; - arg0 = iso14443a_select_card(NULL, card, NULL, true, 0, param & ISO14A_NO_RATS); - - // if we cant select then we cant send data - if (arg0 != 1 && arg0 != 2) { - // 1 - all is OK with ATS, 2 - without ATS - cantSELECT = true; - } - FpgaDisableTracing(); - LED_B_ON(); - cmd_send(CMD_NACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); - LED_B_OFF(); + arg0 = iso14443a_select_card(NULL,card,NULL); + cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); } } - if (param & ISO14A_SET_TIMEOUT) { - iso14a_set_timeout(timeout); + if(param & ISO14A_SET_TIMEOUT) { + iso14a_timeout = c->arg[2]; } - if (param & ISO14A_APDU && !cantSELECT) { - uint8_t res; - arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); - FpgaDisableTracing(); - LED_B_ON(); - cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); - LED_B_OFF(); + if(param & ISO14A_APDU) { + arg0 = iso14_apdu(cmd, len, buf); + cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); } - if (param & ISO14A_RAW && !cantSELECT) { - if (param & ISO14A_APPEND_CRC) { - if(param & ISO14A_TOPAZMODE) { - AppendCrc14443b(cmd,len); - } else { - AppendCrc14443a(cmd,len); - } + if(param & ISO14A_RAW) { + if(param & ISO14A_APPEND_CRC) { + AppendCrc14443a(cmd,len); len += 2; - if (lenbits) lenbits += 16; } - if (lenbits > 0) { // want to send a specific number of bits (e.g. short commands) - if (param & ISO14A_TOPAZMODE) { - int bits_to_send = lenbits; - uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity - bits_to_send -= 7; - while (bits_to_send > 0) { - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity - bits_to_send -= 8; - } - } else { - GetParity(cmd, lenbits/8, par); - ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity - } - } else { // want to send complete bytes only - if (param & ISO14A_TOPAZMODE) { - uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy - while (i < len) { - ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy - } - } else { - ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity - } + if(lenbits>0) { + ReaderTransmitBitsPar(cmd,lenbits,GetParity(cmd,lenbits/8), NULL); + } else { + ReaderTransmit(cmd,len, NULL); } - arg0 = ReaderReceive(buf, par); - FpgaDisableTracing(); - - LED_B_ON(); - cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); - LED_B_OFF(); + arg0 = ReaderReceive(buf); + cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); } - if (param & ISO14A_REQUEST_TRIGGER) { - iso14a_set_trigger(false); + if(param & ISO14A_REQUEST_TRIGGER) { + iso14a_set_trigger(FALSE); } - if (param & ISO14A_NO_DISCONNECT) { + if(param & ISO14A_NO_DISCONNECT) { return; } @@ -2127,7 +1884,7 @@ void ReaderIso14443a(UsbCommand *c) { // Determine the distance between two nonces. // Assume that the difference is small, but we don't know which is first. // Therefore try in alternating directions. -static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { +int32_t dist_nt(uint32_t nt1, uint32_t nt2) { uint16_t i; uint32_t nttmp1, nttmp2; @@ -2136,14 +1893,14 @@ static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { nttmp1 = nt1; nttmp2 = nt2; - + for (i = 1; i < 32768; i++) { nttmp1 = prng_successor(nttmp1, 1); if (nttmp1 == nt2) return i; nttmp2 = prng_successor(nttmp2, 1); - if (nttmp2 == nt1) return -i; + if (nttmp2 == nt1) return -i; } - + return(-99999); // either nt1 or nt2 are invalid nonces } @@ -2161,139 +1918,85 @@ void ReaderMifare(bool first_try) uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; static uint8_t mf_nr_ar3; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET); - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); - // free eventually allocated BigBuf memory. We want all for tracing. - BigBuf_free(); - - clear_trace(); - set_tracing(true); - - uint8_t nt_diff = 0; - uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough - static uint8_t par_low = 0; - bool led_on = true; - uint8_t uid[10] ={0}; + byte_t nt_diff = 0; + byte_t par = 0; + //byte_t par_mask = 0xff; + static byte_t par_low = 0; + bool led_on = TRUE; + uint8_t uid[10]; uint32_t cuid; - uint32_t nt = 0; - uint32_t previous_nt = 0; + uint32_t nt, previous_nt; static uint32_t nt_attacked = 0; - uint8_t par_list[8] = {0x00}; - uint8_t ks_list[8] = {0x00}; + byte_t par_list[8] = {0,0,0,0,0,0,0,0}; + byte_t ks_list[8] = {0,0,0,0,0,0,0,0}; - #define PRNG_SEQUENCE_LENGTH (1 << 16); - uint32_t sync_time = GetCountSspClk() & 0xfffffff8; - static int32_t sync_cycles; + static uint32_t sync_time; + static uint32_t sync_cycles; int catch_up_cycles = 0; int last_catch_up = 0; - uint16_t elapsed_prng_sequences; uint16_t consecutive_resyncs = 0; int isOK = 0; - if (first_try) { + + + if (first_try) { mf_nr_ar3 = 0; - par[0] = par_low = 0; - sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + sync_time = GetCountSspClk() & 0xfffffff8; + sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). nt_attacked = 0; + nt = 0; + par = 0; } else { // we were unsuccessful on a previous call. Try another READER nonce (first 3 parity bits remain the same) + // nt_attacked = prng_successor(nt_attacked, 1); mf_nr_ar3++; mf_nr_ar[3] = mf_nr_ar3; - par[0] = par_low; + par = par_low; } LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - - #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. - #define MAX_SYNC_TRIES 32 - #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle - #define NUM_DEBUG_INFOS 8 // per strategy - #define MAX_STRATEGY 3 - uint16_t unexpected_random = 0; - uint16_t sync_tries = 0; - int16_t debug_info_nr = -1; - uint16_t strategy = 0; - int32_t debug_info[MAX_STRATEGY][NUM_DEBUG_INFOS]; - uint32_t select_time; - uint32_t halt_time; - - for (uint16_t i = 0; true; i++) { - - LED_C_ON(); + + + for(uint16_t i = 0; TRUE; i++) { + WDT_HIT(); // Test if the action was cancelled if(BUTTON_PRESS()) { - isOK = -1; break; } + + LED_C_ON(); - if (strategy == 2) { - // test with additional hlt command - halt_time = 0; - int len = mifare_sendcmd_short(NULL, false, 0x50, 0x00, receivedAnswer, receivedAnswerPar, &halt_time); - if (len && MF_DBGLEVEL >= 3) { - Dbprintf("Unexpected response of %d bytes to hlt command (additional debugging).", len); - } - } - - if (strategy == 3) { - // test with FPGA power off/on - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(100); - } - - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); continue; } - select_time = GetCountSspClk(); - elapsed_prng_sequences = 1; - if (debug_info_nr == -1) { - sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; - catch_up_cycles = 0; + sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; + catch_up_cycles = 0; - // if we missed the sync time already or are about to miss it, advance to the next nonce repeat - while(sync_time < GetCountSspClk() + SYNC_TIME_BUFFER) { - elapsed_prng_sequences++; - sync_time = (sync_time & 0xfffffff8) + sync_cycles; - } - - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) - ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); - } else { - // collect some information on tag nonces for debugging: - #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH - if (strategy == 0) { - // nonce distances at fixed time after card select: - sync_time = select_time + DEBUG_FIXED_SYNC_CYCLES; - } else if (strategy == 1) { - // nonce distances at fixed time between authentications: - sync_time = sync_time + DEBUG_FIXED_SYNC_CYCLES; - } else if (strategy == 2) { - // nonce distances at fixed time after halt: - sync_time = halt_time + DEBUG_FIXED_SYNC_CYCLES; - } else { - // nonce_distances at fixed time after power on - sync_time = DEBUG_FIXED_SYNC_CYCLES; - } - ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + // if we missed the sync time already, advance to the next nonce repeat + while(GetCountSspClk() > sync_time) { + sync_time = (sync_time & 0xfffffff8) + sync_cycles; } + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + // Receive the (4 Byte) "random" nonce - if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); + if (!ReaderReceive(receivedAnswer)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); continue; } @@ -2307,82 +2010,56 @@ void ReaderMifare(bool first_try) int nt_distance = dist_nt(previous_nt, nt); if (nt_distance == 0) { nt_attacked = nt; - } else { - if (nt_distance == -99999) { // invalid nonce received - unexpected_random++; - if (unexpected_random > MAX_UNEXPECTED_RANDOM) { - isOK = -3; // Card has an unpredictable PRNG. Give up - break; - } else { - continue; // continue trying... - } - } - if (++sync_tries > MAX_SYNC_TRIES) { - if (strategy > MAX_STRATEGY || MF_DBGLEVEL < 3) { - isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly - break; - } else { // continue for a while, just to collect some debug info - debug_info[strategy][debug_info_nr] = nt_distance; - debug_info_nr++; - if (debug_info_nr == NUM_DEBUG_INFOS) { - strategy++; - debug_info_nr = 0; - } - continue; - } - } - sync_cycles = (sync_cycles - nt_distance/elapsed_prng_sequences); - if (sync_cycles <= 0) { - sync_cycles += PRNG_SEQUENCE_LENGTH; - } - if (MF_DBGLEVEL >= 3) { - Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles); + } + else { + if (nt_distance == -99999) { // invalid nonce received, try again + continue; } + sync_cycles = (sync_cycles - nt_distance); + if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles); continue; } } - if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... + if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... catch_up_cycles = -dist_nt(nt_attacked, nt); - if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. + if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. catch_up_cycles = 0; continue; } - catch_up_cycles /= elapsed_prng_sequences; if (catch_up_cycles == last_catch_up) { consecutive_resyncs++; } else { last_catch_up = catch_up_cycles; - consecutive_resyncs = 0; + consecutive_resyncs = 0; } if (consecutive_resyncs < 3) { if (MF_DBGLEVEL >= 3) Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, -catch_up_cycles, consecutive_resyncs); } - else { + else { sync_cycles = sync_cycles + catch_up_cycles; if (MF_DBGLEVEL >= 3) Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, -catch_up_cycles, sync_cycles); - last_catch_up = 0; - catch_up_cycles = 0; - consecutive_resyncs = 0; } continue; } - + consecutive_resyncs = 0; - + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding - if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { - catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer - - if (nt_diff == 0) { - par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change + if (ReaderReceive(receivedAnswer)) + { + catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer + + if (nt_diff == 0) + { + par_low = par & 0x07; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change } led_on = !led_on; if(led_on) LED_B_ON(); else LED_B_OFF(); - par_list[nt_diff] = SwapBits(par[0], 8); + par_list[nt_diff] = par; ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // Test if the information is complete @@ -2393,56 +2070,546 @@ void ReaderMifare(bool first_try) nt_diff = (nt_diff + 1) & 0x07; mf_nr_ar[3] = (mf_nr_ar[3] & 0x1F) | (nt_diff << 5); - par[0] = par_low; + par = par_low; } else { if (nt_diff == 0 && first_try) { - par[0]++; - if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK. - isOK = -2; - break; - } + par++; } else { - par[0] = ((par[0] & 0x1F) + 1) | par_low; + par = (((par >> 3) + 1) << 3) | par_low; } } } mf_nr_ar[3] &= 0x1F; - - if (isOK == -4) { - if (MF_DBGLEVEL >= 3) { - for (uint16_t i = 0; i <= MAX_STRATEGY; i++) { - for (uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) { - Dbprintf("collected debug info[%d][%d] = %d", i, j, debug_info[i][j]); - } - } - } - } - - FpgaDisableTracing(); - - uint8_t buf[32]; + + byte_t buf[28]; memcpy(buf + 0, uid, 4); num_to_bytes(nt, 4, buf + 4); memcpy(buf + 8, par_list, 8); memcpy(buf + 16, ks_list, 8); - memcpy(buf + 24, mf_nr_ar, 8); - - cmd_send(CMD_ACK, isOK, 0, 0, buf, 32); + memcpy(buf + 24, mf_nr_ar, 4); + + cmd_send(CMD_ACK,isOK,0,0,buf,28); // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - set_tracing(false); + iso14a_set_tracing(FALSE); +} + +/** + *MIFARE 1K simulate. + * + *@param flags : + * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK + * 4B_FLAG_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that + * 7B_FLAG_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that + * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later + *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite + */ +void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) +{ + int cardSTATE = MFEMUL_NOFIELD; + int _7BUID = 0; + int vHf = 0; // in mV + int res; + uint32_t selTimer = 0; + uint32_t authTimer = 0; + uint32_t par = 0; + int len = 0; + uint8_t cardWRBL = 0; + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = 0xff; // no authentication + uint32_t cardRr = 0; + uint32_t cuid = 0; + //uint32_t rn_enc = 0; + uint32_t ans = 0; + uint32_t cardINTREG = 0; + uint8_t cardINTBLOCK = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + uint32_t numReads = 0;//Counts numer of times reader read a block + uint8_t* receivedCmd = eml_get_bigbufptr_recbuf(); + uint8_t *response = eml_get_bigbufptr_sendbuf(); + + uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID + uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; + uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! + uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; + uint8_t rSAK1[] = {0x04, 0xda, 0x17}; + + uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; + uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; + + //Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2 + // This can be used in a reader-only attack. + // (it can also be retrieved via 'hf 14a list', but hey... + uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0}; + uint8_t ar_nr_collected = 0; + + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + + // Authenticate response - nonce + uint32_t nonce = bytes_to_num(rAUTH_NT, 4); + + //-- Determine the UID + // Can be set from emulator memory, incoming data + // and can be 7 or 4 bytes long + if (flags & FLAG_4B_UID_IN_DATA) + { + // 4B uid comes from data-portion of packet + memcpy(rUIDBCC1,datain,4); + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + + } else if (flags & FLAG_7B_UID_IN_DATA) { + // 7B uid comes from data-portion of packet + memcpy(&rUIDBCC1[1],datain,3); + memcpy(rUIDBCC2, datain+3, 4); + _7BUID = true; + } else { + // get UID from emul memory + emlGetMemBt(receivedCmd, 7, 1); + _7BUID = !(receivedCmd[0] == 0x00); + if (!_7BUID) { // ---------- 4BUID + emlGetMemBt(rUIDBCC1, 0, 4); + } else { // ---------- 7BUID + emlGetMemBt(&rUIDBCC1[1], 0, 3); + emlGetMemBt(rUIDBCC2, 3, 4); + } + } + + /* + * Regardless of what method was used to set the UID, set fifth byte and modify + * the ATQA for 4 or 7-byte UID + */ + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + if (_7BUID) { + rATQA[0] = 0x44; + rUIDBCC1[0] = 0x88; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + } + + // We need to listen to the high-frequency, peak-detected path. + iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); + + + if (MF_DBGLEVEL >= 1) { + if (!_7BUID) { + Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]); + } else { + Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]); + } + } + + bool finished = FALSE; + while (!BUTTON_PRESS() && !finished) { + WDT_HIT(); + + // find reader field + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + if (cardSTATE == MFEMUL_NOFIELD) { + vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; + if (vHf > MF_MINFIELDV) { + cardSTATE_TO_IDLE(); + LED_A_ON(); + } + } + if(cardSTATE == MFEMUL_NOFIELD) continue; + + //Now, get data + + res = EmGetCmd(receivedCmd, &len); + if (res == 2) { //Field is off! + cardSTATE = MFEMUL_NOFIELD; + LEDsoff(); + continue; + } else if (res == 1) { + break; //return value 1 means button press + } + + // REQ or WUP request in ANY state and WUP in HALTED state + if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) { + selTimer = GetTickCount(); + EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52)); + cardSTATE = MFEMUL_SELECT1; + + // init crypto block + LED_B_OFF(); + LED_C_OFF(); + crypto1_destroy(pcs); + cardAUTHKEY = 0xff; + continue; + } + + switch (cardSTATE) { + case MFEMUL_NOFIELD: + case MFEMUL_HALTED: + case MFEMUL_IDLE:{ + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + case MFEMUL_SELECT1:{ + // select all + if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { + if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received"); + EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); + break; + } + + if (MF_DBGLEVEL >= 4 && len == 9 && receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 ) + { + Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + } + // select card + if (len == 9 && + (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { + EmSendCmd(_7BUID?rSAK1:rSAK, sizeof(_7BUID?rSAK1:rSAK)); + cuid = bytes_to_num(rUIDBCC1, 4); + if (!_7BUID) { + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); + break; + } else { + cardSTATE = MFEMUL_SELECT2; + } + } + break; + } + case MFEMUL_AUTH1:{ + if( len != 8) + { + cardSTATE_TO_IDLE(); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + uint32_t ar = bytes_to_num(receivedCmd, 4); + uint32_t nr= bytes_to_num(&receivedCmd[4], 4); + + //Collect AR/NR + if(ar_nr_collected < 2){ + if(ar_nr_responses[2] != ar) + {// Avoid duplicates... probably not necessary, ar should vary. + ar_nr_responses[ar_nr_collected*4] = cuid; + ar_nr_responses[ar_nr_collected*4+1] = nonce; + ar_nr_responses[ar_nr_collected*4+2] = ar; + ar_nr_responses[ar_nr_collected*4+3] = nr; + ar_nr_collected++; + } + } + + // --- crypto + crypto1_word(pcs, ar , 1); + cardRr = nr ^ crypto1_word(pcs, 0, 0); + + // test if auth OK + if (cardRr != prng_successor(nonce, 64)){ + if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64)); + // Shouldn't we respond anything here? + // Right now, we don't nack or anything, which causes the + // reader to do a WUPA after a while. /Martin + cardSTATE_TO_IDLE(); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + + ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); + + num_to_bytes(ans, 4, rAUTH_AT); + // --- crypto + EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); + LED_C_ON(); + cardSTATE = MFEMUL_WORK; + if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sector=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer); + break; + } + case MFEMUL_SELECT2:{ + if (!len) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + if (len == 2 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x20)) { + EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); + break; + } + + // select 2 card + if (len == 9 && + (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { + EmSendCmd(rSAK, sizeof(rSAK)); + cuid = bytes_to_num(rUIDBCC2, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + if (MF_DBGLEVEL >= 4) Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + break; + } + + // i guess there is a command). go into the work state. + if (len != 4) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + cardSTATE = MFEMUL_WORK; + //goto lbWORK; + //intentional fall-through to the next case-stmt + } + + case MFEMUL_WORK:{ + if (len == 0) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + + bool encrypted_data = (cardAUTHKEY != 0xFF) ; + + if(encrypted_data) { + // decrypt seqence + mf_crypto1_decrypt(pcs, receivedCmd, len); + } + + if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { + authTimer = GetTickCount(); + cardAUTHSC = receivedCmd[1] / 4; // received block num + cardAUTHKEY = receivedCmd[0] - 0x60; + crypto1_destroy(pcs);//Added by martin + crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); + + if (!encrypted_data) { // first authentication + if (MF_DBGLEVEL >= 2) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY ); + + crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state + num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce + } else { // nested authentication + if (MF_DBGLEVEL >= 2) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY ); + ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0); + num_to_bytes(ans, 4, rAUTH_AT); + } + EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); + //Dbprintf("Sending rAUTH %02x%02x%02x%02x", rAUTH_AT[0],rAUTH_AT[1],rAUTH_AT[2],rAUTH_AT[3]); + cardSTATE = MFEMUL_AUTH1; + break; + } + + // rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued + // BUT... ACK --> NACK + if (len == 1 && receivedCmd[0] == CARD_ACK) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + break; + } + + // rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK) + if (len == 1 && receivedCmd[0] == CARD_NACK_NA) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + break; + } + + if(len != 4) { + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + + if(receivedCmd[0] == 0x30 // read block + || receivedCmd[0] == 0xA0 // write block + || receivedCmd[0] == 0xC0 + || receivedCmd[0] == 0xC1 + || receivedCmd[0] == 0xC2 // inc dec restore + || receivedCmd[0] == 0xB0) { // transfer + if (receivedCmd[1] >= 16 * 4) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + break; + } + + if (receivedCmd[1] / 4 != cardAUTHSC) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC); + break; + } + } + // read block + if (receivedCmd[0] == 0x30) { + if (MF_DBGLEVEL >= 2) { + Dbprintf("Reader reading block %d (0x%02x)",receivedCmd[1],receivedCmd[1]); + } + emlGetMem(response, receivedCmd[1], 1); + AppendCrc14443a(response, 16); + mf_crypto1_encrypt(pcs, response, 18, &par); + EmSendCmdPar(response, 18, par); + numReads++; + if(exitAfterNReads > 0 && numReads == exitAfterNReads) { + Dbprintf("%d reads done, exiting", numReads); + finished = true; + } + break; + } + // write block + if (receivedCmd[0] == 0xA0) { + if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd[1],receivedCmd[1]); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + cardSTATE = MFEMUL_WRITEBL2; + cardWRBL = receivedCmd[1]; + break; + } + // increment, decrement, restore + if (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2) { + if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + if (emlCheckValBl(receivedCmd[1])) { + if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + break; + } + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + if (receivedCmd[0] == 0xC1) + cardSTATE = MFEMUL_INTREG_INC; + if (receivedCmd[0] == 0xC0) + cardSTATE = MFEMUL_INTREG_DEC; + if (receivedCmd[0] == 0xC2) + cardSTATE = MFEMUL_INTREG_REST; + cardWRBL = receivedCmd[1]; + break; + } + // transfer + if (receivedCmd[0] == 0xB0) { + if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]); + if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd[1])) + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + else + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + break; + } + // halt + if (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00) { + LED_B_OFF(); + LED_C_OFF(); + cardSTATE = MFEMUL_HALTED; + if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED. Selected time: %d ms", GetTickCount() - selTimer); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + break; + } + // RATS + if (receivedCmd[0] == 0xe0) {//RATS + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + break; + } + // command not allowed + if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking"); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + break; + } + case MFEMUL_WRITEBL2:{ + if (len == 18){ + mf_crypto1_decrypt(pcs, receivedCmd, len); + emlSetMem(receivedCmd, cardWRBL, 1); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + cardSTATE = MFEMUL_WORK; + } else { + cardSTATE_TO_IDLE(); + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + } + break; + } + + case MFEMUL_INTREG_INC:{ + mf_crypto1_decrypt(pcs, receivedCmd, len); + memcpy(&ans, receivedCmd, 4); + if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + cardSTATE_TO_IDLE(); + break; + } + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + cardINTREG = cardINTREG + ans; + cardSTATE = MFEMUL_WORK; + break; + } + case MFEMUL_INTREG_DEC:{ + mf_crypto1_decrypt(pcs, receivedCmd, len); + memcpy(&ans, receivedCmd, 4); + if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + cardSTATE_TO_IDLE(); + break; + } + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + cardINTREG = cardINTREG - ans; + cardSTATE = MFEMUL_WORK; + break; + } + case MFEMUL_INTREG_REST:{ + mf_crypto1_decrypt(pcs, receivedCmd, len); + memcpy(&ans, receivedCmd, 4); + if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + cardSTATE_TO_IDLE(); + break; + } + LogTrace(Uart.output, Uart.len, Uart.startTime*16 - DELAY_AIR2ARM_AS_TAG, Uart.parityBits, TRUE); + LogTrace(NULL, 0, Uart.endTime*16 - DELAY_AIR2ARM_AS_TAG, 0, TRUE); + cardSTATE = MFEMUL_WORK; + break; + } + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK + { + //May just aswell send the collected ar_nr in the response aswell + cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4); + } + + if(flags & FLAG_NR_AR_ATTACK) + { + if(ar_nr_collected > 1) { + Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:"); + Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", + ar_nr_responses[0], // UID + ar_nr_responses[1], //NT + ar_nr_responses[2], //AR1 + ar_nr_responses[3], //NR1 + ar_nr_responses[6], //AR2 + ar_nr_responses[7] //NR2 + ); + } else { + Dbprintf("Failed to obtain two AR/NR pairs!"); + if(ar_nr_collected >0) { + Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x", + ar_nr_responses[0], // UID + ar_nr_responses[1], //NT + ar_nr_responses[2], //AR1 + ar_nr_responses[3] //NR1 + ); + } + } + } + if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, traceLen); } + //----------------------------------------------------------------------------- -// MIFARE sniffer. -// +// MIFARE sniffer. +// //----------------------------------------------------------------------------- void RAMFUNC SniffMifare(uint8_t param) { // param: @@ -2451,81 +2618,81 @@ void RAMFUNC SniffMifare(uint8_t param) { // C(red) A(yellow) B(green) LEDsoff(); - LED_A_ON(); - // init trace buffer - clear_trace(); - set_tracing(true); + iso14a_clear_trace(); // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. // So 32 should be enough! - uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedCmdPar[MAX_MIFARE_PARITY_SIZE]; + uint8_t *receivedCmd = (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); // The response (tag -> reader) that we're receiving. - uint8_t receivedResponse[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedResponsePar[MAX_MIFARE_PARITY_SIZE]; + uint8_t *receivedResponse = (((uint8_t *)BigBuf) + RECV_RES_OFFSET); - iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); - - // free eventually allocated BigBuf memory - BigBuf_free(); - // allocate the DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + // As we receive stuff, we copy it from receivedCmd or receivedResponse + // into trace, along with its length and other annotations. + //uint8_t *trace = (uint8_t *)BigBuf; + + // The DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = ((uint8_t *)BigBuf) + DMA_BUFFER_OFFSET; uint8_t *data = dmaBuf; uint8_t previous_data = 0; int maxDataLen = 0; int dataLen = 0; - bool ReaderIsActive = false; - bool TagIsActive = false; + bool ReaderIsActive = FALSE; + bool TagIsActive = FALSE; + + iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); // Set up the demodulator for tag -> reader responses. - DemodInit(receivedResponse, receivedResponsePar); + Demod.output = receivedResponse; // Set up the demodulator for the reader -> tag commands - UartInit(receivedCmd, receivedCmdPar); + Uart.output = receivedCmd; // Setup for the DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. + LED_D_OFF(); + // init sniffer MfSniffInit(); // And now we loop, receiving samples. - for (uint32_t sniffCounter = 0; true; ) { - + for(uint32_t sniffCounter = 0; TRUE; ) { + if(BUTTON_PRESS()) { - DbpString("Canceled by button."); + DbpString("cancelled by button"); break; } + LED_A_ON(); WDT_HIT(); - - if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time + + if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time // check if a transaction is completed (timeout after 2000ms). // if yes, stop the DMA transfer and send what we have so far to the client - if (MfSniffSend(2000)) { + if (MfSniffSend(2000)) { // Reset everything - we missed some sniffed data anyway while the DMA was stopped sniffCounter = 0; data = dmaBuf; maxDataLen = 0; - ReaderIsActive = false; - TagIsActive = false; + ReaderIsActive = FALSE; + TagIsActive = FALSE; FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. } } - - int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far + + int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; // number of bytes already transferred - if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred - dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed - } else { + if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred + dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed + } else { dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; // number of bytes still to be processed } // test for length of buffer - if(dataLen > maxDataLen) { // we are more behind than ever... - maxDataLen = dataLen; - if(dataLen > (9 * DMA_BUFFER_SIZE / 10)) { + if(dataLen > maxDataLen) { // we are more behind than ever... + maxDataLen = dataLen; + if(dataLen > 400) { Dbprintf("blew circular buffer! dataLen=0x%x", dataLen); break; } @@ -2544,33 +2711,34 @@ void RAMFUNC SniffMifare(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } + LED_A_OFF(); + if (sniffCounter & 0x01) { - if(!TagIsActive) { // no need to try decoding tag data if the reader is sending + if(!TagIsActive) { // no need to try decoding tag data if the reader is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { - - if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, true)) break; + LED_C_INV(); + if (MfSniffLogic(receivedCmd, Uart.len, Uart.parityBits, Uart.bitCount, TRUE)) break; /* And ready to receive another command. */ - UartInit(receivedCmd, receivedCmdPar); - + UartReset(); + /* And also reset the demod code */ DemodReset(); } ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - - if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending + + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { + LED_C_INV(); - if (MfSniffLogic(receivedResponse, Demod.len, Demod.parity, Demod.bitCount, false)) break; + if (MfSniffLogic(receivedResponse, Demod.len, Demod.parityBits, Demod.bitCount, FALSE)) break; // And ready to receive another response. DemodReset(); - // And reset the Miller decoder including its (now outdated) input buffer - UartInit(receivedCmd, receivedCmdPar); } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } @@ -2585,13 +2753,11 @@ void RAMFUNC SniffMifare(uint8_t param) { } // main cycle - FpgaDisableTracing(); + DbpString("COMMAND FINISHED"); + FpgaDisableSscDma(); - LEDsoff(); - - DbpString("COMMAND FINISHED."); - MfSniffEnd(); - + Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); + LEDsoff(); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 32bf3971..6d18515f 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -12,46 +12,86 @@ #ifndef __ISO14443A_H #define __ISO14443A_H +#include "common.h" +#include "mifaresniff.h" -#include -#include -#include -#include "usb_cmd.h" -#include "mifare.h" +// mifare reader over DMA buffer (SnoopIso14443a())!!! +#define MIFARE_BUFF_OFFSET 3560 // \/ \/ \/ +// card emulator memory +#define EML_RESPONSES 4000 +#define CARD_MEMORY 6000 +#define CARD_MEMORY_LEN 4096 typedef struct { - uint8_t* response; - uint8_t* modulation; - uint16_t response_n; - uint16_t modulation_n; - uint32_t ProxToAirDuration; - uint8_t par; // enough for precalculated parity of 8 Byte responses -} tag_response_info_t; + enum { + DEMOD_UNSYNCD, + // DEMOD_HALF_SYNCD, + // DEMOD_MOD_FIRST_HALF, + // DEMOD_NOMOD_FIRST_HALF, + DEMOD_MANCHESTER_DATA + } state; + uint16_t twoBits; + uint16_t highCnt; + uint16_t bitCount; + uint16_t collisionPos; + uint16_t syncBit; + uint32_t parityBits; + uint16_t shiftReg; + uint16_t samples; + uint16_t len; + uint32_t startTime, endTime; + uint8_t *output; +} tDemod; -extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); +typedef enum { + MOD_NOMOD = 0, + MOD_SECOND_HALF, + MOD_FIRST_HALF, + MOD_BOTH_HALVES + } Modulation_t; + +typedef struct { + enum { + STATE_UNSYNCD, + STATE_START_OF_COMMUNICATION, + STATE_MILLER_X, + STATE_MILLER_Y, + STATE_MILLER_Z, + // DROP_NONE, + // DROP_FIRST_HALF, + } state; + uint16_t shiftReg; + uint16_t bitCount; + uint16_t len; + uint16_t byteCntMax; + uint16_t posCnt; + uint16_t syncBit; + uint32_t parityBits; + uint16_t highCnt; + uint16_t twoBits; + uint32_t startTime, endTime; + uint8_t *output; +} tUart; + + + +extern byte_t oddparity (const byte_t bt); +extern uint32_t GetParity(const uint8_t *pbtCmd, int iLen); extern void AppendCrc14443a(uint8_t *data, int len); -extern void RAMFUNC SnoopIso14443a(uint8_t param); -extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t *data); -extern void ReaderIso14443a(UsbCommand *c); -extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); -extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); -extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); -extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par); -extern void ReaderMifare(bool first_try); - -extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity); -extern int EmSendCmd(uint8_t *resp, uint16_t respLen); -extern int EmSend4bit(uint8_t resp); -extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); -extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); - -extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size); +extern void ReaderTransmit(uint8_t *frame, int len, uint32_t *timing); +extern void ReaderTransmitBitsPar(uint8_t *frame, int bits, uint32_t par, uint32_t *timing); +extern void ReaderTransmitPar(uint8_t *frame, int len, uint32_t par, uint32_t *timing); +extern int ReaderReceive(uint8_t *receivedAnswer); +extern int ReaderReceivePar(uint8_t *receivedAnswer, uint32_t *parptr); extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); -extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); +extern int iso14_apdu(uint8_t *cmd, size_t cmd_len, void *data); +extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr); extern void iso14a_set_trigger(bool enable); extern void iso14a_set_timeout(uint32_t timeout); -extern uint32_t iso14a_get_timeout(void); + +extern void iso14a_clear_tracelen(); +extern void iso14a_set_tracing(bool enable); + #endif /* __ISO14443A_H */ diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c deleted file mode 100644 index 0f36c7c7..00000000 --- a/armsrc/iso14443b.c +++ /dev/null @@ -1,1292 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, split Nov 2006 -// piwi 2018 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support ISO 14443B. This includes both the reader software and -// the `fake tag' modes. -//----------------------------------------------------------------------------- - -#include "iso14443b.h" - -#include "proxmark3.h" -#include "apps.h" -#include "usb_cdc.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "fpgaloader.h" -#include "BigBuf.h" - -#define RECEIVE_SAMPLES_TIMEOUT 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA -#define ISO14443B_DMA_BUFFER_SIZE 128 - -// PCB Block number for APDUs -static uint8_t pcb_blocknum = 0; - -//============================================================================= -// An ISO 14443 Type B tag. We listen for commands from the reader, using -// a UART kind of thing that's implemented in software. When we get a -// frame (i.e., a group of bytes between SOF and EOF), we check the CRC. -// If it's good, then we can do something appropriate with it, and send -// a response. -//============================================================================= - -//----------------------------------------------------------------------------- -// Code up a string of octets at layer 2 (including CRC, we don't generate -// that here) so that they can be transmitted to the reader. Doesn't transmit -// them yet, just leaves them ready to send in ToSend[]. -//----------------------------------------------------------------------------- -static void CodeIso14443bAsTag(const uint8_t *cmd, int len) -{ - int i; - - ToSendReset(); - - // Transmit a burst of ones, as the initial thing that lets the - // reader get phase sync. This (TR1) must be > 80/fs, per spec, - // but tag that I've tried (a Paypass) exceeds that by a fair bit, - // so I will too. - for(i = 0; i < 20; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Send SOF. - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - for(i = 0; i < 2; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - for(i = 0; i < len; i++) { - int j; - uint8_t b = cmd[i]; - - // Start bit - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - - // Data bits - for(j = 0; j < 8; j++) { - if(b & 1) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } else { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - b >>= 1; - } - - // Stop bit - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Send EOF. - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - } - for(i = 0; i < 2; i++) { - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - } - - // Convert from last byte pos to length - ToSendMax++; -} - -//----------------------------------------------------------------------------- -// The software UART that receives commands from the reader, and its state -// variables. -//----------------------------------------------------------------------------- -static struct { - enum { - STATE_UNSYNCD, - STATE_GOT_FALLING_EDGE_OF_SOF, - STATE_AWAITING_START_BIT, - STATE_RECEIVING_DATA - } state; - uint16_t shiftReg; - int bitCnt; - int byteCnt; - int byteCntMax; - int posCnt; - uint8_t *output; -} Uart; - -/* Receive & handle a bit coming from the reader. - * - * This function is called 4 times per bit (every 2 subcarrier cycles). - * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us - * - * LED handling: - * LED A -> ON once we have received the SOF and are expecting the rest. - * LED A -> OFF once we have received EOF or are in error state or unsynced - * - * Returns: true if we received a EOF - * false if we are still waiting for some more - */ -static RAMFUNC int Handle14443bUartBit(uint8_t bit) -{ - switch(Uart.state) { - case STATE_UNSYNCD: - if(!bit) { - // we went low, so this could be the beginning - // of an SOF - Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF; - Uart.posCnt = 0; - Uart.bitCnt = 0; - } - break; - - case STATE_GOT_FALLING_EDGE_OF_SOF: - Uart.posCnt++; - if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit - if(bit) { - if(Uart.bitCnt > 9) { - // we've seen enough consecutive - // zeros that it's a valid SOF - Uart.posCnt = 0; - Uart.byteCnt = 0; - Uart.state = STATE_AWAITING_START_BIT; - LED_A_ON(); // Indicate we got a valid SOF - } else { - // didn't stay down long enough - // before going high, error - Uart.state = STATE_UNSYNCD; - } - } else { - // do nothing, keep waiting - } - Uart.bitCnt++; - } - if(Uart.posCnt >= 4) Uart.posCnt = 0; - if(Uart.bitCnt > 12) { - // Give up if we see too many zeros without - // a one, too. - LED_A_OFF(); - Uart.state = STATE_UNSYNCD; - } - break; - - case STATE_AWAITING_START_BIT: - Uart.posCnt++; - if(bit) { - if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs - // stayed high for too long between - // characters, error - Uart.state = STATE_UNSYNCD; - } - } else { - // falling edge, this starts the data byte - Uart.posCnt = 0; - Uart.bitCnt = 0; - Uart.shiftReg = 0; - Uart.state = STATE_RECEIVING_DATA; - } - break; - - case STATE_RECEIVING_DATA: - Uart.posCnt++; - if(Uart.posCnt == 2) { - // time to sample a bit - Uart.shiftReg >>= 1; - if(bit) { - Uart.shiftReg |= 0x200; - } - Uart.bitCnt++; - } - if(Uart.posCnt >= 4) { - Uart.posCnt = 0; - } - if(Uart.bitCnt == 10) { - if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001)) - { - // this is a data byte, with correct - // start and stop bits - Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff; - Uart.byteCnt++; - - if(Uart.byteCnt >= Uart.byteCntMax) { - // Buffer overflowed, give up - LED_A_OFF(); - Uart.state = STATE_UNSYNCD; - } else { - // so get the next byte now - Uart.posCnt = 0; - Uart.state = STATE_AWAITING_START_BIT; - } - } else if (Uart.shiftReg == 0x000) { - // this is an EOF byte - LED_A_OFF(); // Finished receiving - Uart.state = STATE_UNSYNCD; - if (Uart.byteCnt != 0) { - return true; - } - } else { - // this is an error - LED_A_OFF(); - Uart.state = STATE_UNSYNCD; - } - } - break; - - default: - LED_A_OFF(); - Uart.state = STATE_UNSYNCD; - break; - } - - return false; -} - - -static void UartReset() -{ - Uart.byteCntMax = MAX_FRAME_SIZE; - Uart.state = STATE_UNSYNCD; - Uart.byteCnt = 0; - Uart.bitCnt = 0; -} - - -static void UartInit(uint8_t *data) -{ - Uart.output = data; - UartReset(); -} - - -//----------------------------------------------------------------------------- -// Receive a command (from the reader to us, where we are the simulated tag), -// and store it in the given buffer, up to the given maximum length. Keeps -// spinning, waiting for a well-framed command, until either we get one -// (returns true) or someone presses the pushbutton on the board (false). -// -// Assume that we're called with the SSC (to the FPGA) and ADC path set -// correctly. -//----------------------------------------------------------------------------- -static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) -{ - // Set FPGA mode to "simulated ISO 14443B tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - - // Now run a `software UART' on the stream of incoming samples. - UartInit(received); - - for(;;) { - WDT_HIT(); - - if(BUTTON_PRESS()) return false; - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) { - if(Handle14443bUartBit(b & mask)) { - *len = Uart.byteCnt; - return true; - } - } - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Main loop of simulated tag: receive commands from reader, decide what -// response to send, and send it. -//----------------------------------------------------------------------------- -void SimulateIso14443bTag(void) -{ - LED_A_ON(); - // the only commands we understand is WUPB, AFI=0, Select All, N=1: - static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; // WUPB - // ... and REQB, AFI=0, Normal Request, N=1: - static const uint8_t cmd2[] = { 0x05, 0x00, 0x00, 0x71, 0xFF }; // REQB - // ... and HLTB - static const uint8_t cmd3[] = { 0x50, 0xff, 0xff, 0xff, 0xff }; // HLTB - // ... and ATTRIB - static const uint8_t cmd4[] = { 0x1D, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB - - // ... and we always respond with ATQB, PUPI = 820de174, Application Data = 0x20381922, - // supports only 106kBit/s in both directions, max frame size = 32Bytes, - // supports ISO14443-4, FWI=8 (77ms), NAD supported, CID not supported: - static const uint8_t response1[] = { - 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22, - 0x00, 0x21, 0x85, 0x5e, 0xd7 - }; - // response to HLTB and ATTRIB - static const uint8_t response2[] = {0x00, 0x78, 0xF0}; - - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - clear_trace(); - set_tracing(true); - - const uint8_t *resp; - uint8_t *respCode; - uint16_t respLen, respCodeLen; - - // allocate command receive buffer - BigBuf_free(); - uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - - uint16_t len; - uint16_t cmdsRecvd = 0; - - // prepare the (only one) tag answer: - CodeIso14443bAsTag(response1, sizeof(response1)); - uint8_t *resp1Code = BigBuf_malloc(ToSendMax); - memcpy(resp1Code, ToSend, ToSendMax); - uint16_t resp1CodeLen = ToSendMax; - - // prepare the (other) tag answer: - CodeIso14443bAsTag(response2, sizeof(response2)); - uint8_t *resp2Code = BigBuf_malloc(ToSendMax); - memcpy(resp2Code, ToSend, ToSendMax); - uint16_t resp2CodeLen = ToSendMax; - - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - - cmdsRecvd = 0; - - for(;;) { - - if(!GetIso14443bCommandFromReader(receivedCmd, &len)) { - Dbprintf("button pressed, received %d commands", cmdsRecvd); - break; - } - - LogTrace(receivedCmd, len, 0, 0, NULL, true); - - // Good, look at the command now. - if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) - || (len == sizeof(cmd2) && memcmp(receivedCmd, cmd2, len) == 0) ) { - resp = response1; - respLen = sizeof(response1); - respCode = resp1Code; - respCodeLen = resp1CodeLen; - } else if ( (len == sizeof(cmd3) && receivedCmd[0] == cmd3[0]) - || (len == sizeof(cmd4) && receivedCmd[0] == cmd4[0]) ) { - resp = response2; - respLen = sizeof(response2); - respCode = resp2Code; - respCodeLen = resp2CodeLen; - } else { - Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); - // And print whether the CRC fails, just for good measure - uint8_t b1, b2; - if (len >= 3){ // if crc exists - ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2); - if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) { - // Not so good, try again. - DbpString("+++CRC fail"); - - } else { - DbpString("CRC passes"); - } - } - //get rid of compiler warning - respCodeLen = 0; - resp = response1; - respLen = 0; - respCode = resp1Code; - //don't crash at new command just wait and see if reader will send other new cmds. - //break; - } - - cmdsRecvd++; - - if(cmdsRecvd > 0x30) { - DbpString("many commands later..."); - break; - } - - if(respCodeLen <= 0) continue; - - // Modulate BPSK - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); - AT91C_BASE_SSC->SSC_THR = 0xff; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - - // Transmit the response. - uint16_t i = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - uint8_t b = respCode[i]; - - AT91C_BASE_SSC->SSC_THR = b; - - i++; - if(i > respCodeLen) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - (void)b; - } - } - - // trace the response: - LogTrace(resp, respLen, 0, 0, NULL, false); - - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); -} - -//============================================================================= -// An ISO 14443 Type B reader. We take layer two commands, code them -// appropriately, and then send them to the tag. We then listen for the -// tag's response, which we leave in the buffer to be demodulated on the -// PC side. -//============================================================================= - -static struct { - enum { - DEMOD_UNSYNCD, - DEMOD_PHASE_REF_TRAINING, - DEMOD_AWAITING_FALLING_EDGE_OF_SOF, - DEMOD_GOT_FALLING_EDGE_OF_SOF, - DEMOD_AWAITING_START_BIT, - DEMOD_RECEIVING_DATA - } state; - int bitCount; - int posCount; - int thisBit; -/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. - int metric; - int metricN; -*/ - uint16_t shiftReg; - uint8_t *output; - int len; - int sumI; - int sumQ; -} Demod; - -/* - * Handles reception of a bit from the tag - * - * This function is called 2 times per bit (every 4 subcarrier cycles). - * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 4,72us - * - * LED handling: - * LED C -> ON once we have received the SOF and are expecting the rest. - * LED C -> OFF once we have received EOF or are unsynced - * - * Returns: true if we received a EOF - * false if we are still waiting for some more - * - */ -static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) -{ - int v; - -// The soft decision on the bit uses an estimate of just the -// quadrant of the reference angle, not the exact angle. -#define MAKE_SOFT_DECISION() { \ - if(Demod.sumI > 0) { \ - v = ci; \ - } else { \ - v = -ci; \ - } \ - if(Demod.sumQ > 0) { \ - v += cq; \ - } else { \ - v -= cq; \ - } \ - } - -#define SUBCARRIER_DETECT_THRESHOLD 8 - -// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) -#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2)) - switch(Demod.state) { - case DEMOD_UNSYNCD: - if(AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected - Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = ci; - Demod.sumQ = cq; - Demod.posCount = 1; - } - break; - - case DEMOD_PHASE_REF_TRAINING: - if(Demod.posCount < 8) { - if (AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) { - // set the reference phase (will code a logic '1') by averaging over 32 1/fs. - // note: synchronization time > 80 1/fs - Demod.sumI += ci; - Demod.sumQ += cq; - Demod.posCount++; - } else { // subcarrier lost - Demod.state = DEMOD_UNSYNCD; - } - } else { - Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; - } - break; - - case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: - MAKE_SOFT_DECISION(); - if(v < 0) { // logic '0' detected - Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; // start of SOF sequence - } else { - if(Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs - Demod.state = DEMOD_UNSYNCD; - } - } - Demod.posCount++; - break; - - case DEMOD_GOT_FALLING_EDGE_OF_SOF: - Demod.posCount++; - MAKE_SOFT_DECISION(); - if(v > 0) { - if(Demod.posCount < 9*2) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges - Demod.state = DEMOD_UNSYNCD; - } else { - LED_C_ON(); // Got SOF - Demod.posCount = 0; - Demod.bitCount = 0; - Demod.len = 0; - Demod.state = DEMOD_AWAITING_START_BIT; -/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. - Demod.metricN = 0; - Demod.metric = 0; -*/ - } - } else { - if(Demod.posCount > 12*2) { // low phase of SOF too long (> 12 etu) - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - } - } - break; - - case DEMOD_AWAITING_START_BIT: - Demod.posCount++; - MAKE_SOFT_DECISION(); - if (v > 0) { - if (Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs - LED_C_OFF(); - if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass - return true; - } else { - Demod.state = DEMOD_UNSYNCD; - } - } - } else { // start bit detected - Demod.posCount = 1; // this was the first half - Demod.thisBit = v; - Demod.shiftReg = 0; - Demod.state = DEMOD_RECEIVING_DATA; - } - break; - - case DEMOD_RECEIVING_DATA: - MAKE_SOFT_DECISION(); - if (Demod.posCount == 0) { // first half of bit - Demod.thisBit = v; - Demod.posCount = 1; - } else { // second half of bit - Demod.thisBit += v; - -/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. - if(Demod.thisBit > 0) { - Demod.metric += Demod.thisBit; - } else { - Demod.metric -= Demod.thisBit; - } - (Demod.metricN)++; -*/ - - Demod.shiftReg >>= 1; - if (Demod.thisBit > 0) { // logic '1' - Demod.shiftReg |= 0x200; - } - - Demod.bitCount++; - if (Demod.bitCount == 10) { - uint16_t s = Demod.shiftReg; - if ((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' - uint8_t b = (s >> 1); - Demod.output[Demod.len] = b; - Demod.len++; - Demod.bitCount = 0; - Demod.state = DEMOD_AWAITING_START_BIT; - } else { - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - if (s == 0x000) { - // This is EOF (start, stop and all data bits == '0' - return true; - } - } - } - Demod.posCount = 0; - } - break; - - default: - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - break; - } - - return false; -} - - -static void DemodReset() -{ - // Clear out the state of the "UART" that receives from the tag. - Demod.len = 0; - Demod.state = DEMOD_UNSYNCD; - Demod.posCount = 0; - memset(Demod.output, 0x00, MAX_FRAME_SIZE); -} - - -static void DemodInit(uint8_t *data) -{ - Demod.output = data; - DemodReset(); -} - - -/* - * Demodulate the samples we received from the tag, also log to tracebuffer - * quiet: set to 'true' to disable debug output - */ -static int GetSamplesFor14443bDemod(int timeout, bool quiet) { - int ret = 0; - int maxBehindBy = 0; - bool gotFrame = false; - int lastRxCounter, samples = 0; - int8_t ci, cq; - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); - - // The response (tag -> reader) that we're receiving. - uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); - - // The DMA buffer, used to stream samples from the FPGA - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); - - // Set up the demodulator for tag -> reader responses. - DemodInit(receivedResponse); - - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) - - // Setup and start DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); - - uint16_t *upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - - // Signal field is ON with the appropriate LED: - LED_D_ON(); - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); - - for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } - - if(behindBy < 1) continue; - - ci = *upTo >> 8; - cq = *upTo; - upTo++; - lastRxCounter--; - if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers - } - samples++; - - if (Handle14443bSamplesDemod(ci, cq)) { - ret = Demod.len; - gotFrame = true; - break; - } - - if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { - ret = -1; - LED_C_OFF(); - break; - } - } - - FpgaDisableSscDma(); - - if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); - - if (ret < 0) { - return ret; - } - //Tracing - LogTrace(Demod.output, Demod.len, 0, 0, NULL, false); - - return ret; -} - - -//----------------------------------------------------------------------------- -// Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitFor14443b(void) -{ - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - LED_B_ON(); - for(int c = 0; c < ToSendMax; c++) { - uint8_t data = ToSend[c]; - for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - data <<= 1; - } - WDT_HIT(); - } - LED_B_OFF(); -} - - -//----------------------------------------------------------------------------- -// Code a layer 2 command (string of octets, including CRC) into ToSend[], -// so that it is ready to transmit to the tag using TransmitFor14443b(). -//----------------------------------------------------------------------------- -static void CodeIso14443bAsReader(const uint8_t *cmd, int len) -{ - int i, j; - uint8_t b; - - ToSendReset(); - - // Send SOF - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - } - ToSendStuffBit(1); - ToSendStuffBit(1); - - for(i = 0; i < len; i++) { - // Start bit - ToSendStuffBit(0); - // Data bits - b = cmd[i]; - for(j = 0; j < 8; j++) { - if(b & 1) { - ToSendStuffBit(1); - } else { - ToSendStuffBit(0); - } - b >>= 1; - } - // Stop bit - ToSendStuffBit(1); - } - - // Send EOF - for(i = 0; i < 10; i++) { - ToSendStuffBit(0); - } - ToSendStuffBit(1); - - // ensure that last byte is filled up - for(i = 0; i < 8; i++) { - ToSendStuffBit(1); - } - - // Convert from last character reference to length - ToSendMax++; -} - - -/** - Convenience function to encode, transmit and trace iso 14443b comms - **/ -static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) -{ - CodeIso14443bAsReader(cmd, len); - TransmitFor14443b(); - LogTrace(cmd,len, 0, 0, NULL, true); -} - -/* Sends an APDU to the tag - * TODO: check CRC and preamble - */ -int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { - LED_A_ON(); - uint8_t message_frame[message_length + 4]; - // PCB - message_frame[0] = 0x0A | pcb_blocknum; - pcb_blocknum ^= 1; - // CID - message_frame[1] = 0; - // INF - memcpy(message_frame + 2, message, message_length); - // EDC (CRC) - ComputeCrc14443(CRC_14443_B, message_frame, message_length + 2, &message_frame[message_length + 2], &message_frame[message_length + 3]); - // send - CodeAndTransmit14443bAsReader(message_frame, message_length + 4); - // get response - int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - FpgaDisableTracing(); - if (ret < 3) { - LED_A_OFF(); - return 0; - } - // TODO: Check CRC - // copy response contents - if (response != NULL) { - memcpy(response, Demod.output, Demod.len); - } - LED_A_OFF(); - return ret; -} - -/* Perform the ISO 14443 B Card Selection procedure - * Currently does NOT do any collision handling. - * It expects 0-1 cards in the device's range. - * TODO: Support multiple cards (perform anticollision) - * TODO: Verify CRC checksums - */ -int iso14443b_select_card() -{ - // WUPB command (including CRC) - // Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state - static const uint8_t wupb[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; - // ATTRIB command (with space for CRC) - uint8_t attrib[] = { 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}; - - // first, wake up the tag - CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); - int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - // ATQB too short? - if (ret < 14) { - return 2; - } - - // select the tag - // copy the PUPI to ATTRIB - memcpy(attrib + 1, Demod.output + 1, 4); - /* copy the protocol info from ATQB (Protocol Info -> Protocol_Type) into - ATTRIB (Param 3) */ - attrib[7] = Demod.output[10] & 0x0F; - ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10); - CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); - ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - // Answer to ATTRIB too short? - if (ret < 3) { - return 2; - } - // reset PCB block number - pcb_blocknum = 0; - return 1; -} - -// Set up ISO 14443 Type B communication (similar to iso14443a_setup) -void iso14443b_setup() { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - // connect Demodulated Signal to ADC: - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Signal field is on with the appropriate LED - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - - DemodReset(); - UartReset(); -} - -//----------------------------------------------------------------------------- -// Read a SRI512 ISO 14443B tag. -// -// SRI512 tags are just simple memory tags, here we're looking at making a dump -// of the contents of the memory. No anticollision algorithm is done, we assume -// we have a single tag in the field. -// -// I tried to be systematic and check every answer of the tag, every CRC, etc... -//----------------------------------------------------------------------------- -void ReadSTMemoryIso14443b(uint32_t dwLast) -{ - LED_A_ON(); - uint8_t i = 0x00; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Make sure that we start from off, since the tags are stateful; - // confusing things will happen if we don't reset them between reads. - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - SpinDelay(200); - - clear_trace(); - set_tracing(true); - - // First command: wake up the tag using the INITIATE command - uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - - if (ret < 0) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("No response from tag"); - LEDsoff(); - return; - } else { - Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", - Demod.output[0], Demod.output[1], Demod.output[2]); - } - - // There is a response, SELECT the uid - DbpString("Now SELECT tag:"); - cmd1[0] = 0x0E; // 0x0E is SELECT - cmd1[1] = Demod.output[0]; - ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (Demod.len != 3) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); - LEDsoff(); - return; - } - // Check the CRC of the answer: - ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("CRC Error reading select response."); - LEDsoff(); - return; - } - // Check response from the tag: should be the same UID as the command we just sent: - if (cmd1[1] != Demod.output[0]) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); - LEDsoff(); - return; - } - - // Tag is now selected, - // First get the tag's UID: - cmd1[0] = 0x0B; - ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); - CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one - ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (ret != 10) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); - LEDsoff(); - return; - } - // The check the CRC of the answer (use cmd1 as temporary variable): - ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { - Dbprintf("CRC Error reading block! Expected: %04x got: %04x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); - // Do not return;, let's go on... (we should retry, maybe ?) - } - Dbprintf("Tag UID (64 bits): %08x %08x", - (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); - - // Now loop to read all 16 blocks, address from 0 to last block - Dbprintf("Tag memory dump, block 0 to %d", dwLast); - cmd1[0] = 0x08; - i = 0x00; - dwLast++; - for (;;) { - if (i == dwLast) { - DbpString("System area block (0xff):"); - i = 0xff; - } - cmd1[1] = i; - ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (ret != 6) { // Check if we got an answer from the tag - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Expected 6 bytes from tag, got less..."); - LEDsoff(); - return; - } - // The check the CRC of the answer (use cmd1 as temporary variable): - ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); - if (cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { - Dbprintf("CRC Error reading block! Expected: %04x got: %04x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); - // Do not return;, let's go on... (we should retry, maybe ?) - } - // Now print out the memory location: - Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", i, - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], - (Demod.output[4]<<8)+Demod.output[5]); - if (i == 0xff) { - break; - } - i++; - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - - -//============================================================================= -// Finally, the `sniffer' combines elements from both the reader and -// simulated tag, to show both sides of the conversation. -//============================================================================= - -//----------------------------------------------------------------------------- -// Record the sequence of commands sent by the reader to the tag, with -// triggering so that we start recording at the point that the tag is moved -// near the reader. -//----------------------------------------------------------------------------- -/* - * Memory usage for this function, (within BigBuf) - * Last Received command (reader->tag) - MAX_FRAME_SIZE - * Last Received command (tag->reader) - MAX_FRAME_SIZE - * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE - * Demodulated samples received - all the rest - */ -void RAMFUNC SnoopIso14443b(void) -{ - LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - BigBuf_free(); - - clear_trace(); - set_tracing(true); - - // The DMA buffer, used to stream samples from the FPGA - uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t)); - int lastRxCounter; - uint16_t *upTo; - int8_t ci, cq; - int maxBehindBy = 0; - - // Count of samples received so far, so that we can include timing - // information in the trace buffer. - int samples = 0; - - DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); - UartInit(BigBuf_malloc(MAX_FRAME_SIZE)); - - // Print some debug information about the buffer sizes - Dbprintf("Snooping buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); - - // Signal field is off - LED_D_OFF(); - - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNOOP_IQ); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Setup for the DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); - - bool TagIsActive = false; - bool ReaderIsActive = false; - // We won't start recording the frames that we acquire until we trigger. - // A good trigger condition to get started is probably when we see a - // reader command - bool triggered = false; - - // And now we loop, receiving samples. - for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } - - if(behindBy < 1) continue; - - ci = *upTo>>8; - cq = *upTo; - upTo++; - lastRxCounter--; - if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning again - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; - if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - break; - } - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers - WDT_HIT(); - if(BUTTON_PRESS()) { - DbpString("cancelled"); - break; - } - } - - samples++; - - if (!TagIsActive) { // no need to try decoding reader data if the tag is sending - if(Handle14443bUartBit(ci & 0x01)) { - triggered = true; - LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true); - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); - } - if(Handle14443bUartBit(cq & 0x01)) { - triggered = true; - LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true); - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); - } - ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); - } - - if (!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered - if (Handle14443bSamplesDemod(ci/2, cq/2) >= 0) { - //Use samples as a time measurement - LogTrace(Demod.output, Demod.len, samples, samples, NULL, false); - // And ready to receive another response. - DemodReset(); - } - TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF); - } - - } - - FpgaDisableSscDma(); - DbpString("Snoop statistics:"); - Dbprintf(" Max behind by: %i", maxBehindBy); - Dbprintf(" Uart State: %x", Uart.state); - Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt); - Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax); - Dbprintf(" Trace length: %i", BigBuf_get_traceLen()); - LEDsoff(); -} - - -/* - * Send raw command to tag ISO14443B - * @Input - * datalen len of buffer data - * recv bool when true wait for data from tag and send to client - * powerfield bool leave the field on when true - * data buffer with byte to send - * - * @Output - * none - * - */ -void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) -{ - LED_A_ON(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // switch field on and give tag some time to power up - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - SpinDelay(10); - - if (datalen){ - set_tracing(true); - - CodeAndTransmit14443bAsReader(data, datalen); - - if (recv) { - int ret = GetSamplesFor14443bDemod(5*RECEIVE_SAMPLES_TIMEOUT, true); - FpgaDisableTracing(); - uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); - cmd_send(CMD_ACK, ret, 0, 0, Demod.output, iLen); - } - - FpgaDisableTracing(); - } - - if (!powerfield) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - } - - LED_A_OFF(); -} - diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h deleted file mode 100644 index 3326ab12..00000000 --- a/armsrc/iso14443b.h +++ /dev/null @@ -1,27 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011 -// Gerhard de Koning Gans - May 2008 -// Hagen Fritsch - June 2010 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support ISO 14443 type B. -//----------------------------------------------------------------------------- - -#ifndef ISO14443B_H__ -#define ISO14443B_H__ - -#include -#include - -extern int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); -extern void iso14443b_setup(); -extern int iso14443b_select_card(); -extern void SimulateIso14443bTag(void); -extern void ReadSTMemoryIso14443b(uint32_t); -extern void SnoopIso14443b(void); -extern void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); - -#endif /* __ISO14443B_H */ diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f16698bb..63e72c14 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2,1393 +2,816 @@ // Jonathan Westhues, split Nov 2006 // Modified by Greg Jones, Jan 2009 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 -// Modified by piwi, Oct 2018 // // 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. //----------------------------------------------------------------------------- // Routines to support ISO 15693. This includes both the reader software and -// the `fake tag' modes. +// the `fake tag' modes, but at the moment I've implemented only the reader +// stuff, and that barely. +// Modified to perform modulation onboard in arm rather than on PC +// Also added additional reader commands (SELECT, READ etc.) //----------------------------------------------------------------------------- - -// The ISO 15693 describes two transmission modes from reader to tag, and four -// transmission modes from tag to reader. As of Oct 2018 this code supports -// both reader modes and the high speed variant with one subcarrier from card to reader. -// As long as the card fully support ISO 15693 this is no problem, since the -// reader chooses both data rates, but some non-standard tags do not. -// For card simulation, the code supports both high and low speed modes with one subcarrier. +// The ISO 15693 describes two transmission modes from reader to tag, and 4 +// transmission modes from tag to reader. As of Mar 2010 this code only +// supports one of each: "1of4" mode from reader to tag, and the highspeed +// variant with one subcarrier from card to reader. +// As long, as the card fully support ISO 15693 this is no problem, since the +// reader chooses both data rates, but some non-standard tags do not. Further for +// the simulation to work, we will need to support all data rates. // // VCD (reader) -> VICC (tag) // 1 out of 256: -// data rate: 1,66 kbit/s (fc/8192) -// used for long range +// data rate: 1,66 kbit/s (fc/8192) +// used for long range // 1 out of 4: -// data rate: 26,48 kbit/s (fc/512) -// used for short range, high speed -// +// data rate: 26,48 kbit/s (fc/512) +// used for short range, high speed +// // VICC (tag) -> VCD (reader) // Modulation: -// ASK / one subcarrier (423,75 khz) -// FSK / two subcarriers (423,75 khz && 484,28 khz) +// ASK / one subcarrier (423,75 khz) +// FSK / two subcarriers (423,75 khz && 484,28 khz) // Data Rates / Modes: -// low ASK: 6,62 kbit/s -// low FSK: 6.67 kbit/s -// high ASK: 26,48 kbit/s -// high FSK: 26,69 kbit/s +// low ASK: 6,62 kbit/s +// low FSK: 6.67 kbit/s +// high ASK: 26,48 kbit/s +// high FSK: 26,69 kbit/s //----------------------------------------------------------------------------- +// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911 // Random Remarks: // *) UID is always used "transmission order" (LSB), which is reverse to display order // TODO / BUGS / ISSUES: -// *) signal decoding is unable to detect collisions. -// *) add anti-collision support for inventory-commands +// *) writing to tags takes longer: we miss the answer from the tag in most cases +// -> tweak the read-timeout times +// *) signal decoding from the card is still a bit shaky. +// *) signal decoding is unable to detect collissions. +// *) add anti-collission support for inventory-commands // *) read security status of a block -// *) sniffing and simulation do not support two subcarrier modes. -// *) remove or refactor code under "deprecated" +// *) sniffing and simulation do only support one transmission mode. need to support +// all 8 transmission combinations +// *) remove or refactor code under "depricated" // *) document all the functions -#include "iso15693.h" #include "proxmark3.h" #include "util.h" #include "apps.h" #include "string.h" #include "iso15693tools.h" -#include "protocols.h" -#include "usb_cdc.h" -#include "BigBuf.h" -#include "fpgaloader.h" +#include "cmd.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) -// Delays in SSP_CLK ticks. -// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag -#define DELAY_READER_TO_ARM 8 -#define DELAY_ARM_TO_READER 0 -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 -#define DELAY_ARM_TO_TAG 16 -#define DELAY_TAG_TO_ARM 32 -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when snooping. All values should be multiples of 16 -#define DELAY_TAG_TO_ARM_SNOOP 32 -#define DELAY_READER_TO_ARM_SNOOP 32 - -// times in samples @ 212kHz when acting as reader -//#define ISO15693_READER_TIMEOUT 80 // 80/212kHz = 378us, nominal t1_max=313,9us -#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us, should be even enough for iClass tags responding to ACTALL -#define ISO15693_READER_TIMEOUT_WRITE 4700 // 4700/212kHz = 22ms, nominal 20ms - - -static int DEBUG = 0; - - /////////////////////////////////////////////////////////////////////// // ISO 15693 Part 2 - Air Interface -// This section basically contains transmission and receiving of bits +// This section basicly contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -// buffers -#define ISO15693_DMA_BUFFER_SIZE 256 // must be a power of 2 -#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet -#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF +#define Crc(data,datalen) Iso15693Crc(data,datalen) +#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) +#define sprintUID(target,uid) Iso15693sprintUID(target,uid) -// specific LogTrace function for ISO15693: the duration needs to be scaled because otherwise it won't fit into a uint16_t -bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { - uint32_t duration = timestamp_end - timestamp_start; - duration /= 32; - timestamp_end = timestamp_start + duration; - return LogTrace(btBytes, iLen, timestamp_start, timestamp_end, parity, readerToTag); -} +int DEBUG=0; // --------------------------- -// Signal Processing +// Signal Processing // --------------------------- // prepare data using "1 out of 4" code for later transmission -// resulting data rate is 26.48 kbit/s (fc/512) +// resulting data rate is 26,48 kbit/s (fc/512) // cmd ... data // n ... length of data -void CodeIso15693AsReader(uint8_t *cmd, int n) { +static void CodeIso15693AsReader(uint8_t *cmd, int n) +{ + int i, j; ToSendReset(); - // SOF for 1of4 - ToSend[++ToSendMax] = 0x84; //10000100 + // Give it a bit of slack at the beginning + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } - // data - for (int i = 0; i < n; i++) { - for (int j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 0x03; + // SOF for 1of4 + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + for(i = 0; i < n; i++) { + for(j = 0; j < 8; j += 2) { + int these = (cmd[i] >> j) & 3; switch(these) { case 0: - ToSend[++ToSendMax] = 0x40; //01000000 + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); break; case 1: - ToSend[++ToSendMax] = 0x10; //00010000 + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); break; case 2: - ToSend[++ToSendMax] = 0x04; //00000100 + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); break; case 3: - ToSend[++ToSendMax] = 0x01; //00000001 + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); break; } } } - // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); - ToSendMax++; + // And slack at the end, too. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } } - -// Encode EOF only -static void CodeIso15693AsReaderEOF() { - ToSendReset(); - ToSend[++ToSendMax] = 0x20; - ToSendMax++; -} - - -// encode data using "1 out of 256" scheme -// data rate is 1,66 kbit/s (fc/8192) +// encode data using "1 out of 256" sheme +// data rate is 1,66 kbit/s (fc/8192) // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { + int i, j; + ToSendReset(); + // Give it a bit of slack at the beginning + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } + // SOF for 1of256 - ToSend[++ToSendMax] = 0x81; //10000001 - - // data - for(int i = 0; i < n; i++) { - for (int j = 0; j <= 255; j++) { - if (cmd[i] == j) { - ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + + for(i = 0; i < n; i++) { + for (j = 0; j<=255; j++) { + if (cmd[i]==j) { ToSendStuffBit(1); + ToSendStuffBit(0); } else { - ToSendStuffBit(0); - ToSendStuffBit(0); - } - } + ToSendStuffBit(1); + ToSendStuffBit(1); + } + } } - // EOF - ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); - ToSendMax++; + // And slack at the end, too. + for(i = 0; i < 24; i++) { + ToSendStuffBit(1); + } } -// static uint8_t encode4Bits(const uint8_t b) { - // uint8_t c = b & 0xF; - // // OTA, the least significant bits first - // // The columns are - // // 1 - Bit value to send - // // 2 - Reversed (big-endian) - // // 3 - Manchester Encoded - // // 4 - Hex values +// Transmit the command (to the tag) that was placed in ToSend[]. +static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait) +{ + int c; - // switch(c){ - // // 1 2 3 4 - // case 15: return 0x55; // 1111 -> 1111 -> 01010101 -> 0x55 - // case 14: return 0x95; // 1110 -> 0111 -> 10010101 -> 0x95 - // case 13: return 0x65; // 1101 -> 1011 -> 01100101 -> 0x65 - // case 12: return 0xa5; // 1100 -> 0011 -> 10100101 -> 0xa5 - // case 11: return 0x59; // 1011 -> 1101 -> 01011001 -> 0x59 - // case 10: return 0x99; // 1010 -> 0101 -> 10011001 -> 0x99 - // case 9: return 0x69; // 1001 -> 1001 -> 01101001 -> 0x69 - // case 8: return 0xa9; // 1000 -> 0001 -> 10101001 -> 0xa9 - // case 7: return 0x56; // 0111 -> 1110 -> 01010110 -> 0x56 - // case 6: return 0x96; // 0110 -> 0110 -> 10010110 -> 0x96 - // case 5: return 0x66; // 0101 -> 1010 -> 01100110 -> 0x66 - // case 4: return 0xa6; // 0100 -> 0010 -> 10100110 -> 0xa6 - // case 3: return 0x5a; // 0011 -> 1100 -> 01011010 -> 0x5a - // case 2: return 0x9a; // 0010 -> 0100 -> 10011010 -> 0x9a - // case 1: return 0x6a; // 0001 -> 1000 -> 01101010 -> 0x6a - // default: return 0xaa; // 0000 -> 0000 -> 10101010 -> 0xaa +// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + if(*wait < 10) { *wait = 10; } - // } -// } +// for(c = 0; c < *wait;) { +// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { +// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! +// c++; +// } +// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { +// volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; +// (void)r; +// } +// WDT_HIT(); +// } -static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; - -void CodeIso15693AsTag(uint8_t *cmd, size_t len) { - /* - * SOF comprises 3 parts; - * * An unmodulated time of 56.64 us - * * 24 pulses of 423.75 kHz (fc/32) - * * A logic 1, which starts with an unmodulated time of 18.88us - * followed by 8 pulses of 423.75kHz (fc/32) - * - * EOF comprises 3 parts: - * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated - * time of 18.88us. - * - 24 pulses of fc/32 - * - An unmodulated time of 56.64 us - * - * A logic 0 starts with 8 pulses of fc/32 - * followed by an unmodulated time of 256/fc (~18,88us). - * - * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by - * 8 pulses of fc/32 (also 18.88us) - * - * A bit here becomes 8 pulses of fc/32. Therefore: - * The SOF can be written as 00011101 = 0x1D - * The EOF can be written as 10111000 = 0xb8 - * A logic 1 is 01 - * A logic 0 is 10 - * - * */ - - ToSendReset(); - - // SOF - ToSend[++ToSendMax] = 0x1D; // 00011101 - - // data - for (int i = 0; i < len; i++) { - ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; - ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; - } - - // EOF - ToSend[++ToSendMax] = 0xB8; // 10111000 - - ToSendMax++; + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + c++; + if(c >= len) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + *samples = (c + *wait) << 3; } - -// Transmit the command (to the tag) that was placed in cmd[]. -void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - - if (*start_time < DELAY_ARM_TO_TAG) { - *start_time = DELAY_ARM_TO_TAG; - } - - *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; - - if (GetCountSspClk() > *start_time) { // we may miss the intended time - *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time - } - - while (GetCountSspClk() < *start_time) - /* wait */ ; - - LED_B_ON(); - for (int c = 0; c < len; c++) { - uint8_t data = cmd[c]; - for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; - AT91C_BASE_SSC->SSC_THR = send_word; - data <<= 1; - } - WDT_HIT(); - } - LED_B_OFF(); - - *start_time = *start_time + DELAY_ARM_TO_TAG; -} - - //----------------------------------------------------------------------------- -// Transmit the tag response (to the reader) that was placed in cmd[]. +// Transmit the command (to the reader) that was placed in ToSend[]. //----------------------------------------------------------------------------- -void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { - // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); +static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait) +{ + int c; - uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF +// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR); // No requirement to energise my coils + if(*wait < 10) { *wait = 10; } - while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time - if (slot_time) { - modulation_start_time += slot_time; // use next available slot - } else { - modulation_start_time = (modulation_start_time & 0xfffffff8) + 8; // next possible time - } - } - - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) - /* wait */ ; - - uint8_t shift_delay = modulation_start_time & 0x00000007; - - *start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8; - - LED_C_ON(); - uint8_t bits_to_shift = 0x00; - uint8_t bits_to_send = 0x00; - for (size_t c = 0; c < len; c++) { - for (int i = (c==0?4:7); i >= 0; i--) { - uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; - for (int j = 0; j < (slow?4:1); ) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; - AT91C_BASE_SSC->SSC_THR = bits_to_send; - bits_to_shift = cmd_bits; - j++; - } - } - } - WDT_HIT(); - } - // send the remaining bits, padded with 0: - bits_to_send = bits_to_shift << (8 - shift_delay); - for ( ; ; ) { - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = bits_to_send; - break; - } - } - LED_C_OFF(); + c = 0; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = cmd[c]; + c++; + if(c >= len) { + break; + } + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + *samples = (c + *wait) << 3; } -//============================================================================= -// An ISO 15693 decoder for tag responses (one subcarrier only). -// Uses cross correlation to identify each bit and EOF. -// This function is called 8 times per bit (every 2 subcarrier cycles). -// Subcarrier frequency fs is 424kHz, 1/fs = 2,36us, -// i.e. function is called every 4,72us -// LED handling: -// LED C -> ON once we have received the SOF and are expecting the rest. -// LED C -> OFF once we have received EOF or are unsynced -// -// Returns: true if we received a EOF -// false if we are still waiting for some more -//============================================================================= +// Read from Tag +// Parameters: +// receivedResponse +// maxLen +// samples +// elapsed +// returns: +// number of decoded bytes +static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; -#define NOISE_THRESHOLD 80 // don't try to correlate noise -#define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD) - -typedef struct DecodeTag { - enum { - STATE_TAG_SOF_LOW, - STATE_TAG_SOF_RISING_EDGE, - STATE_TAG_SOF_HIGH, - STATE_TAG_SOF_HIGH_END, - STATE_TAG_RECEIVING_DATA, - STATE_TAG_EOF, - STATE_TAG_EOF_TAIL - } state; - int bitCount; - int posCount; - enum { - LOGIC0, - LOGIC1, - SOF_PART1, - SOF_PART2 - } lastBit; - uint16_t shiftReg; - uint16_t max_len; - uint8_t *output; - int len; - int sum1, sum2; - int threshold_sof; - int threshold_half; - uint16_t previous_amplitude; -} DecodeTag_t; - - -static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { - switch (DecodeTag->state) { - case STATE_TAG_SOF_LOW: - // waiting for a rising edge - if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { - if (DecodeTag->posCount > 10) { - DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; // to be divided by 2 - DecodeTag->threshold_half = 0; - DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; - } else { - DecodeTag->posCount = 0; - } - } else { - DecodeTag->posCount++; - DecodeTag->previous_amplitude = amplitude; - } - break; - - case STATE_TAG_SOF_RISING_EDGE: - if (amplitude > DecodeTag->threshold_sof + DecodeTag->previous_amplitude) { // edge still rising - if (amplitude > DecodeTag->threshold_sof + DecodeTag->threshold_sof) { // steeper edge, take this as time reference - DecodeTag->posCount = 1; - } else { - DecodeTag->posCount = 2; - } - DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; - } else { - DecodeTag->posCount = 2; - DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; - } - // DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_SOF_HIGH; - break; - - case STATE_TAG_SOF_HIGH: - // waiting for 10 times high. Take average over the last 8 - if (amplitude > DecodeTag->threshold_sof) { - DecodeTag->posCount++; - if (DecodeTag->posCount > 2) { - DecodeTag->threshold_half += amplitude; // keep track of average high value - } - if (DecodeTag->posCount == 10) { - DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) - DecodeTag->state = STATE_TAG_SOF_HIGH_END; - } - } else { // high phase was too short - DecodeTag->posCount = 1; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - } - break; - - case STATE_TAG_SOF_HIGH_END: - // check for falling edge - if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { - DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) - DecodeTag->shiftReg = 0; - DecodeTag->bitCount = 0; - DecodeTag->len = 0; - DecodeTag->sum1 = amplitude; - DecodeTag->sum2 = 0; - DecodeTag->posCount = 2; - DecodeTag->state = STATE_TAG_RECEIVING_DATA; - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING - LED_C_ON(); - } else { - DecodeTag->posCount++; - if (DecodeTag->posCount > 13) { // high phase too long - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - break; - - case STATE_TAG_RECEIVING_DATA: - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves - if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF - DecodeTag->state = STATE_TAG_EOF; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half - // logic 1 - if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF - DecodeTag->lastBit = SOF_PART2; // SOF completed - } else { - DecodeTag->lastBit = LOGIC1; - DecodeTag->shiftReg >>= 1; - DecodeTag->shiftReg |= 0x80; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { - // buffer overflow, give up - LED_C_OFF(); - return true; - } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; - } - } - } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half - // logic 0 - if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } else { - DecodeTag->lastBit = LOGIC0; - DecodeTag->shiftReg >>= 1; - DecodeTag->bitCount++; - if (DecodeTag->bitCount == 8) { - DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; - DecodeTag->len++; - // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING - if (DecodeTag->len > DecodeTag->max_len) { - // buffer overflow, give up - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - DecodeTag->bitCount = 0; - DecodeTag->shiftReg = 0; - } - } - } else { // no modulation - if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) - LED_C_OFF(); - return true; - } else { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount = 0; - } - DecodeTag->posCount++; - break; - - case STATE_TAG_EOF: - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_EOF_TAIL; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount++; - break; - - case STATE_TAG_EOF_TAIL: - if (DecodeTag->posCount == 1) { - DecodeTag->sum1 = 0; - DecodeTag->sum2 = 0; - } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += amplitude; - } else { - DecodeTag->sum2 += amplitude; - } - if (DecodeTag->posCount == 8) { - if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves - LED_C_OFF(); - return true; - } else { - DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = amplitude; - DecodeTag->state = STATE_TAG_SOF_LOW; - LED_C_OFF(); - } - } - DecodeTag->posCount++; - break; - } - - return false; -} - - -static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->output = data; - DecodeTag->max_len = max_len; -} - - -static void DecodeTagReset(DecodeTag_t *DecodeTag) { - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; -} - - -/* - * Receive and decode the tag response, also log to tracebuffer - */ -int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { - - int samples = 0; - int ret = 0; - - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - - // the Decoder data structure - DecodeTag_t DecodeTag = { 0 }; - DecodeTagInit(&DecodeTag, response, max_len); - - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); - - // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - - // Setup and start DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; + int8_t prev = 0; +// NOW READ RESPONSE + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads + c = 0; + getNext = FALSE; for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - - if (behindBy == 0) continue; - - samples++; - if (samples == 1) { - // DMA has transferred the very first data - dma_start_time = GetCountSspClk() & 0xfffffff0; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; - uint16_t tagdata = *upTo++; + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; - if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); - ret = -1; + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 2000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + } + } + + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// + + int i, j; + int max = 0, maxPos=0; + + int skip = 4; + + // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + + // First, correlate for SOF + for(i = 0; i < 100; i++) { + int corr = 0; + for(j = 0; j < arraylen(FrameSOF); j += skip) { + corr += FrameSOF[j]*dest[i+(j/skip)]; + } + if(corr > max) { + max = corr; + maxPos = i; + } + } + // DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); + + int k = 0; // this will be our return value + + // greg - If correlation is less than 1 then there's little point in continuing + if ((max/(arraylen(FrameSOF)/skip)) >= 1) + { + + i = maxPos + arraylen(FrameSOF)/skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j]*dest[i+(j/skip)]; + } + for(j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += arraylen(Logic1)/skip; + outBuf[k] |= mask; + } else { + i += arraylen(Logic0)/skip; + } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; + } + if((i+(int)arraylen(FrameEOF)) >= 2000) { + DbpString("ran off end!"); break; } } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + if(mask != 0x01) { // this happens, when we miss the EOF + // TODO: for some reason this happens quite often + if (DEBUG) Dbprintf("error, uneven octet! (extra bits!) mask=%02x", mask); + if (mask<0x08) k--; // discard the last uneven octet; + // 0x08 is an assumption - but works quite often } + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; + } + } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) + return k; // return the number of bytes demodulated - if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { - *eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { - *eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) +/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); + +} + + +// Now the GetISO15693 message from sniffing command +static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; + + int8_t prev = 0; + +// NOW READ RESPONSE + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads + c = 0; + getNext = FALSE; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; + + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 20000) { + break; + } + } else { + prev = b; } - if (DecodeTag.len > DecodeTag.max_len) { - ret = -2; // buffer overflow - } - break; - } - if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - ret = -1; // timeout - break; + getNext = !getNext; } - } - FpgaDisableSscDma(); + ////////////////////////////////////////// + /////////// DEMODULATE /////////////////// + ////////////////////////////////////////// - if (DEBUG) Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", - samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + int i, j; + int max = 0, maxPos=0; - if (ret < 0) { - return ret; + int skip = 4; + +// if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL + + // First, correlate for SOF + for(i = 0; i < 19000; i++) { + int corr = 0; + for(j = 0; j < arraylen(FrameSOF); j += skip) { + corr += FrameSOF[j]*dest[i+(j/skip)]; + } + if(corr > max) { + max = corr; + maxPos = i; + } } +// DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); - uint32_t sof_time = *eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + int k = 0; // this will be our return value - if (DEBUG) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); - - LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); - - return DecodeTag.len; -} - - -//============================================================================= -// An ISO15693 decoder for reader commands. -// -// This function is called 4 times per bit (every 2 subcarrier cycles). -// Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us -// LED handling: -// LED B -> ON once we have received the SOF and are expecting the rest. -// LED B -> OFF once we have received EOF or are in error state or unsynced -// -// Returns: true if we received a EOF -// false if we are still waiting for some more -//============================================================================= - -typedef struct DecodeReader { - enum { - STATE_READER_UNSYNCD, - STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, - STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, - STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, - STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, - STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4, - STATE_READER_RECEIVE_DATA_1_OUT_OF_4, - STATE_READER_RECEIVE_DATA_1_OUT_OF_256, - STATE_READER_RECEIVE_JAMMING - } state; - enum { - CODING_1_OUT_OF_4, - CODING_1_OUT_OF_256 - } Coding; - uint8_t shiftReg; - uint8_t bitCount; - int byteCount; - int byteCountMax; - int posCount; - int sum1, sum2; - uint8_t *output; - uint8_t jam_search_len; - uint8_t *jam_search_string; -} DecodeReader_t; - - -static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len, uint8_t jam_search_len, uint8_t *jam_search_string) { - DecodeReader->output = data; - DecodeReader->byteCountMax = max_len; - DecodeReader->state = STATE_READER_UNSYNCD; - DecodeReader->byteCount = 0; - DecodeReader->bitCount = 0; - DecodeReader->posCount = 1; - DecodeReader->shiftReg = 0; - DecodeReader->jam_search_len = jam_search_len; - DecodeReader->jam_search_string = jam_search_string; -} - - -static void DecodeReaderReset(DecodeReader_t* DecodeReader) { - DecodeReader->state = STATE_READER_UNSYNCD; -} - - -static int inline __attribute__((always_inline)) Handle15693SampleFromReader(bool bit, DecodeReader_t *DecodeReader) { - switch (DecodeReader->state) { - case STATE_READER_UNSYNCD: - // wait for unmodulated carrier - if (bit) { - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + // greg - If correlation is less than 1 then there's little point in continuing + if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 + { + + i = maxPos + arraylen(FrameSOF)/skip; + + uint8_t outBuf[20]; + memset(outBuf, 0, sizeof(outBuf)); + uint8_t mask = 0x01; + for(;;) { + int corr0 = 0, corr1 = 0, corrEOF = 0; + for(j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j]*dest[i+(j/skip)]; } - break; - - case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: - if (!bit) { - // we went low, so this could be the beginning of a SOF - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; + for(j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j]*dest[i+(j/skip)]; } - break; - - case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (bit) { // detected rising edge - if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { // SOF - DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; - } + for(j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j]*dest[i+(j/skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if(corrEOF > corr1 && corrEOF > corr0) { + // DbpString("EOF at %d", i); + break; + } else if(corr1 > corr0) { + i += arraylen(Logic1)/skip; + outBuf[k] |= mask; } else { - if (DecodeReader->posCount > 5) { // stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } + i += arraylen(Logic0)/skip; } - break; - - case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (!bit) { // detected a falling edge - if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) - DecodeReaderReset(DecodeReader); - } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding - DecodeReader->Coding = CODING_1_OUT_OF_4; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) - DecodeReaderReset(DecodeReader); - } else { // SOF for 1 out of 256 coding - DecodeReader->Coding = CODING_1_OUT_OF_256; - DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; - } - } else { - if (DecodeReader->posCount > 29) { // stayed high for too long - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - // do nothing, keep waiting - } + mask <<= 1; + if(mask == 0) { + k++; + mask = 0x01; } - break; - - case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: - DecodeReader->posCount++; - if (bit) { // detected rising edge - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; - LED_B_ON(); - } - } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; - } else { - DecodeReader->posCount = 1; - DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; - } - } - } else { - if (DecodeReader->Coding == CODING_1_OUT_OF_256) { - if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } - } else { // CODING_1_OUT_OF_4 - if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); - } else { - // do nothing, keep waiting - } - } - } - break; - - case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: - DecodeReader->posCount++; - if (bit) { - if (DecodeReader->posCount == 9) { - DecodeReader->posCount = 1; - DecodeReader->bitCount = 0; - DecodeReader->byteCount = 0; - DecodeReader->sum1 = 1; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; - LED_B_ON(); - } else { - // do nothing, keep waiting - } - } else { // unexpected falling edge - DecodeReaderReset(DecodeReader); - } - break; - - case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; - } else { - if (bit) DecodeReader->sum2++; - } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF - LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { - return true; - } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position - DecodeReader->shiftReg >>= 2; - DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); - } - if (DecodeReader->bitCount == 15) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { - // buffer overflow, give up - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - } - DecodeReader->bitCount = 0; - DecodeReader->shiftReg = 0; - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; - } - } - } else { - DecodeReader->bitCount++; - } - } - break; - - case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: - DecodeReader->posCount++; - if (DecodeReader->posCount == 1) { - DecodeReader->sum1 = bit?1:0; - } else if (DecodeReader->posCount <= 4) { - if (bit) DecodeReader->sum1++; - } else if (DecodeReader->posCount == 5) { - DecodeReader->sum2 = bit?1:0; - } else if (bit) { - DecodeReader->sum2++; - } - if (DecodeReader->posCount == 8) { - DecodeReader->posCount = 0; - if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF - LED_B_OFF(); // Finished receiving - DecodeReaderReset(DecodeReader); - if (DecodeReader->byteCount != 0) { - return true; - } - } else if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position - DecodeReader->shiftReg = DecodeReader->bitCount; - } - if (DecodeReader->bitCount == 255) { // we have a full byte - DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; - if (DecodeReader->byteCount > DecodeReader->byteCountMax) { - // buffer overflow, give up - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - } - if (DecodeReader->byteCount == DecodeReader->jam_search_len) { - if (!memcmp(DecodeReader->output, DecodeReader->jam_search_string, DecodeReader->jam_search_len)) { - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_JAM); - DecodeReader->state = STATE_READER_RECEIVE_JAMMING; - } - } - } - DecodeReader->bitCount++; - } - break; - - case STATE_READER_RECEIVE_JAMMING: - DecodeReader->posCount++; - if (DecodeReader->Coding == CODING_1_OUT_OF_4) { - if (DecodeReader->posCount == 7*16) { // 7 bits jammed - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming - // FpgaDisableTracing(); - LED_D_OFF(); - } else if (DecodeReader->posCount == 8*16) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; - } - } else { - if (DecodeReader->posCount == 7*256) { // 7 bits jammend - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); // stop jamming - LED_D_OFF(); - } else if (DecodeReader->posCount == 8*256) { - DecodeReader->posCount = 0; - DecodeReader->output[DecodeReader->byteCount++] = 0x00; - DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; - } - } - break; - - default: - LED_B_OFF(); - DecodeReaderReset(DecodeReader); - break; - } - - return false; -} - - -//----------------------------------------------------------------------------- -// Receive a command (from the reader to us, where we are the simulated tag), -// and store it in the given buffer, up to the given maximum length. Keeps -// spinning, waiting for a well-framed command, until either we get one -// (returns len) or someone presses the pushbutton on the board (returns -1). -// -// Assume that we're called with the SSC (to the FPGA) and ADC path set -// correctly. -//----------------------------------------------------------------------------- - -int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { - int samples = 0; - bool gotFrame = false; - uint8_t b; - - uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - - // the decoder data structure - DecodeReader_t DecodeReader = {0}; - DecodeReaderInit(&DecodeReader, received, max_len, 0, NULL); - - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); - - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); - - // clear receive register and wait for next transfer - uint32_t temp = AT91C_BASE_SSC->SSC_RHR; - (void) temp; - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; - - uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; - - // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint8_t *upTo = dmaBuf; - - for (;;) { - uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - - if (behindBy == 0) continue; - - b = *upTo++; - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + if((i+(int)arraylen(FrameEOF)) >= 2000) { + DbpString("ran off end!"); break; } } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + if(mask != 0x01) { + DbpString("sniff: error, uneven octet! (discard extra bits!)"); + /// DbpString(" mask=%02x", mask); } - - for (int i = 7; i >= 0; i--) { - if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { - *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF - gotFrame = true; - break; - } - samples++; + // uint8_t str1 [8]; + // itoa(k,str1); + // strncat(str1," octets read",8); + + // DbpString( str1); // DbpString("%d octets", k); + + // for(i = 0; i < k; i+=3) { + // //DbpString("# %2d: %02x ", i, outBuf[i]); + // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); + // } + + for(i = 0; i < k; i++) { + receivedResponse[i] = outBuf[i]; } + } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) + return k; // return the number of bytes demodulated - if (gotFrame) { - break; - } - - if (BUTTON_PRESS()) { - DecodeReader.byteCount = -1; - break; - } - - WDT_HIT(); - } - - FpgaDisableSscDma(); - - if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); - - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = *eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - - 32 // time for SOF transfer - - 16; // time for EOF transfer - LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); - } - - return DecodeReader.byteCount; -} - - -// Construct an identify (Inventory) request, which is the first -// thing that you must send to a tag to get a response. -static void BuildIdentifyRequest(uint8_t *cmd) { - uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1 | ISO15693_REQ_DATARATE_HIGH; - // inventory command code - cmd[1] = 0x01; - // no mask - cmd[2] = 0x00; - //Now the CRC - crc = Iso15693Crc(cmd, 3); - cmd[3] = crc & 0xff; - cmd[4] = crc >> 8; +/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); } +static void BuildIdentifyRequest(void); //----------------------------------------------------------------------------- // Start to read an ISO 15693 tag. We send an identify request, then wait // for the response. The response is not demodulated, just left in the buffer // so that it can be downloaded to a PC and processed there. //----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso15693(void) { - LED_A_ON(); +void AcquireRawAdcSamplesIso15693(void) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; - uint8_t *dest = BigBuf_get_addr(); + int8_t prev = 0; + + BuildIdentifyRequest(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - LED_D_ON(); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - uint8_t cmd[5]; - BuildIdentifyRequest(cmd); - CodeIso15693AsReader(cmd, sizeof(cmd)); - // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(100); // Now send the command - uint32_t start_time = 0; - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); - - for(int c = 0; c < 4000; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint16_t r = AT91C_BASE_SSC->SSC_RHR; - dest[c++] = r >> 5; - } - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - - -void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string) { - - LED_A_ON(); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - clear_trace(); - set_tracing(true); - - // The DMA buffer, used to stream samples from the FPGA - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - - // Count of samples received so far, so that we can include timing - // information in the trace buffer. - int samples = 0; - - DecodeTag_t DecodeTag = {0}; - uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; - DecodeTagInit(&DecodeTag, response, sizeof(response)); - - DecodeReader_t DecodeReader = {0}; - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd), jam_search_len, jam_search_string); - - // Print some debug information about the buffer sizes - if (DEBUG) { - Dbprintf("Snooping buffers initialized:"); - Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); - Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); - Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); - Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); - } - Dbprintf("Snoop started. Press PM3 Button to stop."); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); - LED_D_OFF(); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - StartCountSspClk(); - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - - bool TagIsActive = false; - bool ReaderIsActive = false; - bool ExpectTagAnswer = false; - uint32_t dma_start_time = 0; - uint16_t *upTo = dmaBuf; - - uint16_t max_behindBy = 0; - - // And now we loop, receiving samples. + c = 0; for(;;) { - uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy > max_behindBy) { - max_behindBy = behindBy; - } - - if (behindBy == 0) continue; - - samples++; - if (samples == 1) { - // DMA has transferred the very first data - dma_start_time = GetCountSspClk() & 0xfffffff0; - } - - uint16_t snoopdata = *upTo++; - - if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. - upTo = dmaBuf; // start reading the circular buffer from the beginning - if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { - // FpgaDisableTracing(); - Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = ToSend[c]; + c++; + if(c == ToSendMax+3) { break; } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers - WDT_HIT(); - if (BUTTON_PRESS()) { - DbpString("Snoop stopped."); - break; - } - } } - - if (!TagIsActive) { // no need to try decoding reader data if the tag is sending - if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { - // FpgaDisableSscDma(); - uint32_t eof_time = dma_start_time + samples*16 + 8 - DELAY_READER_TO_ARM_SNOOP; // end of EOF - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); - } - /* And ready to receive another command. */ - DecodeReaderReset(&DecodeReader); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; - // upTo = dmaBuf; - // samples = 0; - // FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - // continue; - } else if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) { - // FpgaDisableSscDma(); - uint32_t eof_time = dma_start_time + samples*16 + 16 - DELAY_READER_TO_ARM_SNOOP; // end of EOF - if (DecodeReader.byteCount > 0) { - uint32_t sof_time = eof_time - - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128*16:2048*16) // time for byte transfers - - 32*16 // time for SOF transfer - - 16*16; // time for EOF transfer - LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, sof_time*4, eof_time*4, NULL, true); - } - /* And ready to receive another command. */ - DecodeReaderReset(&DecodeReader); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DecodeTagReset(&DecodeTag); - ReaderIsActive = false; - ExpectTagAnswer = true; - // upTo = dmaBuf; - // samples = 0; - // FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - // continue; - } else { - ReaderIsActive = (DecodeReader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4); - } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; } - - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet - if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { - // FpgaDisableSscDma(); - uint32_t eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM_SNOOP; // end of EOF - if (DecodeTag.lastBit == SOF_PART2) { - eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) - } - uint32_t sof_time = eof_time - - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - - 32 * 16 // time for SOF transfer - - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, sof_time*4, eof_time*4, NULL, false); - // And ready to receive another response. - DecodeTagReset(&DecodeTag); - DecodeReaderReset(&DecodeReader); - ExpectTagAnswer = false; - TagIsActive = false; - // upTo = dmaBuf; - // samples = 0; - // FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - // continue; - } else { - TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); - } - } - + WDT_HIT(); } - FpgaDisableSscDma(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - DbpString("Snoop statistics:"); - Dbprintf(" ExpectTagAnswer: %d, TagIsActive: %d, ReaderIsActive: %d", ExpectTagAnswer, TagIsActive, ReaderIsActive); - Dbprintf(" DecodeTag State: %d", DecodeTag.state); - Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); - Dbprintf(" DecodeTag posCount: %d", DecodeTag.posCount); - Dbprintf(" DecodeReader State: %d", DecodeReader.state); - Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); - Dbprintf(" DecodeReader posCount: %d", DecodeReader.posCount); - Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); - Dbprintf(" Max behindBy: %d", max_behindBy); + c = 0; + getNext = FALSE; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; + + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 2000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + } + } } -// Initialize the proxmark as iso15k reader -void Iso15693InitReader(void) { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); +void RecordRawAdcSamplesIso15693(void) +{ + int c = 0; + uint8_t *dest = (uint8_t *)BigBuf; + int getNext = 0; - // switch field off and wait until tag resets - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelay(10); + int8_t prev = 0; + + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - // switch field on - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); - LED_D_ON(); - - // initialize SSC and select proper AD input - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // give tags some time to energize + SpinDelay(100); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + + c = 0; + getNext = FALSE; + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + int8_t b; + b = (int8_t)AT91C_BASE_SSC->SSC_RHR; + + // The samples are correlations against I and Q versions of the + // tone that the tag AM-modulates, so every other sample is I, + // every other is Q. We just want power, so abs(I) + abs(Q) is + // close to what we want. + if(getNext) { + int8_t r; + + if(b < 0) { + r = -b; + } else { + r = b; + } + if(prev < 0) { + r -= prev; + } else { + r += prev; + } + + dest[c++] = (uint8_t)r; + + if(c >= 7000) { + break; + } + } else { + prev = b; + } + + getNext = !getNext; + WDT_HIT(); + } + } + Dbprintf("fin record"); +} + + +// Initialize the proxmark as iso15k reader +// (this might produces glitches that confuse some tags +void Iso15693InitReader() { + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + // Setup SSC + // FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(10); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(250); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); } /////////////////////////////////////////////////////////////////////// // ISO 15693 Part 3 - Air Interface -// This section basically contains transmission and receiving of bits +// This section basicly contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// +// Encode (into the ToSend buffers) an identify request, which is the first +// thing that you must send to a tag to get a response. +static void BuildIdentifyRequest(void) +{ + uint8_t cmd[5]; + + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); + // inventory command code + cmd[1] = 0x01; + // no mask + cmd[2] = 0x00; + //Now the CRC + crc = Crc(cmd, 3); + cmd[3] = crc & 0xff; + cmd[4] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} // uid is in transmission order (which is reverse of display order) -static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber, uint8_t *cmd) { +static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) +{ + uint8_t cmd[13]; + uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the security status of the block - // followed by the block data - cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data + // one sub-carrier, inventory, 1 slot, fast rate + cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit // READ BLOCK command code - cmd[1] = ISO15693_READBLOCK; + cmd[1] = 0x20; // UID may be optionally specified here // 64-bit UID cmd[2] = uid[0]; @@ -1400,96 +823,97 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber, uint8_t *cm cmd[8] = uid[6]; cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) // Block number to read - cmd[10] = blockNumber; + cmd[10] = blockNumber;//0x00; //Now the CRC - crc = Iso15693Crc(cmd, 11); // the crc needs to be calculated over 11 bytes + crc = Crc(cmd, 11); // the crc needs to be calculated over 12 bytes cmd[11] = crc & 0xff; cmd[12] = crc >> 8; + CodeIso15693AsReader(cmd, sizeof(cmd)); } - // Now the VICC>VCD responses when we are simulating a tag -static void BuildInventoryResponse(uint8_t *uid) { + static void BuildInventoryResponse(void) +{ uint8_t cmd[12]; uint16_t crc; - - cmd[0] = 0; // No error, no protocol format extension - cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = 0; //(1 << 2) | (1 << 5) | (1 << 1); + cmd[1] = 0; // 64-bit UID - cmd[2] = uid[7]; //0x32; - cmd[3] = uid[6]; //0x4b; - cmd[4] = uid[5]; //0x03; - cmd[5] = uid[4]; //0x01; - cmd[6] = uid[3]; //0x00; - cmd[7] = uid[2]; //0x10; - cmd[8] = uid[1]; //0x05; - cmd[9] = uid[0]; //0xe0; + cmd[2] = 0x32; + cmd[3]= 0x4b; + cmd[4] = 0x03; + cmd[5] = 0x01; + cmd[6] = 0x00; + cmd[7] = 0x10; + cmd[8] = 0x05; + cmd[9]= 0xe0; //Now the CRC - crc = Iso15693Crc(cmd, 10); + crc = Crc(cmd, 10); cmd[10] = crc & 0xff; cmd[11] = crc >> 8; - CodeIso15693AsTag(cmd, sizeof(cmd)); + CodeIso15693AsReader(cmd, sizeof(cmd)); } // Universal Method for sending to and recv bytes from a tag -// init ... should we initialize the reader? -// speed ... 0 low speed, 1 hi speed -// *recv will contain the tag's answer -// return: length of received data, or -1 for timeout -int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { +// init ... should we initialize the reader? +// speed ... 0 low speed, 1 hi speed +// **recv will return you a pointer to the received data +// If you do not need the answer use NULL for *recv[] +// return: lenght of received data +int SendDataTag(uint8_t *send, int sendlen, int init, int speed, uint8_t **recv) { - if (init) { - Iso15693InitReader(); - StartCountSspClk(); - } + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + + int answerLen=0; + uint8_t *answer = (((uint8_t *)BigBuf) + 3660); + if (recv!=NULL) memset(BigBuf + 3660, 0, 100); - int answerLen = 0; - - if (speed_fast) { - // high speed (1 out of 4) - CodeIso15693AsReader(send, sendlen); - } else { + if (init) Iso15693InitReader(); + + if (!speed) { // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); + } else { + // high speed (1 out of 4) + CodeIso15693AsReader(send, sendlen); } - - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF - LogTrace_ISO15693(send, sendlen, start_time*4, end_time*4, NULL, true); - + + LED_A_ON(); + LED_B_OFF(); + + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // Now wait for a response - if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); - } - - return answerLen; -} - - -int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time) { - - int answerLen = 0; - - CodeIso15693AsReaderEOF(); - - TransmitTo15693Tag(ToSend, ToSendMax, &start_time); - uint32_t end_time = start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF - LogTrace_ISO15693(NULL, 0, start_time*4, end_time*4, NULL, true); - - // Now wait for a response - if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + if (recv!=NULL) { + LED_A_OFF(); + LED_B_ON(); + answerLen = GetIso15693AnswerFromTag(answer, 100, &samples, &elapsed) ; + *recv=answer; } + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); + return answerLen; } // -------------------------------------------------------------------- -// Debug Functions +// Debug Functions // -------------------------------------------------------------------- // Decodes a message from a tag and displays its metadata and content @@ -1498,53 +922,53 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { char status[DBD15STATLEN+1]={0}; uint16_t crc; - if (len > 3) { - if (d[0] & ISO15693_RES_EXT) - strncat(status,"ProtExt ", DBD15STATLEN); - if (d[0] & ISO15693_RES_ERROR) { + if (len>3) { + if (d[0]&(1<<3)) + strncat(status,"ProtExt ",DBD15STATLEN); + if (d[0]&1) { // error - strncat(status,"Error ", DBD15STATLEN); + strncat(status,"Error ",DBD15STATLEN); switch (d[1]) { - case 0x01: - strncat(status,"01:notSupp", DBD15STATLEN); + case 0x01: + strncat(status,"01:notSupp",DBD15STATLEN); break; - case 0x02: - strncat(status,"02:notRecog", DBD15STATLEN); + case 0x02: + strncat(status,"02:notRecog",DBD15STATLEN); break; - case 0x03: - strncat(status,"03:optNotSupp", DBD15STATLEN); + case 0x03: + strncat(status,"03:optNotSupp",DBD15STATLEN); break; - case 0x0f: - strncat(status,"0f:noInfo", DBD15STATLEN); + case 0x0f: + strncat(status,"0f:noInfo",DBD15STATLEN); break; - case 0x10: - strncat(status,"10:doesn'tExist", DBD15STATLEN); + case 0x10: + strncat(status,"10:dontExist",DBD15STATLEN); break; - case 0x11: - strncat(status,"11:lockAgain", DBD15STATLEN); + case 0x11: + strncat(status,"11:lockAgain",DBD15STATLEN); break; - case 0x12: - strncat(status,"12:locked", DBD15STATLEN); + case 0x12: + strncat(status,"12:locked",DBD15STATLEN); break; - case 0x13: - strncat(status,"13:progErr", DBD15STATLEN); + case 0x13: + strncat(status,"13:progErr",DBD15STATLEN); break; - case 0x14: - strncat(status,"14:lockErr", DBD15STATLEN); + case 0x14: + strncat(status,"14:lockErr",DBD15STATLEN); break; default: - strncat(status,"unknownErr", DBD15STATLEN); + strncat(status,"unknownErr",DBD15STATLEN); } - strncat(status," ", DBD15STATLEN); + strncat(status," ",DBD15STATLEN); } else { - strncat(status,"NoErr ", DBD15STATLEN); + strncat(status,"NoErr ",DBD15STATLEN); } - - crc=Iso15693Crc(d,len-2); - if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) + + crc=Crc(d,len-2); + if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) strncat(status,"CrcOK",DBD15STATLEN); else - strncat(status,"CrcFail!",DBD15STATLEN); + strncat(status,"CrcFail!",DBD15STATLEN); Dbprintf("%s",status); } @@ -1563,297 +987,306 @@ void SetDebugIso15693(uint32_t debug) { } -//--------------------------------------------------------------------------------------- -// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector. + +//----------------------------------------------------------------------------- +// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg -//--------------------------------------------------------------------------------------- -void ReaderIso15693(uint32_t parameter) { +//----------------------------------------------------------------------------- +void ReaderIso15693(uint32_t parameter) +{ + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); + +//DbpString(parameter); + + //uint8_t *answer0 = (((uint8_t *)BigBuf) + 3560); // allow 100 bytes per reponse (way too much) + uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // + uint8_t *answer2 = (((uint8_t *)BigBuf) + 3760); + uint8_t *answer3 = (((uint8_t *)BigBuf) + 3860); + //uint8_t *TagUID= (((uint8_t *)BigBuf) + 3960); // where we hold the uid for hi15reader +// int answerLen0 = 0; + int answerLen1 = 0; + int answerLen2 = 0; + int answerLen3 = 0; + int i=0; // counter + + // Blank arrays + memset(BigBuf + 3660, 0, 300); + + // Setup SSC + FpgaSetupSsc(); + + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + SpinDelay(200); LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); - set_tracing(true); - - uint8_t TagUID[8] = {0x00}; - uint8_t answer[ISO15693_MAX_RESPONSE_LENGTH]; + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME + uint8_t TagUID[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // where we hold the uid for hi15reader + +// BuildIdentifyRequest(); +// //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); +// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 +// // Now wait for a response +// responseLen0 = GetIso15693AnswerFromTag(receivedAnswer0, 100, &samples, &elapsed) ; +// if (responseLen0 >=12) // we should do a better check than this +// { +// // really we should check it is a valid mesg +// // but for now just grab what we think is the uid +// TagUID[0] = receivedAnswer0[2]; +// TagUID[1] = receivedAnswer0[3]; +// TagUID[2] = receivedAnswer0[4]; +// TagUID[3] = receivedAnswer0[5]; +// TagUID[4] = receivedAnswer0[6]; +// TagUID[5] = receivedAnswer0[7]; +// TagUID[6] = receivedAnswer0[8]; // IC Manufacturer code +// DbpIntegers(TagUID[6],TagUID[5],TagUID[4]); +//} // Now send the IDENTIFY command - uint8_t cmd[5]; - BuildIdentifyRequest(cmd); - uint32_t start_time = 0; - uint32_t eof_time; - int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, sizeof(answer), start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + BuildIdentifyRequest(); + //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 + // Now wait for a response + answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ; + + if (answerLen1 >=12) // we should do a better check than this + { + + TagUID[0] = answer1[2]; + TagUID[1] = answer1[3]; + TagUID[2] = answer1[4]; + TagUID[3] = answer1[5]; + TagUID[4] = answer1[6]; + TagUID[5] = answer1[7]; + TagUID[6] = answer1[8]; // IC Manufacturer code + TagUID[7] = answer1[9]; // always E0 + + // Now send the SELECT command + // since the SELECT command is optional, we should not rely on it. +//// BuildSelectRequest(TagUID); +// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 + // Now wait for a response +/// answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + + // Now send the MULTI READ command +// BuildArbitraryRequest(*TagUID,parameter); +/// BuildArbitraryCustomRequest(TagUID,parameter); +// BuildReadBlockRequest(*TagUID,parameter); +// BuildSysInfoRequest(*TagUID); + //TransmitTo15693Tag(ToSend,ToSendMax+3,&tsamples, &wait); +/// TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); // No longer ToSendMax+3 + // Now wait for a response +/// answerLen3 = GetIso15693AnswerFromTag(answer3, 100, &samples, &elapsed) ; - if (answerLen >= 12) { // we should do a better check than this - TagUID[0] = answer[2]; - TagUID[1] = answer[3]; - TagUID[2] = answer[4]; - TagUID[3] = answer[5]; - TagUID[4] = answer[6]; - TagUID[5] = answer[7]; - TagUID[6] = answer[8]; // IC Manufacturer code - TagUID[7] = answer[9]; // always E0 } - Dbprintf("%d octets read from IDENTIFY request:", answerLen); - DbdecodeIso15693Answer(answerLen, answer); - Dbhexdump(answerLen, answer, false); + Dbprintf("%d octets read from IDENTIFY request:", answerLen1); + DbdecodeIso15693Answer(answerLen1,answer1); + Dbhexdump(answerLen1,answer1,true); // UID is reverse - if (answerLen >= 12) - Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", - TagUID[7],TagUID[6],TagUID[5],TagUID[4], - TagUID[3],TagUID[2],TagUID[1],TagUID[0]); + if (answerLen1>=12) + //Dbprintf("UID = %*D",8,TagUID," "); + Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX",TagUID[7],TagUID[6],TagUID[5], + TagUID[4],TagUID[3],TagUID[2],TagUID[1],TagUID[0]); + + Dbprintf("%d octets read from SELECT request:", answerLen2); + DbdecodeIso15693Answer(answerLen2,answer2); + Dbhexdump(answerLen2,answer2,true); + + Dbprintf("%d octets read from XXX request:", answerLen3); + DbdecodeIso15693Answer(answerLen3,answer3); + Dbhexdump(answerLen3,answer3,true); + + // read all pages - if (answerLen >= 12 && DEBUG) { - for (int i = 0; i < 32; i++) { // sanity check, assume max 32 pages - uint8_t cmd[13]; - BuildReadBlockRequest(TagUID, i, cmd); - answerLen = SendDataTag(cmd, sizeof(cmd), false, true, answer, sizeof(answer), start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - if (answerLen > 0) { - Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen); - DbdecodeIso15693Answer(answerLen, answer); - Dbhexdump(answerLen, answer, false); - if ( *((uint32_t*) answer) == 0x07160101 ) break; // exit on NoPageErr - } - } + if (answerLen1>=12 && DEBUG) { + i=0; + while (i<32) { // sanity check, assume max 32 pages + BuildReadBlockRequest(TagUID,i); + TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait); + answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed); + if (answerLen2>0) { + Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); + DbdecodeIso15693Answer(answerLen2,answer2); + Dbhexdump(answerLen2,answer2,true); + if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr + } + i++; + } } - // for the time being, switch field off to protect RDV4 - // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); +// str2[0]=0; +// for(i = 0; i < responseLen3; i++) { +// itoa(str1,receivedAnswer3[i]); +// strncat(str2,str1,8); +// } +// DbpString(str2); LED_A_OFF(); -} - - -// Initialize the proxmark as iso15k tag -void Iso15693InitTag(void) { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + LED_B_OFF(); + LED_C_OFF(); LED_D_OFF(); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - StartCountSspClk(); } - -// Simulate an ISO15693 TAG. -// For Inventory command: print command and send Inventory Response with given UID -// TODO: interpret other reader commands and send appropriate response -void SimTagIso15693(uint32_t parameter, uint8_t *uid) { - +// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands +// all demodulation performed in arm rather than host. - greg +void SimTagIso15693(uint32_t parameter) +{ LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + LED_D_OFF(); - Iso15693InitTag(); + uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); // + int answerLen1 = 0; - // Build a suitable response to the reader INVENTORY command - BuildInventoryResponse(uid); + // Blank arrays + memset(answer1, 0, 100); - // Listen to reader - while (!BUTTON_PRESS()) { - uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; - uint32_t eof_time = 0, start_time = 0; - int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); + // Setup SSC + FpgaSetupSsc(); - if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags - bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; - TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); - } + // Start from off (no field generated) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - Dbprintf("%d bytes read from reader:", cmd_len); - Dbhexdump(cmd_len, cmd, false); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + // Give the tags time to energize +// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); // NO GOOD FOR SIM TAG!!!! + SpinDelay(200); + + LED_A_OFF(); + LED_B_OFF(); + LED_C_ON(); + LED_D_OFF(); + + int samples = 0; + int tsamples = 0; + int wait = 0; + int elapsed = 0; + + answerLen1 = GetIso15693AnswerFromSniff(answer1, 100, &samples, &elapsed) ; + + if (answerLen1 >=1) // we should do a better check than this + { + // Build a suitable reponse to the reader INVENTORY cocmmand + BuildInventoryResponse(); + TransmitTo15693Reader(ToSend,ToSendMax, &tsamples, &wait); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1, + answer1[0], answer1[1], answer1[2], + answer1[3], answer1[4], answer1[5], + answer1[6], answer1[7], answer1[8]); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); } // Since there is no standardized way of reading the AFI out of a tag, we will brute force it // (some manufactures offer a way to read the AFI, though) -void BruteforceIso15693Afi(uint32_t speed) { - LED_A_ON(); - - uint8_t data[6]; - uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; - int datalen = 0, recvlen = 0; - uint32_t eof_time; - +void BruteforceIso15693Afi(uint32_t speed) +{ + uint8_t data[20]; + uint8_t *recv=data; + int datalen=0, recvlen=0; + + Iso15693InitReader(); + // first without AFI - // Tags should respond without AFI and with AFI=0 even when AFI is active - - data[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; - data[1] = ISO15693_INVENTORY; - data[2] = 0; // mask length - datalen = Iso15693AddCrc(data,3); - uint32_t start_time = GetCountSspClk(); - recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + // Tags should respond wihtout AFI and with AFI=0 even when AFI is active + + data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + data[1]=ISO15_CMD_INVENTORY; + data[2]=0; // mask length + datalen=AddCrc(data,3); + recvlen=SendDataTag(data,datalen,0,speed,&recv); WDT_HIT(); if (recvlen>=12) { - Dbprintf("NoAFI UID=%s", Iso15693sprintUID(NULL, &recv[2])); + Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2])); } - + // now with AFI - - data[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_AFI | ISO15693_REQINV_SLOT1; - data[1] = ISO15693_INVENTORY; - data[2] = 0; // AFI - data[3] = 0; // mask length - - for (int i = 0; i < 256; i++) { - data[2] = i & 0xFF; - datalen = Iso15693AddCrc(data,4); - recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_AFI | ISO15_REQINV_SLOT1; + data[1]=ISO15_CMD_INVENTORY; + data[2]=0; // AFI + data[3]=0; // mask length + + for (int i=0;i<256;i++) { + data[2]=i & 0xFF; + datalen=AddCrc(data,4); + recvlen=SendDataTag(data,datalen,0,speed,&recv); WDT_HIT(); - if (recvlen >= 12) { - Dbprintf("AFI=%i UID=%s", i, Iso15693sprintUID(NULL, &recv[2])); + if (recvlen>=12) { + Dbprintf("AFI=%i UID=%s",i,sprintUID(NULL,&recv[2])); } - } + } Dbprintf("AFI Bruteforcing done."); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - LED_A_OFF(); - + } // Allows to directly send commands to the tag via the client -void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]) { +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]) { - LED_A_ON(); - - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time; - - uint16_t timeout; - bool request_answer = false; + int recvlen=0; + uint8_t *recvbuf=(uint8_t *)BigBuf; +// UsbCommand n; - switch (data[1]) { - case ISO15693_WRITEBLOCK: - case ISO15693_LOCKBLOCK: - case ISO15693_WRITE_MULTI_BLOCK: - case ISO15693_WRITE_AFI: - case ISO15693_LOCK_AFI: - case ISO15693_WRITE_DSFID: - case ISO15693_LOCK_DSFID: - timeout = ISO15693_READER_TIMEOUT_WRITE; - request_answer = data[0] & ISO15693_REQ_OPTION; - break; - default: - timeout = ISO15693_READER_TIMEOUT; - } - if (DEBUG) { - Dbprintf("SEND:"); - Dbhexdump(datalen, data, false); - } - - recvlen = SendDataTag(data, datalen, true, speed, (recv?recvbuf:NULL), sizeof(recvbuf), 0, timeout, &eof_time); - - if (request_answer) { // send a single EOF to get the tag response - recvlen = SendDataTagEOF((recv?recvbuf:NULL), sizeof(recvbuf), 0, ISO15693_READER_TIMEOUT, &eof_time); + Dbprintf("SEND"); + Dbhexdump(datalen,data,true); } - // for the time being, switch field off to protect rdv4.0 - // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); + recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL)); - if (recv) { + if (recv) { +// n.cmd=/* CMD_ISO_15693_COMMAND_DONE */ CMD_ACK; +// n.arg[0]=recvlen>48?48:recvlen; +// memcpy(n.d.asBytes, recvbuf, 48); + LED_B_ON(); + cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48); +// UsbSendPacket((uint8_t *)&n, sizeof(n)); + LED_B_OFF(); + if (DEBUG) { - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } + Dbprintf("RECV"); + DbdecodeIso15693Answer(recvlen,recvbuf); + Dbhexdump(recvlen,recvbuf,true); } - if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { - recvlen = ISO15693_MAX_RESPONSE_LENGTH; - } - cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); } - LED_A_OFF(); } -//----------------------------------------------------------------------------- -// Work with "magic Chinese" card. -// -//----------------------------------------------------------------------------- - -// Set the UID on Magic ISO15693 tag (based on Iceman's LUA-script). -void SetTag15693Uid(uint8_t *uid) { - - LED_A_ON(); - - uint8_t cmd[4][9] = { - {ISO15693_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3e, 0x00, 0x00, 0x00, 0x00}, - {ISO15693_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x3f, 0x69, 0x96, 0x00, 0x00}, - {ISO15693_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x38}, - {ISO15693_REQ_DATARATE_HIGH, ISO15693_WRITEBLOCK, 0x39} - }; - - uint16_t crc; - - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time; - - // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) - cmd[2][3] = uid[7]; - cmd[2][4] = uid[6]; - cmd[2][5] = uid[5]; - cmd[2][6] = uid[4]; - - // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) - cmd[3][3] = uid[3]; - cmd[3][4] = uid[2]; - cmd[3][5] = uid[1]; - cmd[3][6] = uid[0]; - - uint32_t start_time = 0; - - for (int i = 0; i < 4; i++) { - // Add the CRC - crc = Iso15693Crc(cmd[i], 7); - cmd[i][7] = crc & 0xff; - cmd[i][8] = crc >> 8; - - recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), i==0?true:false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - if (DEBUG) { - Dbprintf("SEND:"); - Dbhexdump(sizeof(cmd[i]), cmd[i], false); - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - } - // Note: need to know if we expect an answer from one of the magic commands - // if (recvlen < 0) { - // break; - // } - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); - LED_A_OFF(); -} @@ -1869,8 +1302,8 @@ static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) uint8_t cmd[12]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the security status of the block - // followed by the block data + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // System Information command code @@ -1886,7 +1319,7 @@ static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) cmd[8] = 0x05; cmd[9]= 0xe0; // always e0 (not exactly unique) //Now the CRC - crc = Iso15693Crc(cmd, 10); // the crc needs to be calculated over 2 bytes + crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes cmd[10] = crc & 0xff; cmd[11] = crc >> 8; @@ -1900,8 +1333,8 @@ static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the security status of the block - // followed by the block data + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ Multi BLOCK command code @@ -1921,7 +1354,7 @@ static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) // Number of Blocks to read cmd[11] = 0x2f; // read quite a few //Now the CRC - crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1934,8 +1367,8 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the security status of the block - // followed by the block data + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ BLOCK command code @@ -1954,9 +1387,9 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C cmd[10] = 0x00; cmd[11] = 0x0a; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1969,8 +1402,8 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the security status of the block - // followed by the block data + // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block + // followed by teh block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ BLOCK command code @@ -1986,12 +1419,12 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u cmd[8] = 0x05; cmd[9]= 0xe0; // always e0 (not exactly unique) // Parameter - cmd[10] = 0x05; // for custom codes this must be manufacturer code + cmd[10] = 0x05; // for custom codes this must be manufcturer code cmd[11] = 0x00; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC - crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC + crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h deleted file mode 100644 index 15dfe763..00000000 --- a/armsrc/iso15693.h +++ /dev/null @@ -1,43 +0,0 @@ -//----------------------------------------------------------------------------- -// Piwi - October 2018 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support ISO 15693. -//----------------------------------------------------------------------------- - -#ifndef ISO15693_H__ -#define ISO15693_H__ - -#include -#include -#include - -// Delays in SSP_CLK ticks. -// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag -#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 -#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response -#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command - -extern void Iso15693InitReader(void); -extern void Iso15693InitTag(void); -extern void CodeIso15693AsReader(uint8_t *cmd, int n); -extern void CodeIso15693AsTag(uint8_t *cmd, size_t len); -extern void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); -extern int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); -extern void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); -extern int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); -extern void SnoopIso15693(uint8_t jam_search_len, uint8_t *jam_search_string); -extern void AcquireRawAdcSamplesIso15693(void); -extern void ReaderIso15693(uint32_t parameter); -extern void SimTagIso15693(uint32_t parameter, uint8_t *uid); -extern void BruteforceIso15693Afi(uint32_t speed); -extern void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]); -extern void SetTag15693Uid(uint8_t *uid); -extern void SetDebugIso15693(uint32_t flag); -extern bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); - -#endif diff --git a/armsrc/ldscript b/armsrc/ldscript index 34da26bc..dcb04bf0 100644 --- a/armsrc/ldscript +++ b/armsrc/ldscript @@ -11,7 +11,8 @@ INCLUDE ../common/ldscript.common PHDRS { - text PT_LOAD FLAGS(5); + fpgaimage PT_LOAD FLAGS(4); + text PT_LOAD; data PT_LOAD; bss PT_LOAD; } @@ -19,12 +20,15 @@ PHDRS ENTRY(Vector) SECTIONS { + .fpgaimage : { + *(fpga_bit.data) + } >fpgaimage :fpgaimage + .start : { *(.startos) } >osimage :text .text : { - KEEP(*(stage1_image)) *(.text) *(.text.*) *(.eh_frame) @@ -35,13 +39,12 @@ SECTIONS .rodata : { *(.rodata) *(.rodata.*) - *(fpga_all_bit.data) KEEP(*(.version_information)) - . = ALIGN(8); } >osimage :text + . = ALIGN(4); + .data : { - KEEP(*(compressed_data)) *(.data) *(.data.*) *(.ramfunc) @@ -51,7 +54,6 @@ SECTIONS __data_src_start__ = LOADADDR(.data); __data_start__ = ADDR(.data); __data_end__ = __data_start__ + SIZEOF(.data); - __os_size__ = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.rodata); .bss : { __bss_start__ = .; diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 71ff0321..f2eb680b 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -1,7 +1,5 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz -// 2016 Iceman -// 2018 AntiCat // // 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 @@ -10,449 +8,745 @@ // LEGIC RF simulation code //----------------------------------------------------------------------------- -#include "legicrf.h" - #include "proxmark3.h" #include "apps.h" -#include "usb_cdc.h" #include "util.h" #include "string.h" + +#include "legicrf.h" #include "legic_prng.h" -#include "legic.h" #include "crc.h" -#include "fpgaloader.h" -static legic_card_select_t card;/* metadata of currently selected card */ -static crc_t legic_crc; +static struct legic_frame { + int bits; + uint32_t data; +} current_frame; -//----------------------------------------------------------------------------- -// Frame timing and pseudorandom number generator -// -// The Prng is forwarded every 100us (TAG_BIT_PERIOD), except when the reader is -// transmitting. In that case the prng has to be forwarded every bit transmitted: -// - 60us for a 0 (RWD_TIME_0) -// - 100us for a 1 (RWD_TIME_1) -// -// The data dependent timing makes writing comprehensible code significantly -// harder. The current aproach forwards the prng data based if there is data on -// air and time based, using GET_TICKS, during computational and wait periodes. -// -// To not have the necessity to calculate/guess exection time dependend timeouts -// tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots. -//----------------------------------------------------------------------------- +static enum { + STATE_DISCON, + STATE_IV, + STATE_CON, +} legic_state; -static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ +static crc_t legic_crc; +static int legic_read_count; +static uint32_t legic_prng_bc; +static uint32_t legic_prng_iv; -#define RWD_TIME_PAUSE 30 /* 20us */ -#define RWD_TIME_1 150 /* READER_TIME_PAUSE 20us off + 80us on = 100us */ -#define RWD_TIME_0 90 /* READER_TIME_PAUSE 20us off + 40us on = 60us */ -#define RWD_FRAME_WAIT 330 /* 220us from TAG frame end to READER frame start */ -#define TAG_FRAME_WAIT 495 /* 330us from READER frame end to TAG frame start */ -#define TAG_BIT_PERIOD 150 /* 100us */ -#define TAG_WRITE_TIMEOUT 60 /* 40 * 100us (write should take at most 3.6ms) */ +static int legic_phase_drift; +static int legic_frame_drift; +static int legic_reqresp_drift; -#define LEGIC_READ 0x01 /* Read Command */ -#define LEGIC_WRITE 0x00 /* Write Command */ +AT91PS_TC timer; +AT91PS_TC prng_timer; -#define SESSION_IV 0x55 /* An arbitrary chose session IV, all shoud work */ -#define OFFSET_LOG 1024 /* The largest Legic Prime card is 1k */ -#define WRITE_LOWERLIMIT 4 /* UID and MCC are not writable */ +static void setup_timer(void) +{ + /* Set up Timer 1 to use for measuring time between pulses. Since we're bit-banging + * this it won't be terribly accurate but should be good enough. + */ + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + timer = AT91C_BASE_TC1; + timer->TC_CCR = AT91C_TC_CLKDIS; + timer->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; + timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; -#define INPUT_THRESHOLD 8 /* heuristically determined, lower values */ - /* lead to detecting false ack during write */ - -//----------------------------------------------------------------------------- -// I/O interface abstraction (FPGA -> ARM) -//----------------------------------------------------------------------------- - -static inline uint16_t rx_frame_from_fpga() { - for(;;) { - WDT_HIT(); - - // wait for frame be become available in rx holding register - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - return AT91C_BASE_SSC->SSC_RHR; - } - } + /* + * Set up Timer 2 to use for measuring time between frames in + * tag simulation mode. Runs 4x faster as Timer 1 + */ + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC2); + prng_timer = AT91C_BASE_TC2; + prng_timer->TC_CCR = AT91C_TC_CLKDIS; + prng_timer->TC_CMR = AT91C_TC_CLKS_TIMER_DIV2_CLOCK; + prng_timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; } -//----------------------------------------------------------------------------- -// Demodulation (Reader) -//----------------------------------------------------------------------------- +/* At TIMER_CLOCK3 (MCK/32) */ +#define RWD_TIME_1 150 /* RWD_TIME_PAUSE off, 80us on = 100us */ +#define RWD_TIME_0 90 /* RWD_TIME_PAUSE off, 40us on = 60us */ +#define RWD_TIME_PAUSE 30 /* 20us */ +#define RWD_TIME_FUZZ 20 /* rather generous 13us, since the peak detector + hysteresis fuzz quite a bit */ +#define TAG_TIME_BIT 150 /* 100us for every bit */ +#define TAG_TIME_WAIT 490 /* time from RWD frame end to tag frame start, experimentally determined */ -// Returns a demedulated bit -// -// The FPGA running xcorrelation samples the subcarrier at ~13.56 MHz. The mode -// was initialy designed to receive BSPK/2-PSK. Hance, it reports an I/Q pair -// every 4.7us (8 bits i and 8 bits q). -// -// The subcarrier amplitude can be calculated using Pythagoras sqrt(i^2 + q^2). -// To reduce CPU time the amplitude is approximated by using linear functions: -// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) -// -// The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples -// and averages the next (most stable) 8 samples. The final 8 samples are dropped -// also. -// -// The demodulated should be alligned to the bit period by the caller. This is -// done in rx_bit and rx_ack. -static inline bool rx_bit() { - int32_t sum_cq = 0; - int32_t sum_ci = 0; +#define SIM_DIVISOR 586 /* prng_time/SIM_DIVISOR count prng needs to be forwared */ +#define SIM_SHIFT 900 /* prng_time+SIM_SHIFT shift of delayed start */ - // skip first 5 I/Q pairs - for(size_t i = 0; i<5; ++i) { - (void)rx_frame_from_fpga(); +#define SESSION_IV 0x55 +#define OFFSET_LOG 1024 + +#define FUZZ_EQUAL(value, target, fuzz) ((value) > ((target)-(fuzz)) && (value) < ((target)+(fuzz))) + +/* Generate Keystream */ +static uint32_t get_key_stream(int skip, int count) +{ + uint32_t key=0; int i; + + /* Use int to enlarge timer tc to 32bit */ + legic_prng_bc += prng_timer->TC_CV; + prng_timer->TC_CCR = AT91C_TC_SWTRG; + + /* If skip == -1, forward prng time based */ + if(skip == -1) { + i = (legic_prng_bc+SIM_SHIFT)/SIM_DIVISOR; /* Calculate Cycles based on timer */ + i -= legic_prng_count(); /* substract cycles of finished frames */ + i -= count; /* substract current frame length, rewidn to bedinning */ + legic_prng_forward(i); + } else { + legic_prng_forward(skip); } - // sample next 8 I/Q pairs - for(size_t i = 0; i<8; ++i) { - uint16_t iq = rx_frame_from_fpga(); - int8_t ci = (int8_t)(iq >> 8); - int8_t cq = (int8_t)(iq & 0xff); - sum_ci += ci; - sum_cq += cq; - } + /* Write Time Data into LOG */ + if(count == 6) { i = -1; } else { i = legic_read_count; } + ((uint8_t*)BigBuf)[OFFSET_LOG+128+i] = legic_prng_count(); + ((uint8_t*)BigBuf)[OFFSET_LOG+256+i*4] = (legic_prng_bc >> 0) & 0xff; + ((uint8_t*)BigBuf)[OFFSET_LOG+256+i*4+1] = (legic_prng_bc >> 8) & 0xff; + ((uint8_t*)BigBuf)[OFFSET_LOG+256+i*4+2] = (legic_prng_bc >>16) & 0xff; + ((uint8_t*)BigBuf)[OFFSET_LOG+256+i*4+3] = (legic_prng_bc >>24) & 0xff; + ((uint8_t*)BigBuf)[OFFSET_LOG+384+i] = count; - // calculate power - int32_t power = (MAX(ABS(sum_ci), ABS(sum_cq)) + MIN(ABS(sum_ci), ABS(sum_cq))/2); - - // compare average (power / 8) to threshold - return ((power >> 3) > INPUT_THRESHOLD); -} - -//----------------------------------------------------------------------------- -// Modulation (Reader) -// -// I've tried to modulate the Legic specific pause-puls using ssc and the default -// ssc clock of 105.4 kHz (bit periode of 9.4us) - previous commit. However, -// the timing was not precise enough. By increasing the ssc clock this could -// be circumvented, but the adventage over bitbang would be little. -//----------------------------------------------------------------------------- - -static inline void tx_bit(bool bit) { - // insert pause - HIGH(GPIO_SSC_DOUT); - last_frame_end += RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; - - // return to carrier on, wait for bit periode to end - LOW(GPIO_SSC_DOUT); - last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; - while(GET_TICKS < last_frame_end) { }; -} - -//----------------------------------------------------------------------------- -// Frame Handling (Reader) -// -// The LEGIC RF protocol from card to reader does not include explicit frame -// start/stop information or length information. The reader must know beforehand -// how many bits it wants to receive. -// Notably: a card sending a stream of 0-bits is indistinguishable from no card -// present. -//----------------------------------------------------------------------------- - -static void tx_frame(uint32_t frame, uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - - // wait for next tx timeslot - last_frame_end += RWD_FRAME_WAIT; - while(GET_TICKS < last_frame_end) { }; - - // transmit frame, MSB first - for(uint8_t i = 0; i < len; ++i) { - bool bit = (frame >> i) & 0x01; - tx_bit(bit ^ legic_prng_get_bit()); + /* Generate KeyStream */ + for(i=0; iPIO_CODR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + /* Use time to crypt frame */ + if(crypt) { + legic_prng_forward(2); /* TAG_TIME_WAIT -> shift by 2 */ + int i; int key = 0; + for(i=0; iTC_CV < (TAG_TIME_WAIT - 30)) ; + + int i; + for(i=0; iTC_CV + TAG_TIME_BIT; + int bit = response & 1; + response = response >> 1; + if(bit) { + AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; + } else { + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + } + while(timer->TC_CV < nextbit) ; + } + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; +} - uint32_t ack = 0; - for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) { - // sample bit - ack = rx_bit(); - legic_prng_forward(1); +/* Send a frame in reader mode, the FPGA must have been set up by + * LegicRfReader + */ +static void frame_send_rwd(uint32_t data, int bits) +{ + /* Start clock */ + timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ - // rx_bit runs only 95us, resync to TAG_BIT_PERIOD - last_frame_end += TAG_BIT_PERIOD; - while(GET_TICKS < last_frame_end) { }; + int i; + for(i=0; iTC_CV; + int pause_end = starttime + RWD_TIME_PAUSE, bit_end; + int bit = data & 1; + data = data >> 1; - // check if it was an ACK - if(ack) { - break; + if(bit ^ legic_prng_get_bit()) { + bit_end = starttime + RWD_TIME_1; + } else { + bit_end = starttime + RWD_TIME_0; + } + + /* RWD_TIME_PAUSE time off, then some time on, so that the complete bit time is + * RWD_TIME_x, where x is the bit to be transmitted */ + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + while(timer->TC_CV < pause_end) ; + AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; + legic_prng_forward(1); /* bit duration is longest. use this time to forward the lfsr */ + + while(timer->TC_CV < bit_end) ; + } + + { + /* One final pause to mark the end of the frame */ + int pause_end = timer->TC_CV + RWD_TIME_PAUSE; + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + while(timer->TC_CV < pause_end) ; + AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; + } + + /* Reset the timer, to measure time until the start of the tag frame */ + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ +} + +/* Receive a frame from the card in reader emulation mode, the FPGA and + * timer must have been set up by LegicRfReader and frame_send_rwd. + * + * The LEGIC RF protocol from card to reader does not include explicit + * frame start/stop information or length information. The reader must + * know beforehand how many bits it wants to receive. (Notably: a card + * sending a stream of 0-bits is indistinguishable from no card present.) + * + * Receive methodology: There is a fancy correlator in hi_read_rx_xcorr, but + * I'm not smart enough to use it. Instead I have patched hi_read_tx to output + * the ADC signal with hysteresis on SSP_DIN. Bit-bang that signal and look + * for edges. Count the edges in each bit interval. If they are approximately + * 0 this was a 0-bit, if they are approximately equal to the number of edges + * expected for a 212kHz subcarrier, this was a 1-bit. For timing we use the + * timer that's still running from frame_send_rwd in order to get a synchronization + * with the frame that we just sent. + * + * FIXME: Because we're relying on the hysteresis to just do the right thing + * the range is severely reduced (and you'll probably also need a good antenna). + * So this should be fixed some time in the future for a proper receiver. + */ +static void frame_receive_rwd(struct legic_frame * const f, int bits, int crypt) +{ + uint32_t the_bit = 1; /* Use a bitmask to save on shifts */ + uint32_t data=0; + int i, old_level=0, edges=0; + int next_bit_at = TAG_TIME_WAIT; + + if(bits > 32) { + bits = 32; } - } - return ack; + AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; + + /* we have some time now, precompute the cipher + * since we cannot compute it on the fly while reading */ + legic_prng_forward(2); + + if(crypt) + { + for(i=0; iTC_CV < next_bit_at) ; + + next_bit_at += TAG_TIME_BIT; + + for(i=0; iTC_CV < next_bit_at) { + int level = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN); + if(level != old_level) + edges++; + old_level = level; + } + next_bit_at += TAG_TIME_BIT; + + if(edges > 20 && edges < 60) { /* expected are 42 edges */ + data ^= the_bit; + } + the_bit <<= 1; + } + + f->data = data; + f->bits = bits; + + /* Reset the timer, to synchronize the next frame */ + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ } -//----------------------------------------------------------------------------- -// Legic Reader -//----------------------------------------------------------------------------- - -static int init_card(uint8_t cardtype, legic_card_select_t *p_card) { - p_card->tagtype = cardtype; - - switch(p_card->tagtype) { - case 0x0d: - p_card->cmdsize = 6; - p_card->addrsize = 5; - p_card->cardsize = 22; - break; - case 0x1d: - p_card->cmdsize = 9; - p_card->addrsize = 8; - p_card->cardsize = 256; - break; - case 0x3d: - p_card->cmdsize = 11; - p_card->addrsize = 10; - p_card->cardsize = 1024; - break; - default: - p_card->cmdsize = 0; - p_card->addrsize = 0; - p_card->cardsize = 0; - return 2; - } - return 0; +static void frame_append_bit(struct legic_frame * const f, int bit) +{ + if(f->bits >= 31) { + return; /* Overflow, won't happen */ + } + f->data |= (bit<bits); + f->bits++; } -static void init_reader(bool clear_mem) { - // configure FPGA - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - LED_D_ON(); - - // configure SSC with defaults - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - - // re-claim GPIO_SSC_DOUT as GPIO and enable output - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - LOW(GPIO_SSC_DOUT); - - // init crc calculator - crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); - - // start us timer - StartTicks(); +static void frame_clean(struct legic_frame * const f) +{ + f->data = 0; + f->bits = 0; } -// Setup reader to card connection -// -// The setup consists of a three way handshake: -// - Transmit initialisation vector 7 bits -// - Receive card type 6 bits -// - Transmit Acknowledge 6 bits -static uint32_t setup_phase(uint8_t iv) { - // init coordination timestamp - last_frame_end = GET_TICKS; +static uint32_t perform_setup_phase_rwd(int iv) +{ - // Switch on carrier and let the card charge for 5ms. - last_frame_end += 7500; - while(GET_TICKS < last_frame_end) { }; + /* Switch on carrier and let the tag charge for 1ms */ + AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT; + SpinDelay(1); - legic_prng_init(0); - tx_frame(iv, 7); + legic_prng_init(0); /* no keystream yet */ + frame_send_rwd(iv, 7); + legic_prng_init(iv); - // configure prng - legic_prng_init(iv); - legic_prng_forward(2); + frame_clean(¤t_frame); + frame_receive_rwd(¤t_frame, 6, 1); + legic_prng_forward(1); /* we wait anyways */ + while(timer->TC_CV < 387) ; /* ~ 258us */ + frame_send_rwd(0x19, 6); - // receive card type - int32_t card_type = rx_frame(6); - legic_prng_forward(3); - - // send obsfuscated acknowledgment frame - switch (card_type) { - case 0x0D: - tx_frame(0x19, 6); // MIM22 | READCMD = 0x18 | 0x01 - break; - case 0x1D: - case 0x3D: - tx_frame(0x39, 6); // MIM256 | READCMD = 0x38 | 0x01 - break; - } - - return card_type; + return current_frame.data; } -static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) { - crc_clear(&legic_crc); - crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz); - return crc_finish(&legic_crc); +static void LegicCommonInit(void) { + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + + /* Bitbang the transmitter */ + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + + setup_timer(); + + crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); } -static int16_t read_byte(uint16_t index, uint8_t cmd_sz) { - uint16_t cmd = (index << 1) | LEGIC_READ; +static void switch_off_tag_rwd(void) +{ + /* Switch off carrier, make sure tag is reset */ + AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; + SpinDelay(10); - // read one byte - LED_B_ON(); - legic_prng_forward(2); - tx_frame(cmd, cmd_sz); - legic_prng_forward(2); - uint32_t frame = rx_frame(12); - LED_B_OFF(); - - // split frame into data and crc - uint8_t byte = BYTEx(frame, 0); - uint8_t crc = BYTEx(frame, 1); - - // check received against calculated crc - uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte); - if(calc_crc != crc) { - Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc); - return -1; - } - - legic_prng_forward(1); - - return byte; + WDT_HIT(); +} +/* calculate crc for a legic command */ +static int LegicCRC(int byte_index, int value, int cmd_sz) { + crc_clear(&legic_crc); + crc_update(&legic_crc, 1, 1); /* CMD_READ */ + crc_update(&legic_crc, byte_index, cmd_sz-1); + crc_update(&legic_crc, value, 8); + return crc_finish(&legic_crc); } -// Transmit write command, wait until (3.6ms) the tag sends back an unencrypted -// ACK ('1' bit) and forward the prng time based. -bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) { - uint32_t cmd = index << 1 | LEGIC_WRITE; // prepare command - uint8_t crc = calc_crc4(cmd, addr_sz + 1, byte); // calculate crc - cmd |= byte << (addr_sz + 1); // append value - cmd |= (crc & 0xF) << (addr_sz + 1 + 8); // and crc +int legic_read_byte(int byte_index, int cmd_sz) { + int byte; - // send write command - LED_C_ON(); - legic_prng_forward(2); - tx_frame(cmd, addr_sz + 1 + 8 + 4); // sz = addr_sz + cmd + data + crc - legic_prng_forward(3); - LED_C_OFF(); + legic_prng_forward(4); /* we wait anyways */ + while(timer->TC_CV < 387) ; /* ~ 258us + 100us*delay */ - // wait for ack - return rx_ack(); + frame_send_rwd(1 | (byte_index << 1), cmd_sz); + frame_clean(¤t_frame); + + frame_receive_rwd(¤t_frame, 12, 1); + + byte = current_frame.data & 0xff; + if( LegicCRC(byte_index, byte, cmd_sz) != (current_frame.data >> 8) ) { + Dbprintf("!!! crc mismatch: expected %x but got %x !!!", + LegicCRC(byte_index, current_frame.data & 0xff, cmd_sz), current_frame.data >> 8); + return -1; + } + + return byte; } -//----------------------------------------------------------------------------- -// Command Line Interface -// -// Only this functions are public / called from appmain.c -//----------------------------------------------------------------------------- -void LegicRfReader(int offset, int bytes) { - uint8_t *BigBuf = BigBuf_get_addr(); - memset(BigBuf, 0, 1024); +/* legic_write_byte() is not included, however it's trivial to implement + * and here are some hints on what remains to be done: + * + * * assemble a write_cmd_frame with crc and send it + * * wait until the tag sends back an ACK ('1' bit unencrypted) + * * forward the prng based on the timing + */ +int legic_write_byte(int byte, int addr, int addr_sz) { + //do not write UID, CRC, DCF + if(addr <= 0x06) { + return 0; + } - // configure ARM and FPGA - init_reader(false); + //== send write command ============================== + crc_clear(&legic_crc); + crc_update(&legic_crc, 0, 1); /* CMD_WRITE */ + crc_update(&legic_crc, addr, addr_sz); + crc_update(&legic_crc, byte, 8); - // establish shared secret and detect card type - DbpString("Reading card ..."); - uint8_t card_type = setup_phase(SESSION_IV); - uint8_t result = 0; - if(init_card(card_type, &card) != 0) { - result = 1; - goto OUT; - } + uint32_t crc = crc_finish(&legic_crc); + uint32_t cmd = ((crc <<(addr_sz+1+8)) //CRC + |(byte <<(addr_sz+1)) //Data + |(addr <<1) //Address + |(0x00 <<0)); //CMD = W + uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd - // if no argument is specified create full dump - if(bytes == -1) { - bytes = card.cardsize; - } + legic_prng_forward(2); /* we wait anyways */ + while(timer->TC_CV < 387) ; /* ~ 258us */ + frame_send_rwd(cmd, cmd_sz); - // do not read beyond card memory - if(bytes + offset > card.cardsize) { - bytes = card.cardsize - offset; - } - - for(uint16_t i = 0; i < bytes; ++i) { - int16_t byte = read_byte(offset + i, card.cmdsize); - if(byte == -1) { - result = 2; - goto OUT; + //== wait for ack ==================================== + int t, old_level=0, edges=0; + int next_bit_at =0; + while(timer->TC_CV < 387) ; /* ~ 258us */ + for(t=0; t<80; t++) { + edges = 0; + next_bit_at += TAG_TIME_BIT; + while(timer->TC_CV < next_bit_at) { + int level = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN); + if(level != old_level) { + edges++; + } + old_level = level; + } + if(edges > 20 && edges < 60) { /* expected are 42 edges */ + int t = timer->TC_CV; + int c = t/TAG_TIME_BIT; + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ + legic_prng_forward(c); + return 0; + } } - BigBuf[i] = byte; - } + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ + return -1; +} -OUT: - cmd_send(CMD_ACK, result, bytes, 0, &card, sizeof(card)); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); - StopTicks(); +int LegicRfReader(int offset, int bytes) { + int byte_index=0, cmd_sz=0, card_sz=0; + + LegicCommonInit(); + + memset(BigBuf, 0, 1024); + + DbpString("setting up legic card"); + uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); + switch_off_tag_rwd(); //we lose to mutch time with dprintf + switch(tag_type) { + case 0x1d: + DbpString("MIM 256 card found, reading card ..."); + cmd_sz = 9; + card_sz = 256; + break; + case 0x3d: + DbpString("MIM 1024 card found, reading card ..."); + cmd_sz = 11; + card_sz = 1024; + break; + default: + Dbprintf("Unknown card format: %x",tag_type); + return -1; + } + if(bytes == -1) { + bytes = card_sz; + } + if(bytes+offset >= card_sz) { + bytes = card_sz-offset; + } + + perform_setup_phase_rwd(SESSION_IV); + + LED_B_ON(); + while(byte_index < bytes) { + int r = legic_read_byte(byte_index+offset, cmd_sz); + if(r == -1 ||BUTTON_PRESS()) { + DbpString("operation aborted"); + switch_off_tag_rwd(); + LED_B_OFF(); + LED_C_OFF(); + return -1; + } + ((uint8_t*)BigBuf)[byte_index] = r; + WDT_HIT(); + byte_index++; + if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); + } + LED_B_OFF(); + LED_C_OFF(); + switch_off_tag_rwd(); + Dbprintf("Card read, use 'hf legic decode' or"); + Dbprintf("'data hexsamples %d' to view results", (bytes+7) & ~7); + return 0; } void LegicRfWriter(int bytes, int offset) { - uint8_t *BigBuf = BigBuf_get_addr(); + int byte_index=0, addr_sz=0; + + LegicCommonInit(); + + DbpString("setting up legic card"); + uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); + switch_off_tag_rwd(); + switch(tag_type) { + case 0x1d: + if(offset+bytes > 0x100) { + Dbprintf("Error: can not write to 0x%03.3x on MIM 256", offset+bytes); + return; + } + addr_sz = 8; + Dbprintf("MIM 256 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); + break; + case 0x3d: + if(offset+bytes > 0x400) { + Dbprintf("Error: can not write to 0x%03.3x on MIM 1024", offset+bytes); + return; + } + addr_sz = 10; + Dbprintf("MIM 1024 card found, writing 0x%03.3x - 0x%03.3x ...", offset, offset+bytes); + break; + default: + Dbprintf("No or unknown card found, aborting"); + return; + } - // configure ARM and FPGA - init_reader(false); - - // uid is not writeable - if(offset <= WRITE_LOWERLIMIT) { - goto OUT; - } - - // establish shared secret and detect card type - Dbprintf("Writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes); - uint8_t card_type = setup_phase(SESSION_IV); - if(init_card(card_type, &card) != 0) { - Dbprintf("No or unknown card found, aborting"); - goto OUT; - } - - // do not write beyond card memory - if(bytes + offset > card.cardsize) { - bytes = card.cardsize - offset; - } - - // write in reverse order, only then is DCF (decremental field) writable - while(bytes-- > 0 && !BUTTON_PRESS()) { - if(!write_byte(bytes + offset, BigBuf[bytes + offset], card.addrsize)) { - Dbprintf("operation failed @ 0x%03.3x", bytes); - goto OUT; - } - } - - // OK - DbpString("Write successful"); - -OUT: - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); - StopTicks(); + LED_B_ON(); + perform_setup_phase_rwd(SESSION_IV); + legic_prng_forward(2); + while(byte_index < bytes) { + int r = legic_write_byte(((uint8_t*)BigBuf)[byte_index+offset], byte_index+offset, addr_sz); + if((r != 0) || BUTTON_PRESS()) { + Dbprintf("operation aborted @ 0x%03.3x", byte_index); + switch_off_tag_rwd(); + LED_B_OFF(); + LED_C_OFF(); + return; + } + WDT_HIT(); + byte_index++; + if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); + } + LED_B_OFF(); + LED_C_OFF(); + DbpString("write successful"); } + +int timestamp; + +/* Handle (whether to respond) a frame in tag mode */ +static void frame_handle_tag(struct legic_frame const * const f) +{ + /* First Part of Handshake (IV) */ + if(f->bits == 7) { + if(f->data == SESSION_IV) { + LED_C_ON(); + prng_timer->TC_CCR = AT91C_TC_SWTRG; + legic_prng_init(f->data); + frame_send_tag(0x3d, 6, 1); /* 0x3d^0x26 = 0x1b */ + legic_state = STATE_IV; + legic_read_count = 0; + legic_prng_bc = 0; + legic_prng_iv = f->data; + + /* TIMEOUT */ + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1); + while(timer->TC_CV < 280); + return; + } else if((prng_timer->TC_CV % 50) > 40) { + legic_prng_init(f->data); + frame_send_tag(0x3d, 6, 1); + SpinDelay(20); + return; + } + } + + /* 0x19==??? */ + if(legic_state == STATE_IV) { + if((f->bits == 6) && (f->data == (0x19 ^ get_key_stream(1, 6)))) { + legic_state = STATE_CON; + + /* TIMEOUT */ + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1); + while(timer->TC_CV < 200); + return; + } else { + legic_state = STATE_DISCON; + LED_C_OFF(); + Dbprintf("0x19 - Frame: %03.3x", f->data); + return; + } + } + + /* Read */ + if(f->bits == 11) { + if(legic_state == STATE_CON) { + int key = get_key_stream(-1, 11); //legic_phase_drift, 11); + int addr = f->data ^ key; addr = addr >> 1; + int data = ((uint8_t*)BigBuf)[addr]; + int hash = LegicCRC(addr, data, 11) << 8; + ((uint8_t*)BigBuf)[OFFSET_LOG+legic_read_count] = (uint8_t)addr; + legic_read_count++; + + //Dbprintf("Data:%03.3x, key:%03.3x, addr: %03.3x, read_c:%u", f->data, key, addr, read_c); + legic_prng_forward(legic_reqresp_drift); + + frame_send_tag(hash | data, 12, 1); + + /* SHORT TIMEOUT */ + timer->TC_CCR = AT91C_TC_SWTRG; + while(timer->TC_CV > 1); + legic_prng_forward(legic_frame_drift); + while(timer->TC_CV < 180); + return; + } + } + + /* Write */ + if(f->bits == 23) { + int key = get_key_stream(-1, 23); //legic_frame_drift, 23); + int addr = f->data ^ key; addr = addr >> 1; addr = addr & 0x3ff; + int data = f->data ^ key; data = data >> 11; data = data & 0xff; + + /* write command */ + legic_state = STATE_DISCON; + LED_C_OFF(); + Dbprintf("write - addr: %x, data: %x", addr, data); + return; + } + + if(legic_state != STATE_DISCON) { + Dbprintf("Unexpected: sz:%u, Data:%03.3x, State:%u, Count:%u", f->bits, f->data, legic_state, legic_read_count); + int i; + Dbprintf("IV: %03.3x", legic_prng_iv); + for(i = 0; iPIO_ODR = GPIO_SSC_DIN; + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; + + setup_timer(); + crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); + + int old_level = 0; + int active = 0; + legic_state = STATE_DISCON; + + LED_B_ON(); + DbpString("Starting Legic emulator, press button to end"); + while(!BUTTON_PRESS()) { + int level = !!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN); + int time = timer->TC_CV; + + if(level != old_level) { + if(level == 1) { + timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + if(FUZZ_EQUAL(time, RWD_TIME_1, RWD_TIME_FUZZ)) { + /* 1 bit */ + emit(1); + active = 1; + LED_A_ON(); + } else if(FUZZ_EQUAL(time, RWD_TIME_0, RWD_TIME_FUZZ)) { + /* 0 bit */ + emit(0); + active = 1; + LED_A_ON(); + } else if(active) { + /* invalid */ + emit(-1); + active = 0; + LED_A_OFF(); + } + } + } + + if(time >= (RWD_TIME_1+RWD_TIME_FUZZ) && active) { + /* Frame end */ + emit(-1); + active = 0; + LED_A_OFF(); + } + + if(time >= (20*RWD_TIME_1) && (timer->TC_SR & AT91C_TC_CLKSTA)) { + timer->TC_CCR = AT91C_TC_CLKDIS; + } + + old_level = level; + WDT_HIT(); + } + DbpString("Stopped"); + LED_B_OFF(); + LED_A_OFF(); + LED_C_OFF(); +} + diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 9f8cf457..57ab7e6d 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -1,6 +1,5 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz -// 2018 AntiCat // // 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 @@ -12,7 +11,8 @@ #ifndef __LEGICRF_H #define __LEGICRF_H -extern void LegicRfReader(int bytes, int offset); +extern void LegicRfSimulate(int phase, int frame, int reqresp); +extern int LegicRfReader(int bytes, int offset); extern void LegicRfWriter(int bytes, int offset); #endif /* __LEGICRF_H */ diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c deleted file mode 100644 index 409235af..00000000 --- a/armsrc/legicrfsim.c +++ /dev/null @@ -1,470 +0,0 @@ -//----------------------------------------------------------------------------- -// (c) 2009 Henryk Plötz -// 2016 Iceman -// 2018 AntiCat -// -// 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. -//----------------------------------------------------------------------------- -// LEGIC RF simulation code -//----------------------------------------------------------------------------- - -#include "legicrfsim.h" - -#include "proxmark3.h" -#include "apps.h" -#include "util.h" -#include "string.h" -#include "legic_prng.h" -#include "legic.h" -#include "crc.h" -#include "usb_cdc.h" // for usb_poll_validate_length -#include "fpgaloader.h" - -static uint8_t* legic_mem; /* card memory, used for sim */ -static legic_card_select_t card;/* metadata of currently selected card */ -static crc_t legic_crc; - -//----------------------------------------------------------------------------- -// Frame timing and pseudorandom number generator -// -// The Prng is forwarded every 99.1us (TAG_BIT_PERIOD), except when the reader is -// transmitting. In that case the prng has to be forwarded every bit transmitted: -// - 31.3us for a 0 (RWD_TIME_0) -// - 99.1us for a 1 (RWD_TIME_1) -// -// The data dependent timing makes writing comprehensible code significantly -// harder. The current aproach forwards the prng data based if there is data on -// air and time based, using GetCountSspClk(), during computational and wait -// periodes. SSP Clock is clocked by the FPGA at 212 kHz (subcarrier frequency). -// -// To not have the necessity to calculate/guess exection time dependend timeouts -// tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots. -//----------------------------------------------------------------------------- - -static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ - -#define TAG_FRAME_WAIT 70 /* 330us from READER frame end to TAG frame start */ -#define TAG_ACK_WAIT 758 /* 3.57ms from READER frame end to TAG write ACK */ -#define TAG_BIT_PERIOD 21 /* 99.1us */ - -#define RWD_TIME_PAUSE 4 /* 18.9us */ -#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */ -#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */ -#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */ -#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */ -#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */ - -#define RWD_PULSE 1 /* Pulse is signaled with GPIO_SSC_DIN high */ -#define RWD_PAUSE 0 /* Pause is signaled with GPIO_SSC_DIN low */ - -//----------------------------------------------------------------------------- -// Demodulation -//----------------------------------------------------------------------------- - -// Returns true if a pulse/pause is received within timeout -static inline bool wait_for(bool value, const uint32_t timeout) { - while((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) { - if(GetCountSspClk() > timeout) { - return false; - } - } - return true; -} - -// Returns a demedulated bit or -1 on code violation -// -// rx_bit decodes bits using a thresholds. rx_bit has to be called by as soon as -// a frame starts (first pause is received). rx_bit checks for a pause up to -// 18.9us followed by a pulse of 80.2us or 42.4us: -// - A bit length <18.9us is a code violation -// - A bit length >80.2us is a 1 -// - A bit length <80.2us is a 0 -// - A bit length >148.6us is a code violation -static inline int8_t rx_bit() { - // backup ts for threshold calculation - uint32_t bit_start = last_frame_end; - - // wait for pause to end - if(!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) { - return -1; - } - - // wait for next pause - if(!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) { - return -1; - } - - // update bit and frame end - last_frame_end = GetCountSspClk(); - - // check for code violation (bit to short) - if(last_frame_end - bit_start < RWD_TIME_PAUSE) { - return -1; - } - - // apply threshold (average of RWD_TIME_0 and ) - return (last_frame_end - bit_start > (RWD_TIME_0 + RWD_TIME_1) / 2); -} - -//----------------------------------------------------------------------------- -// Modulation -// -// LEGIC RF uses a very basic load modulation from card to reader: -// - Subcarrier on for a 1 -// - Subcarrier off for for a 0 -// -// The 212kHz subcarrier is generated by the FPGA as well as a mathcing ssp clk. -// Each bit is transfered in a 99.1us slot and the first timeslot starts 330us -// after the final 20us pause generated by the reader. -//----------------------------------------------------------------------------- - -// Transmits a bit -// -// Note: The Subcarrier is not disabled during bits to prevent glitches. This is -// not mandatory but results in a cleaner signal. tx_frame will disable -// the subcarrier when the frame is done. -static inline void tx_bit(bool bit) { - LED_C_ON(); - - if(bit) { - // modulate subcarrier - HIGH(GPIO_SSC_DOUT); - } else { - // do not modulate subcarrier - LOW(GPIO_SSC_DOUT); - } - - // wait for tx timeslot to end - last_frame_end += TAG_BIT_PERIOD; - while(GetCountSspClk() < last_frame_end) { }; - LED_C_OFF(); -} - -//----------------------------------------------------------------------------- -// Frame Handling -// -// The LEGIC RF protocol from reader to card does not include explicit frame -// start/stop information or length information. The tag detects end of frame -// trough an extended pulse (>99.1us) without a pause. -// In reverse direction (card to reader) the number of bites is well known -// and depends only the command received (IV, ACK, READ or WRITE). -//----------------------------------------------------------------------------- - -static void tx_frame(uint32_t frame, uint8_t len) { - // wait for next tx timeslot - last_frame_end += TAG_FRAME_WAIT; - legic_prng_forward(TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1); - while(GetCountSspClk() < last_frame_end) { }; - - // transmit frame, MSB first - for(uint8_t i = 0; i < len; ++i) { - bool bit = (frame >> i) & 0x01; - tx_bit(bit ^ legic_prng_get_bit()); - legic_prng_forward(1); - }; - - // disable subcarrier - LOW(GPIO_SSC_DOUT); -} - -static void tx_ack() { - // wait for ack timeslot - last_frame_end += TAG_ACK_WAIT; - legic_prng_forward(TAG_ACK_WAIT/TAG_BIT_PERIOD - 1); - while(GetCountSspClk() < last_frame_end) { }; - - // transmit ack (ack is not encrypted) - tx_bit(true); - legic_prng_forward(1); - - // disable subcarrier - LOW(GPIO_SSC_DOUT); -} - -// Returns a demedulated frame or -1 on code violation -// -// Since TX to RX delay is arbitrary rx_frame has to: -// - detect start of frame (first pause) -// - forward prng based on ts/TAG_BIT_PERIOD -// - receive the frame -// - detect end of frame (last pause) -static int32_t rx_frame(uint8_t *len) { - int32_t frame = 0; - - // add 2 SSP clock cycles (1 for tx and 1 for rx pipeline delay) - // those will be substracted at the end of the rx phase - last_frame_end -= 2; - - // wait for first pause (start of frame) - for(uint8_t i = 0; true; ++i) { - // increment prng every TAG_BIT_PERIOD - last_frame_end += TAG_BIT_PERIOD; - legic_prng_forward(1); - - // if start of frame was received exit delay loop - if(wait_for(RWD_PAUSE, last_frame_end)) { - last_frame_end = GetCountSspClk(); - break; - } - - // check for code violation - if(i > RWD_CMD_TIMEOUT) { - return -1; - } - } - - // receive frame - for(*len = 0; true; ++(*len)) { - // receive next bit - LED_D_ON(); - int8_t bit = rx_bit(); - LED_D_OFF(); - - // check for code violation and to short / long frame - if((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) { - return -1; - } - - // check for code violation caused by end of frame - if(bit < 0) { - break; - } - - // append bit - frame |= (bit ^ legic_prng_get_bit()) << (*len); - legic_prng_forward(1); - } - - // rx_bit sets coordination timestamp to start of pause, append pause duration - // and substract 2 SSP clock cycles (1 for rx and 1 for tx pipeline delay) to - // obtain exact end of frame. - last_frame_end += RWD_TIME_PAUSE - 2; - - return frame; -} - -//----------------------------------------------------------------------------- -// Legic Simulator -//----------------------------------------------------------------------------- - -static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) { - p_card->tagtype = cardtype; - - switch(p_card->tagtype) { - case 0: - p_card->cmdsize = 6; - p_card->addrsize = 5; - p_card->cardsize = 22; - break; - case 1: - p_card->cmdsize = 9; - p_card->addrsize = 8; - p_card->cardsize = 256; - break; - case 2: - p_card->cmdsize = 11; - p_card->addrsize = 10; - p_card->cardsize = 1024; - break; - default: - p_card->cmdsize = 0; - p_card->addrsize = 0; - p_card->cardsize = 0; - return 2; - } - return 0; -} - -static void init_tag() { - // configure FPGA - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR - | FPGA_HF_SIMULATOR_MODULATE_212K); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // configure SSC with defaults - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - - // first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT - LOW(GPIO_SSC_DOUT); - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - - // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. - legic_mem = BigBuf_get_addr(); - - // init crc calculator - crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); - - // start 212kHz timer (running from SSP Clock) - StartCountSspClk(); -} - -// Setup reader to card connection -// -// The setup consists of a three way handshake: -// - Receive initialisation vector 7 bits -// - Transmit card type 6 bits -// - Receive Acknowledge 6 bits -static int32_t setup_phase(legic_card_select_t *p_card) { - uint8_t len = 0; - - // init coordination timestamp - last_frame_end = GetCountSspClk(); - - // reset prng - legic_prng_init(0); - - // wait for iv - int32_t iv = rx_frame(&len); - if((len != 7) || (iv < 0)) { - return -1; - } - - // configure prng - legic_prng_init(iv); - - // reply with card type - switch(p_card->tagtype) { - case 0: - tx_frame(0x0D, 6); - break; - case 1: - tx_frame(0x1D, 6); - break; - case 2: - tx_frame(0x3D, 6); - break; - } - - // wait for ack - int32_t ack = rx_frame(&len); - if((len != 6) || (ack < 0)) { - return -1; - } - - // validate data - switch(p_card->tagtype) { - case 0: - if(ack != 0x19) return -1; - break; - case 1: - if(ack != 0x39) return -1; - break; - case 2: - if(ack != 0x39) return -1; - break; - } - - // During rx the prng is clocked using the variable reader period. - // Since rx_frame detects end of frame by detecting a code violation, - // the prng is off by one bit period after each rx phase. Hence, tx - // code advances the prng by (TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1). - // This is not possible for back to back rx, so this quirk reduces - // the gap by one period. - last_frame_end += TAG_BIT_PERIOD; - - return 0; -} - -static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) { - crc_clear(&legic_crc); - crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz); - return crc_finish(&legic_crc); -} - -static int32_t connected_phase(legic_card_select_t *p_card) { - uint8_t len = 0; - - // wait for command - int32_t cmd = rx_frame(&len); - if(cmd < 0) { - return -1; - } - - // check if command is LEGIC_READ - if(len == p_card->cmdsize) { - // prepare data - uint8_t byte = legic_mem[cmd >> 1]; - uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte); - - // transmit data - tx_frame((crc << 8) | byte, 12); - - return 0; - } - - // check if command is LEGIC_WRITE - if(len == p_card->cmdsize + 8 + 4) { - // decode data - uint16_t mask = (1 << p_card->addrsize) - 1; - uint16_t addr = (cmd >> 1) & mask; - uint8_t byte = (cmd >> p_card->cmdsize) & 0xff; - uint8_t crc = (cmd >> (p_card->cmdsize + 8)) & 0xf; - - // check received against calculated crc - uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte); - if(calc_crc != crc) { - Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc); - return -1; - } - - // store data - legic_mem[addr] = byte; - - // transmit ack - tx_ack(); - - return 0; - } - - return -1; -} - -//----------------------------------------------------------------------------- -// Command Line Interface -// -// Only this function is public / called from appmain.c -//----------------------------------------------------------------------------- - -void LegicRfSimulate(uint8_t cardtype) { - // configure ARM and FPGA - init_tag(); - - // verify command line input - if(init_card(cardtype, &card) != 0) { - DbpString("Unknown tagtype."); - goto OUT; - } - - LED_A_ON(); - DbpString("Starting Legic emulator, press button to end"); - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - WDT_HIT(); - - // wait for carrier, restart after timeout - if(!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) { - continue; - } - - // wait for connection, restart on error - if(setup_phase(&card)) { - continue; - } - - // conection is established, process commands until one fails - while(!connected_phase(&card)) { - WDT_HIT(); - } - } - -OUT: - DbpString("Stopped"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - LED_C_OFF(); - LED_D_OFF(); - StopTicks(); -} diff --git a/armsrc/legicrfsim.h b/armsrc/legicrfsim.h deleted file mode 100644 index c1c8a86e..00000000 --- a/armsrc/legicrfsim.h +++ /dev/null @@ -1,19 +0,0 @@ -//----------------------------------------------------------------------------- -// (c) 2009 Henryk Plötz -// 2018 AntiCat -// -// 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. -//----------------------------------------------------------------------------- -// LEGIC RF emulation public interface -//----------------------------------------------------------------------------- - -#ifndef __LEGICRFSIM_H -#define __LEGICRFSIM_H - -#include "proxmark3.h" - -extern void LegicRfSimulate(uint8_t tagtype); - -#endif /* __LEGICRFSIM_H */ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 995a8810..76c4b44e 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -4,7 +4,7 @@ // the license. //----------------------------------------------------------------------------- // Miscellaneous routines for low frequency tag operations. -// Tags supported here so far are Texas Instruments (TI), HID, EM4x05, EM410x +// Tags supported here so far are Texas Instruments (TI), HID // Also routines for raw mode reading/simulating of LF waveform //----------------------------------------------------------------------------- @@ -14,118 +14,114 @@ #include "hitag2.h" #include "crc16.h" #include "string.h" -#include "lfdemod.h" -#include "lfsampling.h" -#include "protocols.h" -#include "usb_cdc.h" -#include "fpgaloader.h" -/** - * Function to do a modulation and then get samples. - * @param delay_off - * @param period_0 - * @param period_1 - * @param command - */ -void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) +void AcquireRawAdcSamples125k(int divisor) { - // start timer - StartTicks(); + if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else if (divisor == 0) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - // use lf config settings - sample_config *sc = getSamplingConfig(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - // Make sure the tag is reset - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitMS(2500); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // clear read buffer (after fpga bitstream loaded...) - BigBuf_Clear_keep_EM(); + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); - // power on - LFSetupFPGAForADC(sc->divisor, 1); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); - // And a little more time for the tag to fully power up - WaitMS(2000); - // if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods. - bool bitbang = delay_off == 0; - // now modulate the reader field + // Now call the acquisition routine + DoAcquisition125k(); +} - if (bitbang) { - // HACK it appears the loop and if statements take up about 7us so adjust waits accordingly... - uint8_t hack_cnt = 7; - if (period_0 < hack_cnt || period_1 < hack_cnt) { - DbpString("Warning periods cannot be less than 7us in bit bang mode"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - return; - } +// split into two routines so we can avoid timing issues after sending commands // +void DoAcquisition125k(void) +{ + uint8_t *dest = (uint8_t *)BigBuf; + int n = sizeof(BigBuf); + int i; - // hack2 needed--- it appears to take about 8-16us to turn the antenna back on - // leading to ~ 1 to 2 125khz samples extra in every off period - // so we should test for last 0 before next 1 and reduce period_0 by this extra amount... - // but is this time different for every antenna or other hw builds??? more testing needed - - // prime cmd_len to save time comparing strings while modulating - int cmd_len = 0; - while(command[cmd_len] != '\0' && command[cmd_len] != ' ') - cmd_len++; - - int counter = 0; - bool off = false; - for (counter = 0; counter < cmd_len; counter++) { - // if cmd = 0 then turn field off - if (command[counter] == '0') { - // if field already off leave alone (affects timing otherwise) - if (off == false) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - off = true; - } - // note we appear to take about 7us to switch over (or run the if statements/loop...) - WaitUS(period_0-hack_cnt); - // else if cmd = 1 then turn field on - } else { - // if field already on leave alone (affects timing otherwise) - if (off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - LED_D_ON(); - off = false; - } - // note we appear to take about 7us to switch over (or run the if statements/loop...) - WaitUS(period_1-hack_cnt); - } - } - } else { // old mode of cmd read using delay as off period - while(*command != '\0' && *command != ' ') { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - WaitUS(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + memset(dest, 0, n); + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; LED_D_ON(); - if(*(command++) == '0') { - WaitUS(period_0); - } else { - WaitUS(period_1); - } } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + LED_D_OFF(); + if (i >= n) break; + } + } + Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) +{ + int at134khz; + + /* Make sure the tag is reset */ + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(2500); + + // see if 'h' was specified + if (command[strlen((char *) command) - 1] == 'h') + at134khz = TRUE; + else + at134khz = FALSE; + + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + // And a little more time for the tag to fully power up + SpinDelay(2000); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // now modulate the reader field + while(*command != '\0' && *command != ' ') { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - WaitUS(delay_off); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); - } + SpinDelayUs(delay_off); + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + LED_D_ON(); + if(*(command++) == '0') + SpinDelayUs(period_0); + else + SpinDelayUs(period_1); + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelayUs(delay_off); + if (at134khz) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz + else + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); // now do the read - DoAcquisition_config(false, 0); - - // Turn off antenna - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - // tell client we are done - cmd_send(CMD_ACK,0,0,0,0,0); + DoAcquisition125k(); } /* blank r/w tag data stream @@ -143,12 +139,15 @@ void ReadTItag(void) // when we read a TI tag we sample the zerocross line at 2Mhz // TI tags modulate a 1 as 16 cycles of 123.2Khz // TI tags modulate a 0 as 16 cycles of 134.2Khz - #define FSAMPLE 2000000 - #define FREQLO 123200 - #define FREQHI 134200 + #define FSAMPLE 2000000 + #define FREQLO 123200 + #define FREQHI 134200 + + signed char *dest = (signed char *)BigBuf; + int n = sizeof(BigBuf); +// int *dest = GraphBuffer; +// int n = GraphTraceLen; - signed char *dest = (signed char *)BigBuf_get_addr(); - uint16_t n = BigBuf_max_traceLen(); // 128 bit shift register [shift3:shift2:shift1:shift0] uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; @@ -159,7 +158,6 @@ void ReadTItag(void) uint32_t threshold = (sampleslo - sampleshi + 1)>>1; // TI tags charge at 134.2Khz - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz // Place FPGA in passthrough mode, in this mode the CROSS_LO line @@ -184,10 +182,10 @@ void ReadTItag(void) // TI bits are coming to us lsb first so shift them // right through our 128 bit right shift register - shift0 = (shift0>>1) | (shift1 << 31); - shift1 = (shift1>>1) | (shift2 << 31); - shift2 = (shift2>>1) | (shift3 << 31); - shift3 >>= 1; + shift0 = (shift0>>1) | (shift1 << 31); + shift1 = (shift1>>1) | (shift2 << 31); + shift2 = (shift2>>1) | (shift3 << 31); + shift3 >>= 1; // check if the cycles fall close to the number // expected for either the low or high frequency @@ -222,18 +220,18 @@ void ReadTItag(void) if (cycles!=0xF0B) { DbpString("Info: No valid tag detected."); } else { - // put 64 bit data into shift1 and shift0 - shift0 = (shift0>>24) | (shift1 << 8); - shift1 = (shift1>>24) | (shift2 << 8); + // put 64 bit data into shift1 and shift0 + shift0 = (shift0>>24) | (shift1 << 8); + shift1 = (shift1>>24) | (shift2 << 8); // align 16 bit crc into lower half of shift2 - shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; + shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; // if r/w tag, check ident match - if (shift3 & (1<<15) ) { + if ( shift3&(1<<15) ) { DbpString("Info: TI tag is rewriteable"); // only 15 bits compare, last bit of ident is not valid - if (((shift3 >> 16) ^ shift0) & 0x7fff ) { + if ( ((shift3>>16)^shift0)&0x7fff ) { DbpString("Error: Ident mismatch!"); } else { DbpString("Info: TI tag ident is valid"); @@ -248,7 +246,7 @@ void ReadTItag(void) // calculate CRC uint32_t crc=0; - crc = update_crc16(crc, (shift0)&0xff); + crc = update_crc16(crc, (shift0)&0xff); crc = update_crc16(crc, (shift0>>8)&0xff); crc = update_crc16(crc, (shift0>>16)&0xff); crc = update_crc16(crc, (shift0>>24)&0xff); @@ -258,7 +256,7 @@ void ReadTItag(void) crc = update_crc16(crc, (shift1>>24)&0xff); Dbprintf("Info: Tag data: %x%08x, crc=%x", - (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); + (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); if (crc != (shift2&0xffff)) { Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); } else { @@ -297,11 +295,10 @@ void AcquireTiType(void) int i, j, n; // tag transmission is <20ms, sampling at 2M gives us 40K samples max // each sample is 1 bit stuffed into a uint32_t so we need 1250 uint32_t - #define TIBUFLEN 1250 + #define TIBUFLEN 1250 // clear buffer - uint32_t *BigBuf = (uint32_t *)BigBuf_get_addr(); - BigBuf_Clear_ext(false); + memset(BigBuf,0,sizeof(BigBuf)); // Set up the synchronous serial port AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; @@ -349,7 +346,7 @@ void AcquireTiType(void) AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; - char *dest = (char *)BigBuf_get_addr(); + char *dest = (char *)BigBuf; n = TIBUFLEN*32; // unpack buffer for (i=TIBUFLEN-1; i>=0; i--) { @@ -368,9 +365,8 @@ void AcquireTiType(void) // if not provided a valid crc will be computed from the data and written. void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) { - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); if(crc == 0) { - crc = update_crc16(crc, (idlo)&0xff); + crc = update_crc16(crc, (idlo)&0xff); crc = update_crc16(crc, (idlo>>8)&0xff); crc = update_crc16(crc, (idlo>>16)&0xff); crc = update_crc16(crc, (idlo>>24)&0xff); @@ -380,7 +376,7 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) crc = update_crc16(crc, (idhi>>24)&0xff); } Dbprintf("Writing to tag: %x%08x, crc=%x", - (unsigned int) idhi, (unsigned int) idlo, crc); + (unsigned int) idhi, (unsigned int) idlo, crc); // TI tags charge at 134.2Khz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz @@ -432,79 +428,61 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) AcquireTiType(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Now use `lf ti read` to check"); + DbpString("Now use tiread to check"); } void SimulateTagLowFrequency(int period, int gap, int ledcontrol) { int i; - uint8_t *tab = BigBuf_get_addr(); - - //note FpgaDownloadAndGo destroys the bigbuf so be sure this is called before now... - //FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + uint8_t *tab = (uint8_t *)BigBuf; + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; - + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; - - #define SHORT_COIL() LOW(GPIO_SSC_DOUT) - #define OPEN_COIL() HIGH(GPIO_SSC_DOUT) - + +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) + i = 0; for(;;) { - //wait until SSC_CLK goes HIGH - int ii = 0; while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { - //only check every 1000th time (usb_poll_validate_length on some systems was too slow) - if ( ii == 1000 ) { - if (BUTTON_PRESS() || usb_poll_validate_length() ) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - return; - } - ii=0; + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; } WDT_HIT(); - ii++; } + if (ledcontrol) LED_D_ON(); - + if(tab[i]) OPEN_COIL(); else SHORT_COIL(); - + if (ledcontrol) LED_D_OFF(); - ii=0; - //wait until SSC_CLK goes LOW + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { - //only check every 1000th time (usb_poll_validate_length on some systems was too slow) - if ( ii == 1000 ) { - if (BUTTON_PRESS() || usb_poll_validate_length() ) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - return; - } - ii=0; + if(BUTTON_PRESS()) { + DbpString("Stopped"); + return; } WDT_HIT(); - ii++; } - + i++; if(i == period) { - i = 0; if (gap) { SHORT_COIL(); SpinDelayUs(gap); } } - } } @@ -513,31 +491,29 @@ void SimulateTagLowFrequencyBidir(int divisor, int t0) { } -// compose fc/8 fc/10 waveform (FSK2) -static void fc(int c, int *n) -{ - uint8_t *dest = BigBuf_get_addr(); +// compose fc/8 fc/10 waveform +static void fc(int c, int *n) { + uint8_t *dest = (uint8_t *)BigBuf; int idx; // for when we want an fc8 pattern every 4 logical bits if(c==0) { dest[((*n)++)]=1; dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; } - - // an fc/8 encoded bit is a bit pattern of 11110000 x6 = 48 samples + // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples if(c==8) { for (idx=0; idx<6; idx++) { dest[((*n)++)]=1; dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; @@ -545,14 +521,14 @@ static void fc(int c, int *n) } } - // an fc/10 encoded bit is a bit pattern of 1111100000 x5 = 50 samples + // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples if(c==10) { for (idx=0; idx<5; idx++) { dest[((*n)++)]=1; dest[((*n)++)]=1; dest[((*n)++)]=1; - dest[((*n)++)]=1; - dest[((*n)++)]=1; + dest[((*n)++)]=0; + dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; dest[((*n)++)]=0; @@ -561,40 +537,10 @@ static void fc(int c, int *n) } } } -// compose fc/X fc/Y waveform (FSKx) -static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt) -{ - uint8_t *dest = BigBuf_get_addr(); - uint8_t halfFC = fc/2; - uint8_t wavesPerClock = clock/fc; - uint8_t mod = clock % fc; //modifier - uint8_t modAdj = fc/mod; //how often to apply modifier - bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=true; - // loop through clock - step field clock - for (uint8_t idx=0; idx < wavesPerClock; idx++){ - // put 1/2 FC length 1's and 1/2 0's per field clock wave (to create the wave) - memset(dest+(*n), 0, fc-halfFC); //in case of odd number use extra here - memset(dest+(*n)+(fc-halfFC), 1, halfFC); - *n += fc; - } - if (mod>0) (*modCnt)++; - if ((mod>0) && modAdjOk){ //fsk2 - if ((*modCnt % modAdj) == 0){ //if 4th 8 length wave in a rf/50 add extra 8 length wave - memset(dest+(*n), 0, fc-halfFC); - memset(dest+(*n)+(fc-halfFC), 1, halfFC); - *n += fc; - } - } - if (mod>0 && !modAdjOk){ //fsk1 - memset(dest+(*n), 0, mod-(mod/2)); - memset(dest+(*n)+(mod-(mod/2)), 1, mod/2); - *n += mod; - } -} // prepare a waveform pattern in the buffer based on the ID given then // simulate a HID tag until the button is pressed -void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) +void CmdHIDsimTAG(int hi, int lo, int ledcontrol) { int n=0, i=0; /* @@ -607,50 +553,25 @@ void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) */ - if (hi2>0x0FFFFFFF) { - DbpString("Tags can only have 44 or 84 bits. - USE lf simfsk for larger tags"); + if (hi>0xFFF) { + DbpString("Tags can only have 44 bits."); return; } - // set LF so we don't kill the bigbuf we are setting with simulation data. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - fc(0,&n); // special start of frame marker containing invalid bit sequences - fc(8, &n); fc(8, &n); // invalid + fc(8, &n); fc(8, &n); // invalid fc(8, &n); fc(10, &n); // logical 0 fc(10, &n); fc(10, &n); // invalid fc(8, &n); fc(10, &n); // logical 0 WDT_HIT(); - if (hi2 > 0 || hi > 0xFFF){ - // manchester encode bits 91 to 64 (91-84 are part of the header) - for (i=27; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi2>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - WDT_HIT(); - // manchester encode bits 63 to 32 - for (i=31; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } - } - } else { - // manchester encode bits 43 to 32 - for (i=11; i>=0; i--) { - if ((i%4)==3) fc(0,&n); - if ((hi>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition - } else { - fc(8, &n); fc(10, &n); // high-low transition - } + // manchester encode bits 43 to 32 + for (i=11; i>=0; i--) { + if ((i%4)==3) fc(0,&n); + if ((hi>>i)&1) { + fc(10, &n); fc(8, &n); // low-high transition + } else { + fc(8, &n); fc(10, &n); // high-low transition } } @@ -659,9 +580,9 @@ void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) for (i=31; i>=0; i--) { if ((i%4)==3) fc(0,&n); if ((lo>>i)&1) { - fc(10, &n); fc(8, &n); // low-high transition + fc(10, &n); fc(8, &n); // low-high transition } else { - fc(8, &n); fc(10, &n); // high-low transition + fc(8, &n); fc(10, &n); // high-low transition } } @@ -673,1037 +594,862 @@ void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol) LED_A_OFF(); } -// prepare a waveform pattern in the buffer based on the ID given then -// simulate a FSK tag until the button is pressed -// arg1 contains fcHigh and fcLow, arg2 contains invert and clock -void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream) + +// loop to capture raw HID waveform then FSK demodulate the TAG ID from it +void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) { - int ledcontrol=1; - int n=0, i=0; - uint8_t fcHigh = arg1 >> 8; - uint8_t fcLow = arg1 & 0xFF; - uint16_t modCnt = 0; - uint8_t clk = arg2 & 0xFF; - uint8_t invert = (arg2 >> 8) & 1; + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, n=0, i=0, idx=0, found=0, lastval=0; + uint32_t hi2=0, hi=0, lo=0; - // set LF so we don't kill the bigbuf we are setting with simulation data. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - for (i=0; i> 8) & 0xFF; - uint8_t encoding = arg1 & 0xFF; - uint8_t separator = arg2 & 1; - uint8_t invert = (arg2 >> 8) & 1; - - // set LF so we don't kill the bigbuf we are setting with simulation data. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - if (encoding==2){ //biphase - uint8_t phase=0; - for (i=0; i> 8; - uint8_t carrier = arg1 & 0xFF; - uint8_t invert = arg2 & 0xFF; - uint8_t curPhase = 0; - // set LF so we don't kill the bigbuf we are setting with simulation data. - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - for (i=0; i0 && lo>0 && (size==96 || size==192)){ - uint8_t bitlen = 0; - uint32_t fc = 0; - uint32_t cardnum = 0; - bool decoded = false; - - // go over previously decoded manchester data and decode into usable tag ID - if ((hi2 & 0x000FFFF) != 0){ //extra large HID tags 88/192 bits - uint32_t bp = hi2 & 0x000FFFFF; - bitlen = 63; - while (bp > 0) { - bp = bp >> 1; - bitlen++; - } - } else if ((hi >> 6) > 0) { - uint32_t bp = hi; - bitlen = 31; - while (bp > 0) { - bp = bp >> 1; - bitlen++; - } - } else if (((hi >> 5) & 1) == 0) { - bitlen = 37; - } else if ((hi & 0x0000001F) > 0 ) { - uint32_t bp = (hi & 0x0000001F); - bitlen = 31; - while (bp > 0) { - bp = bp >> 1; - bitlen++; - } - } else { - uint32_t bp = lo; - bitlen = 0; - while (bp > 0) { - bp = bp >> 1; - bitlen++; - } + i = 0; + m = sizeof(BigBuf); + memset(dest,128,m); + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + if (ledcontrol) + LED_D_ON(); } - switch (bitlen){ - case 26: - cardnum = (lo>>1)&0xFFFF; - fc = (lo>>17)&0xFF; - decoded = true; - break; - case 35: - cardnum = (lo>>1)&0xFFFFF; - fc = ((hi&1)<<11)|(lo>>21); - decoded = true; + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; + i++; + if (ledcontrol) + LED_D_OFF(); + if(i >= m) { break; + } } - - if (hi2 != 0) //extra large HID tags 88/192 bits - Dbprintf("TAG ID: %x%08x%08x (%d)", - (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - else - Dbprintf("TAG ID: %x%08x (%d)", - (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); - - if (decoded) - Dbprintf("Format Len: %dbits - FC: %d - Card: %d", - (unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum); - - if (findone){ - if (ledcontrol) LED_A_OFF(); - *high2 = hi2; - *high = hi; - *low = lo; - break; - } - // reset } - hi2 = hi = lo = idx = 0; - WDT_HIT(); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); -} - -// loop to get raw HID waveform then FSK demodulate the TAG ID from it -void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol) -{ - uint8_t *dest = BigBuf_get_addr(); - size_t size; - int idx=0, dummyIdx=0; - //clear read buffer - BigBuf_Clear_keep_EM(); - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(95, true); - - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - - WDT_HIT(); - if (ledcontrol) LED_A_ON(); - - DoAcquisition_default(-1,true); // FSK demodulator - size = 50*128*2; //big enough to catch 2 sequences of largest format - idx = AWIDdemodFSK(dest, &size, &dummyIdx); - - if (idx<=0 || size!=96) continue; - // Index map - // 0 10 20 30 40 50 60 - // | | | | | | | - // 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96 - // ----------------------------------------------------------------------------- - // 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1 - // premable bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96 - // |---26 bit---| |-----117----||-------------142-------------| - // b = format bit len, o = odd parity of last 3 bits - // f = facility code, c = card number - // w = wiegand parity - // (26 bit format shown) - //get raw ID before removing parities - uint32_t rawLo = bytebits_to_byte(dest+idx+64,32); - uint32_t rawHi = bytebits_to_byte(dest+idx+32,32); - uint32_t rawHi2 = bytebits_to_byte(dest+idx,32); - - size = removeParity(dest, idx+8, 4, 1, 88); - if (size != 66) continue; - // ok valid card found! - - // Index map - // 0 10 20 30 40 50 60 - // | | | | | | | - // 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456 - // ----------------------------------------------------------------------------- - // 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000 - // bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - // |26 bit| |-117--| |-----142------| - // b = format bit len, o = odd parity of last 3 bits - // f = facility code, c = card number - // w = wiegand parity - // (26 bit format shown) - - uint32_t fc = 0; - uint32_t cardnum = 0; - uint32_t code1 = 0; - uint32_t code2 = 0; - uint8_t fmtLen = bytebits_to_byte(dest,8); - if (fmtLen==26){ - fc = bytebits_to_byte(dest+9, 8); - cardnum = bytebits_to_byte(dest+17, 16); - code1 = bytebits_to_byte(dest+8,fmtLen); - Dbprintf("AWID Found - BitLength: %d, FC: %d, Card: %d - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, fc, cardnum, code1, rawHi2, rawHi, rawLo); - } else { - cardnum = bytebits_to_byte(dest+8+(fmtLen-17), 16); - if (fmtLen>32){ - code1 = bytebits_to_byte(dest+8,fmtLen-32); - code2 = bytebits_to_byte(dest+8+(fmtLen-32),32); - Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x%08x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); - } else{ - code1 = bytebits_to_byte(dest+8,fmtLen); - Dbprintf("AWID Found - BitLength: %d -unknown BitLength- (%d) - Wiegand: %x, Raw: %08x%08x%08x", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); - } - } - if (findone){ - if (ledcontrol) LED_A_OFF(); - break; - } - // reset - idx = 0; - WDT_HIT(); - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); -} - -void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol) -{ - uint8_t *dest = BigBuf_get_addr(); - - size_t size=0, idx=0; - int clk=0, invert=0, errCnt=0, maxErr=20; - uint32_t hi=0; - uint64_t lo=0; - //clear read buffer - BigBuf_Clear_keep_EM(); - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(95, true); - - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { - - WDT_HIT(); - if (ledcontrol) LED_A_ON(); - - DoAcquisition_default(-1,true); - size = BigBuf_max_traceLen(); - //askdemod and manchester decode - if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format - errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1); - WDT_HIT(); - - if (errCnt<0) continue; - - errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); - if (errCnt){ - if (size>64){ - Dbprintf("EM XL TAG ID: %06x%08x%08x - (%05d_%03d_%08d)", - hi, - (uint32_t)(lo>>32), - (uint32_t)lo, - (uint32_t)(lo&0xFFFF), - (uint32_t)((lo>>16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); - } else { - Dbprintf("EM TAG ID: %02x%08x - (%05d_%03d_%08d)", - (uint32_t)(lo>>32), - (uint32_t)lo, - (uint32_t)(lo&0xFFFF), - (uint32_t)((lo>>16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); - } - - if (findone){ - if (ledcontrol) LED_A_OFF(); - *high=lo>>32; - *low=lo & 0xFFFFFFFF; + // sync to first lo-hi transition + for( idx=1; idx>1) & 0xFFFF); + } + else { + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + /* if we're only looking for one tag */ + if (findone) + { + *high = hi; + *low = lo; + return; + } + hi2=0; + hi=0; + lo=0; + found=0; + } + } + if (found) { + if (dest[idx] && (!dest[idx+1]) ) { + hi2=(hi2<<1)|(hi>>31); + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|0; + } else if ( (!dest[idx]) && dest[idx+1]) { + hi2=(hi2<<1)|(hi>>31); + hi=(hi<<1)|(lo>>31); + lo=(lo<<1)|1; + } else { + found=0; + hi2=0; + hi=0; + lo=0; + } + idx++; + } + if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) + { + found=1; + idx+=6; + if (found && (hi|lo)) { + if (hi2 != 0){ + Dbprintf("TAG ID: %x%08x%08x (%d)", + (unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + else { + Dbprintf("TAG ID: %x%08x (%d)", + (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); + } + /* if we're only looking for one tag */ + if (findone) + { + *high = hi; + *low = lo; + return; + } + hi2=0; + hi=0; + lo=0; + found=0; + } } } WDT_HIT(); - hi = lo = size = idx = 0; - clk = invert = errCnt = 0; } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - DbpString("Stopped"); - if (ledcontrol) LED_A_OFF(); } void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) { - uint8_t *dest = BigBuf_get_addr(); - int idx=0; + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, n=0, i=0, idx=0, lastval=0; + int found=0; uint32_t code=0, code2=0; - uint8_t version=0; - uint8_t facilitycode=0; - uint16_t number=0; - int dummyIdx=0; - //clear read buffer - BigBuf_Clear_keep_EM(); - // Configure to go in 125Khz listen mode - LFSetupFPGAForADC(95, true); + //uint32_t hi2=0, hi=0, lo=0; - while(!BUTTON_PRESS() && !usb_poll_validate_length()) { + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Give it a bit of time for the resonant antenna to settle. + SpinDelay(50); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + for(;;) { WDT_HIT(); - if (ledcontrol) LED_A_ON(); - DoAcquisition_default(-1,true); - //fskdemod and get start index + if (ledcontrol) + LED_A_ON(); + if(BUTTON_PRESS()) { + DbpString("Stopped"); + if (ledcontrol) + LED_A_OFF(); + return; + } + + i = 0; + m = sizeof(BigBuf); + memset(dest,128,m); + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x43; + if (ledcontrol) + LED_D_ON(); + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; + i++; + if (ledcontrol) + LED_D_OFF(); + if(i >= m) { + break; + } + } + } + + // FSK demodulator + + // sync to first lo-hi transition + for( idx=1; idx> 3) -#define BitStream_Bit(X) ((X) & 7) - - -void TurnReadLFOn(int delay) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - // Give it a bit of time for the resonant antenna to settle. - WaitUS(delay); //155*8 //50*8 -} +/* + * Relevant times in microsecond + * To compensate antenna falling times shorten the write times + * and enlarge the gap ones. + */ +#define START_GAP 250 +#define WRITE_GAP 160 +#define WRITE_0 144 // 192 +#define WRITE_1 400 // 432 for T55x7; 448 for E5550 // Write one bit to card -void T55xxWriteBit(int bit, T55xx_Timing *Timings) { - - // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 - // Dbprintf ("Bits : %d",bit); - switch (bit){ - case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 - case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 - case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 - case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 - case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(Timings->WRITE_GAP); -} - -// Function to abstract an Arbitrary length byte array to store bit pattern. -// bit_array - Array to hold data/bit pattern -// start_offset - bit location to start storing new bits. -// data - upto 32 bits of data to store -// num_bits - how many bits (low x bits of data) Max 32 bits at a time -// max_len - how many bytes can the bit_array hold (ensure no buffer overflow) -// returns "Next" bit offset / bits stored (for next store) -//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) -int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) +void T55xxWriteBit(int bit) { - int8_t offset; - int8_t NextOffset = start_offset; - - // Check if data will fit. - if ((start_offset + num_bits) <= (max_len*8)) { - // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) { - - if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 - else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 - - NextOffset++; - } - } - else { - // Note: This should never happen unless some code changes cause it. - // So short message for coders when testing. - Dbprintf ("T55 too many bits"); - } - return NextOffset; -} - -// Send one downlink command to the card -void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 !reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - 1xxxxxxx 0x80 reset - - */ - bool PwdMode = ((arg & 0x01) == 0x01); - bool Page = (arg & 0x02); - bool testMode = ((arg & 0x04) == 0x04); - uint8_t downlink_mode = (arg >> 3) & 0x03; - bool reg_readmode = ((arg & 0x20) == 0x20); - bool read_cmd = ((arg & 0x40) == 0x40); - bool reset = (arg & 0x80); - - uint8_t i = 0; - uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) - uint8_t BitStreamLen; - T55xx_Timing *Timing; - uint8_t SendBits; - - // Assigning Downlink Timeing for write - switch (downlink_mode) - { - case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; - case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; - case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; - case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; - default: - Timing = &T55xx_Timing_FixedBit; - } - - // Build Bit Stream to send. - memset (BitStream,0x00,sizeof(BitStream)); - - BitStreamLen = 0; // Ensure 0 bit index to start. - - // Add Leading 0 and 1 of 4 reference bit - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add extra reference 0 for 1 of 4 - if (downlink_mode == T55xx_DLMode_1of4) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Opcode - if (reset) { - // Reset : r*) 00 - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + if (bit == 0) + SpinDelayUs(WRITE_0); else - { - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - - if (PwdMode) { - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - } - - // Add Lock bit 0 - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); - } - - // Send Bits to T55xx - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. + SpinDelayUs(WRITE_1); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(Timing->START_GAP); - - // If long leading 0 send long reference pulse - if (downlink_mode == T55xx_DLMode_LLR) - T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - - if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time - for ( i = 0; i < BitStreamLen-1; i+=2 ) { - SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i - SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; - T55xxWriteBit (SendBits & 3,Timing); - } - } - else { - for (i = 0; i < BitStreamLen; i++) { - SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); - T55xxWriteBit (SendBits & 1,Timing); - } - } -} - -// Send T5577 reset command then read stream (see if we can identify the start of the stream) -void T55xxResetRead(void) { - LED_A_ON(); - - // send r* 00 - uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). - - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_keep_EM(); - - T55xx_SendCMD (0, 0, 0, arg); //, true); - - TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); - - // Acquisition - DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); - - // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); + SpinDelayUs(WRITE_GAP); } // Write one card block in page 0, no lock -void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 !reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - 1xxxxxxx 0x80 reset - */ - - bool testMode = ((arg & 0x04) == 0x04); - arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 - - LED_A_ON (); - T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false); +void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t PwdMode) +{ + unsigned int i; - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); - // "there is a clock delay before programming" - // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 - // so we should wait 1 clock + 5.6ms then read response? - // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... - if (testMode) { - //TESTMODE TIMING TESTS: - // <566us does nothing - // 566-568 switches between wiping to 0s and doing nothing - // 5184 wipes and allows 1 block to be programmed. - // indefinite power on wipes and then programs all blocks with bitshifted data sent. - TurnReadLFOn(5184); + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); - } else { - TurnReadLFOn(20 * 1000); - //could attempt to do a read to confirm write took - // as the tag should repeat back the new block - // until it is reset, but to confirm it we would - // need to know the current block 0 config mode for - // modulation clock an other details to demod the response... - // response should be (for t55x7) a 0 bit then (ST if on) - // block data written in on repeat until reset. - - //DoPartialAcquisition(20, true, 12000); - } - // turn field off + // Now start writting FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); - cmd_send(CMD_ACK,0,0,0,0,0); + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(0); //Page 0 + if (PwdMode == 1){ + // Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + } + // Lock bit + T55xxWriteBit(0); - LED_A_OFF (); + // Data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Data & i); + + // Block + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(Block & i); + + // Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + SpinDelay(20); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } -// Read one card block in page [page] -void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { - - LED_A_ON(); - - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 !reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - 1xxxxxxx 0x80 reset - */ - - // Set Read Flag to ensure SendCMD does not add "data" to the packet - arg0 |= 0x40; - - // RegRead Mode true of block 0xff - if (Block == 0xff) arg0 |= 0x20; - - //make sure block is at max 7 - Block &= 0x7; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - T55xx_SendCMD (0, Block, Pwd, arg0); //, true); - - // Turn field on to read the response - // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); - - // Acquisition +// Read one card block in page 0 +void T55xxReadBlock(uint32_t Block, uint32_t Pwd, uint8_t PwdMode) +{ + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, i=0; + + m = sizeof(BigBuf); + // Clear destination buffer before sending the command + memset(dest, 128, m); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + LED_D_ON(); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // Now start writting + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); + + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(0); //Page 0 + if (PwdMode == 1){ + // Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit(Pwd & i); + } + // Lock bit + T55xxWriteBit(0); + // Block + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit(Block & i); + + // Turn field on to read the response + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); - - // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); - - LED_A_OFF(); + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + // we don't care about actual value, only if it's more or less than a + // threshold essentially we capture zero crossings for later analysis + // if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; + i++; + if (i >= m) break; + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); + DbpString("DONE!"); } -void T55xxWakeUp(uint32_t Pwd){ - LED_B_ON(); - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 !reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - 1xxxxxxx 0x80 reset - */ - - // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD - // So, default Opcode 10 and pwd. - uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block - - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) - - T55xx_SendCMD (0, 0, Pwd, arg); //, true); - - // Turn and leave field on to let the begin repeating transmission - TurnReadLFOn(20*1000); +// Read card traceability data (page 1) +void T55xxReadTrace(void){ + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, i=0; + + m = sizeof(BigBuf); + // Clear destination buffer before sending the command + memset(dest, 128, m); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + LED_D_ON(); + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // Now start writting + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelayUs(START_GAP); + + // Opcode + T55xxWriteBit(1); + T55xxWriteBit(1); //Page 1 + + // Turn field on to read the response + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Now do the acquisition + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + if (i >= m) break; + } + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); + DbpString("DONE!"); } /*-------------- Cloning routines -----------*/ - -void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { - // write last block first and config block last (if included) - for (uint8_t i = numblocks+startblock; i > startblock; i--) { - T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); - //T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); - } -} - -// Copy a HID-like card (e.g. HID Proximity, Paradox) to a T55x7 compatible card -void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble) { - uint32_t data[] = {0,0,0,0,0,0,0}; - uint8_t last_block = 0; - - if (longFMT) { - // Ensure no more than 84 bits supplied - if (hi2>0xFFFFF) { - DbpString("Tags can only have 84 bits."); - return; - } - // Build the 6 data blocks for supplied 84bit ID - last_block = 6; - // load preamble & long format identifier (9E manchester encoded) - data[1] = (preamble << 24) | 0x96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF); - // load raw id from hi2, hi, lo to data blocks (manchester encoded) - data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF); - data[3] = manchesterEncode2Bytes(hi >> 16); - data[4] = manchesterEncode2Bytes(hi & 0xFFFF); - data[5] = manchesterEncode2Bytes(lo >> 16); - data[6] = manchesterEncode2Bytes(lo & 0xFFFF); - } else { - // Ensure no more than 44 bits supplied - if (hi>0xFFF) { - DbpString("Tags can only have 44 bits."); - return; - } - // Build the 3 data blocks for supplied 44bit ID - last_block = 3; - // load preamble - data[1] = (preamble << 24) | (manchesterEncode2Bytes(hi) & 0xFFFFFF); - data[2] = manchesterEncode2Bytes(lo >> 16); - data[3] = manchesterEncode2Bytes(lo & 0xFFFF); - } - // load chip config block - data[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2a | last_block << T55x7_MAXBLOCK_SHIFT; - - //TODO add selection of chip for Q5 or T55x7 - // data[0] = (((50-2)/2)<0xFFFFF) { + DbpString("Tags can only have 84 bits."); + return; + } + // Build the 6 data blocks for supplied 84bit ID + last_block = 6; + data1 = 0x1D96A900; // load preamble (1D) & long format identifier (9E manchester encoded) + for (int i=0;i<4;i++) { + if (hi2 & (1<<(19-i))) + data1 |= (1<<(((3-i)*2)+1)); // 1 -> 10 + else + data1 |= (1<<((3-i)*2)); // 0 -> 01 + } + + data2 = 0; + for (int i=0;i<16;i++) { + if (hi2 & (1<<(15-i))) + data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data2 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data3 = 0; + for (int i=0;i<16;i++) { + if (hi & (1<<(31-i))) + data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data3 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data4 = 0; + for (int i=0;i<16;i++) { + if (hi & (1<<(15-i))) + data4 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data4 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data5 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(31-i))) + data5 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data5 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data6 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(15-i))) + data6 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data6 |= (1<<((15-i)*2)); // 0 -> 01 + } + } + else { + // Ensure no more than 44 bits supplied + if (hi>0xFFF) { + DbpString("Tags can only have 44 bits."); + return; + } + + // Build the 3 data blocks for supplied 44bit ID + last_block = 3; + + data1 = 0x1D000000; // load preamble + + for (int i=0;i<12;i++) { + if (hi & (1<<(11-i))) + data1 |= (1<<(((11-i)*2)+1)); // 1 -> 10 + else + data1 |= (1<<((11-i)*2)); // 0 -> 01 + } + + data2 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(31-i))) + data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data2 |= (1<<((15-i)*2)); // 0 -> 01 + } + + data3 = 0; + for (int i=0;i<16;i++) { + if (lo & (1<<(15-i))) + data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10 + else + data3 |= (1<<((15-i)*2)); // 0 -> 01 + } + } + LED_D_ON(); // Program the data blocks for supplied ID // and the block 0 for HID format - WriteT55xx(data, 0, last_block+1); - + T55xxWriteBlock(data1,1,0,0); + T55xxWriteBlock(data2,2,0,0); + T55xxWriteBlock(data3,3,0,0); + + if (longFMT) { // if long format there are 6 blocks + T55xxWriteBlock(data4,4,0,0); + T55xxWriteBlock(data5,5,0,0); + T55xxWriteBlock(data6,6,0,0); + } + + // Config for HID (RF/50, FSK2a, Maxblock=3 for short/6 for long) + T55xxWriteBlock(T55x7_BITRATE_RF_50 | + T55x7_MODULATION_FSK2a | + last_block << T55x7_MAXBLOCK_SHIFT, + 0,0,0); + LED_D_OFF(); - + DbpString("DONE!"); } -void CopyIOtoT55x7(uint32_t hi, uint32_t lo) { - uint32_t data[] = {T55x7_BITRATE_RF_64 | T55x7_MODULATION_FSK2a | (2 << T55x7_MAXBLOCK_SHIFT), hi, lo}; - //TODO add selection of chip for Q5 or T55x7 - // data[0] = (((64-2)/2)<>1)<>32), (uint32_t)(id & 0xFFFFFFFF)}; + T55xxWriteBlock((uint32_t)(id >> 32), 1, 0, 0); + T55xxWriteBlock((uint32_t)id, 2, 0, 0); - clock = (card & 0xFF00) >> 8; - clock = (clock == 0) ? 64 : clock; - Dbprintf("Clock rate: %d", clock); - if (card & 0xFF) { //t55x7 - clock = GetT55xxClockBit(clock); - if (clock == 0) { - Dbprintf("Invalid clock rate: %d", clock); - return; + // Config for EM410x (RF/64, Manchester, Maxblock=2) + if (card) { + // Clock rate is stored in bits 8-15 of the card value + clock = (card & 0xFF00) >> 8; + Dbprintf("Clock rate: %d", clock); + switch (clock) + { + case 32: + clock = T55x7_BITRATE_RF_32; + break; + case 16: + clock = T55x7_BITRATE_RF_16; + break; + case 0: + // A value of 0 is assumed to be 64 for backwards-compatibility + // Fall through... + case 64: + clock = T55x7_BITRATE_RF_64; + break; + default: + Dbprintf("Invalid clock rate: %d", clock); + return; } - data[0] = clock | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT); - } else { //t5555 (Q5) - data[0] = T5555_SET_BITRATE(clock) | T5555_MODULATION_MANCHESTER | (2 << T5555_MAXBLOCK_SHIFT); - } - WriteT55xx(data, 0, 3); + // Writing configuration for T55x7 tag + T55xxWriteBlock(clock | + T55x7_MODULATION_MANCHESTER | + 2 << T55x7_MAXBLOCK_SHIFT, + 0, 0, 0); + } + else + // Writing configuration for T5555(Q5) tag + T55xxWriteBlock(0x1F << T5555_BITRATE_SHIFT | + T5555_MODULATION_MANCHESTER | + 2 << T5555_MAXBLOCK_SHIFT, + 0, 0, 0); LED_D_OFF(); Dbprintf("Tag %s written with 0x%08x%08x\n", card ? "T55x7":"T5555", - (uint32_t)(id >> 32), (uint32_t)id); + (uint32_t)(id >> 32), (uint32_t)id); } +// Clone Indala 64-bit tag by UID to T55x7 +void CopyIndala64toT55x7(int hi, int lo) +{ + + //Program the 2 data blocks for supplied 64bit UID + // and the block 0 for Indala64 format + T55xxWriteBlock(hi,1,0,0); + T55xxWriteBlock(lo,2,0,0); + //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=2) + T55xxWriteBlock(T55x7_BITRATE_RF_32 | + T55x7_MODULATION_PSK1 | + 2 << T55x7_MAXBLOCK_SHIFT, + 0, 0, 0); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) +// T5567WriteBlock(0x603E1042,0); + + DbpString("DONE!"); + +} + +void CopyIndala224toT55x7(int uid1, int uid2, int uid3, int uid4, int uid5, int uid6, int uid7) +{ + + //Program the 7 data blocks for supplied 224bit UID + // and the block 0 for Indala224 format + T55xxWriteBlock(uid1,1,0,0); + T55xxWriteBlock(uid2,2,0,0); + T55xxWriteBlock(uid3,3,0,0); + T55xxWriteBlock(uid4,4,0,0); + T55xxWriteBlock(uid5,5,0,0); + T55xxWriteBlock(uid6,6,0,0); + T55xxWriteBlock(uid7,7,0,0); + //Config for Indala (RF/32;PSK1 with RF/2;Maxblock=7) + T55xxWriteBlock(T55x7_BITRATE_RF_32 | + T55x7_MODULATION_PSK1 | + 7 << T55x7_MAXBLOCK_SHIFT, + 0,0,0); + //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) +// T5567WriteBlock(0x603E10E2,0); + + DbpString("DONE!"); + +} + + +#define abs(x) ( ((x)<0) ? -(x) : (x) ) +#define max(x,y) ( x GraphBuffer[0]) { + while(i < GraphTraceLen) { + if( !(GraphBuffer[i] > GraphBuffer[i-1]) && GraphBuffer[i] > lmax) + break; + i++; + } + dir = 0; + } + else { + while(i < GraphTraceLen) { + if( !(GraphBuffer[i] < GraphBuffer[i-1]) && GraphBuffer[i] < lmin) + break; + i++; + } + dir = 1; + } + + lastval = i++; + half_switch = 0; + pmc = 0; + block_done = 0; + + for (bitidx = 0; i < GraphTraceLen; i++) + { + if ( (GraphBuffer[i-1] > GraphBuffer[i] && dir == 1 && GraphBuffer[i] > lmax) || (GraphBuffer[i-1] < GraphBuffer[i] && dir == 0 && GraphBuffer[i] < lmin)) + { + lc = i - lastval; + lastval = i; + + // Switch depending on lc length: + // Tolerance is 1/8 of clock rate (arbitrary) + if (abs(lc-clock/4) < tolerance) { + // 16T0 + if((i - pmc) == lc) { /* 16T0 was previous one */ + /* It's a PMC ! */ + i += (128+127+16+32+33+16)-1; + lastval = i; + pmc = 0; + block_done = 1; + } + else { + pmc = i; + } + } else if (abs(lc-clock/2) < tolerance) { + // 32TO + if((i - pmc) == lc) { /* 16T0 was previous one */ + /* It's a PMC ! */ + i += (128+127+16+32+33)-1; + lastval = i; + pmc = 0; + block_done = 1; + } + else if(half_switch == 1) { + BitStream[bitidx++] = 0; + half_switch = 0; + } + else + half_switch++; + } else if (abs(lc-clock) < tolerance) { + // 64TO + BitStream[bitidx++] = 1; + } else { + // Error + warnings++; + if (warnings > 10) + { + Dbprintf("Error: too many detection errors, aborting."); + return 0; + } + } + + if(block_done == 1) { + if(bitidx == 128) { + for(j=0; j<16; j++) { + Blocks[num_blocks][j] = 128*BitStream[j*8+7]+ + 64*BitStream[j*8+6]+ + 32*BitStream[j*8+5]+ + 16*BitStream[j*8+4]+ + 8*BitStream[j*8+3]+ + 4*BitStream[j*8+2]+ + 2*BitStream[j*8+1]+ + BitStream[j*8]; + } + num_blocks++; + } + bitidx = 0; + block_done = 0; + half_switch = 0; + } + if (GraphBuffer[i-1] > GraphBuffer[i]) dir=0; + else dir = 1; + } + if(bitidx==255) + bitidx=0; + warnings = 0; + if(num_blocks == 4) break; + } + memcpy(outBlocks, Blocks, 16*num_blocks); + return num_blocks; +} + +int IsBlock0PCF7931(uint8_t *Block) { + // Assume RFU means 0 :) + if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled + return 1; + if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? + return 1; + return 0; +} + +int IsBlock1PCF7931(uint8_t *Block) { + // Assume RFU means 0 :) + if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) + if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) + return 1; + + return 0; +} + +#define ALLOC 16 + +void ReadPCF7931() { + uint8_t Blocks[8][17]; + uint8_t tmpBlocks[4][16]; + int i, j, ind, ind2, n; + int num_blocks = 0; + int max_blocks = 8; + int ident = 0; + int error = 0; + int tries = 0; + + memset(Blocks, 0, 8*17*sizeof(uint8_t)); + + do { + memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); + n = DemodPCF7931((uint8_t**)tmpBlocks); + if(!n) + error++; + if(error==10 && num_blocks == 0) { + Dbprintf("Error, no tag or bad tag"); + return; + } + else if (tries==20 || error==10) { + Dbprintf("Error reading the tag"); + Dbprintf("Here is the partial content"); + goto end; + } + + for(i=0; i= 0; ind--,ind2--) { + if(ind2 < 0) + ind2 = max_blocks; + if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found + // Dbprintf("Tmp %d -> Block %d", ind, ind2); + memcpy(Blocks[ind2], tmpBlocks[ind], 16); + Blocks[ind2][ALLOC] = 1; + num_blocks++; + if(num_blocks == max_blocks) goto end; + } + } + for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { + if(ind2 > max_blocks) + ind2 = 0; + if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found + // Dbprintf("Tmp %d -> Block %d", ind, ind2); + memcpy(Blocks[ind2], tmpBlocks[ind], 16); + Blocks[ind2][ALLOC] = 1; + num_blocks++; + if(num_blocks == max_blocks) goto end; + } + } + } + } + } + } + } + tries++; + if (BUTTON_PRESS()) return; + } while (num_blocks != max_blocks); +end: + Dbprintf("-----------------------------------------"); + Dbprintf("Memory content:"); + Dbprintf("-----------------------------------------"); + for(i=0; i", i); + } + Dbprintf("-----------------------------------------"); + + return ; +} + + //----------------------------------- // EM4469 / EM4305 routines //----------------------------------- @@ -1793,7 +1865,7 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 #define FWD_CMD_DISABLE 0x5 -#define FWD_CMD_PROTECT 0x3 + uint8_t forwardLink_data[64]; //array of forwarded bits uint8_t * forward_ptr; //ptr for forward message preparation @@ -1805,85 +1877,84 @@ uint8_t * fwd_write_ptr; //forwardlink bit pointer // see EM4469 spec //==================================================================== //-------------------------------------------------------------------- -// VALUES TAKEN FROM EM4x function: SendForward -// START_GAP = 440; (55*8) cycles at 125Khz (8us = 1cycle) -// WRITE_GAP = 128; (16*8) -// WRITE_1 = 256 32*8; (32*8) - -// These timings work for 4469/4269/4305 (with the 55*8 above) -// WRITE_0 = 23*8 , 9*8 SpinDelayUs(23*8); - uint8_t Prepare_Cmd( uint8_t cmd ) { - - *forward_ptr++ = 0; //start bit - *forward_ptr++ = 0; //second pause for 4050 code - - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - cmd >>= 1; - *forward_ptr++ = cmd; - - return 6; //return number of emited bits + //-------------------------------------------------------------------- + + *forward_ptr++ = 0; //start bit + *forward_ptr++ = 0; //second pause for 4050 code + + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + cmd >>= 1; + *forward_ptr++ = cmd; + + return 6; //return number of emited bits } //==================================================================== // prepares address bits // see EM4469 spec //==================================================================== + +//-------------------------------------------------------------------- uint8_t Prepare_Addr( uint8_t addr ) { - - register uint8_t line_parity; - - uint8_t i; - line_parity = 0; - for(i=0;i<6;i++) { - *forward_ptr++ = addr; - line_parity ^= addr; - addr >>= 1; - } - - *forward_ptr++ = (line_parity & 1); - - return 7; //return number of emited bits + //-------------------------------------------------------------------- + + register uint8_t line_parity; + + uint8_t i; + line_parity = 0; + for(i=0;i<6;i++) { + *forward_ptr++ = addr; + line_parity ^= addr; + addr >>= 1; + } + + *forward_ptr++ = (line_parity & 1); + + return 7; //return number of emited bits } //==================================================================== // prepares data bits intreleaved with parity bits // see EM4469 spec //==================================================================== + +//-------------------------------------------------------------------- uint8_t Prepare_Data( uint16_t data_low, uint16_t data_hi) { - - register uint8_t line_parity; - register uint8_t column_parity; - register uint8_t i, j; - register uint16_t data; - - data = data_low; - column_parity = 0; - - for(i=0; i<4; i++) { - line_parity = 0; - for(j=0; j<8; j++) { - line_parity ^= data; - column_parity ^= (data & 1) << j; - *forward_ptr++ = data; - data >>= 1; - } - *forward_ptr++ = line_parity; - if(i == 1) - data = data_hi; - } - - for(j=0; j<8; j++) { - *forward_ptr++ = column_parity; - column_parity >>= 1; - } - *forward_ptr = 0; - - return 45; //return number of emited bits + //-------------------------------------------------------------------- + + register uint8_t line_parity; + register uint8_t column_parity; + register uint8_t i, j; + register uint16_t data; + + data = data_low; + column_parity = 0; + + for(i=0; i<4; i++) { + line_parity = 0; + for(j=0; j<8; j++) { + line_parity ^= data; + column_parity ^= (data & 1) << j; + *forward_ptr++ = data; + data >>= 1; + } + *forward_ptr++ = line_parity; + if(i == 1) + data = data_hi; + } + + for(j=0; j<8; j++) { + *forward_ptr++ = column_parity; + column_parity >>= 1; + } + *forward_ptr = 0; + + return 45; //return number of emited bits } //==================================================================== @@ -1892,196 +1963,114 @@ uint8_t Prepare_Data( uint16_t data_low, uint16_t data_hi) { // fwd_bit_count set with number of bits to be sent //==================================================================== void SendForward(uint8_t fwd_bit_count) { - - fwd_write_ptr = forwardLink_data; - fwd_bit_sz = fwd_bit_count; - - // Set up FPGA, 125kHz or 95 divisor - LFSetupFPGAForADC(95, true); - - // force 1st mod pulse (start gap must be longer for 4305) - fwd_bit_sz--; //prepare next bit modulation - fwd_write_ptr++; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - WaitUS(55*8); //55 cycles off (8us each)for 4305 //another reader has 37 here... - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - WaitUS(18*8); //18 cycles on (8us each) - - // now start writting - 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); //32 cycles at 125Khz (8us each) - else { - //These timings work for 4469/4269/4305 (with the 55*8 above) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - WaitUS(23*8); //23 cycles off (8us each) - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - WaitUS((32-23)*8); //remaining cycles on (8us each) - } - } + + fwd_write_ptr = forwardLink_data; + fwd_bit_sz = fwd_bit_count; + + LED_D_ON(); + + //Field on + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); + + // Give it a bit of time for the resonant antenna to settle. + // And for the tag to fully power up + SpinDelay(150); + + // force 1st mod pulse (start gap must be longer for 4305) + fwd_bit_sz--; //prepare next bit modulation + fwd_write_ptr++; + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + SpinDelayUs(55*8); //55 cycles off (8us each)for 4305 + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);//field on + SpinDelayUs(16*8); //16 cycles on (8us each) + + // now start writting + while(fwd_bit_sz-- > 0) { //prepare next bit modulation + if(((*fwd_write_ptr++) & 1) == 1) + SpinDelayUs(32*8); //32 cycles at 125Khz (8us each) + else { + //These timings work for 4469/4269/4305 (with the 55*8 above) + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + SpinDelayUs(23*8); //16-4 cycles off (8us each) + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);//field on + SpinDelayUs(9*8); //16 cycles on (8us each) + } + } } void EM4xLogin(uint32_t Password) { - - uint8_t fwd_bit_count; - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_LOGIN ); - fwd_bit_count += Prepare_Data( Password&0xFFFF, Password>>16 ); - - SendForward(fwd_bit_count); - - //Wait for command to complete - SpinDelay(20); + + uint8_t fwd_bit_count; + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_LOGIN ); + fwd_bit_count += Prepare_Data( Password&0xFFFF, Password>>16 ); + + SendForward(fwd_bit_count); + + //Wait for command to complete + SpinDelay(20); + } void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { - - uint8_t fwd_bit_count; - - // Clear destination buffer before sending the command - BigBuf_Clear_ext(false); - - LED_A_ON(); - StartTicks(); - //If password mode do login - if (PwdMode == 1) EM4xLogin(Pwd); - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); - fwd_bit_count += Prepare_Addr( Address ); - - SendForward(fwd_bit_count); - WaitUS(400); - // Now do the acquisition - DoPartialAcquisition(20, true, 6000, 1000); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_A_OFF(); - cmd_send(CMD_ACK,0,0,0,0,0); + + uint8_t fwd_bit_count; + uint8_t *dest = (uint8_t *)BigBuf; + int m=0, i=0; + + //If password mode do login + if (PwdMode == 1) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_READ ); + fwd_bit_count += Prepare_Addr( Address ); + + m = sizeof(BigBuf); + // Clear destination buffer before sending the command + memset(dest, 128, m); + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + SendForward(fwd_bit_count); + + // Now do the acquisition + i = 0; + for(;;) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = 0x43; + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { + dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + i++; + if (i >= m) break; + } + } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); } -void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { - - bool PwdMode = (flag & 0x1); - uint8_t Address = (flag >> 8) & 0xFF; - uint8_t fwd_bit_count; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - LED_A_ON(); - StartTicks(); - //If password mode do login - if (PwdMode) EM4xLogin(Pwd); - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE ); - fwd_bit_count += Prepare_Addr( Address ); - fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); - - SendForward(fwd_bit_count); - - //Wait for write to complete - //SpinDelay(10); - - WaitUS(6500); - //Capture response if one exists - DoPartialAcquisition(20, true, 6000, 1000); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_A_OFF(); - cmd_send(CMD_ACK,0,0,0,0,0); -} - -void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd) { - - bool PwdMode = (flag & 0x1); - uint8_t fwd_bit_count; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - LED_A_ON(); - StartTicks(); - //If password mode do login - if (PwdMode) EM4xLogin(Pwd); - - forward_ptr = forwardLink_data; - fwd_bit_count = Prepare_Cmd( FWD_CMD_PROTECT ); - - //unsure if this needs the full packet config... - fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); - - SendForward(fwd_bit_count); - - //Wait for write to complete - //SpinDelay(10); - - WaitUS(6500); - //Capture response if one exists - DoPartialAcquisition(20, true, 6000, 1000); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - LED_A_OFF(); - cmd_send(CMD_ACK,0,0,0,0,0); -} -/* -Reading a COTAG. - -COTAG needs the reader to send a startsequence and the card has an extreme slow datarate. -because of this, we can "sample" the data signal but we interpreate it to Manchester direct. - -READER START SEQUENCE: -burst 800 us, gap 2.2 msecs -burst 3.6 msecs gap 2.2 msecs -burst 800 us gap 2.2 msecs -pulse 3.6 msecs - -This triggers a COTAG tag to response -*/ -void Cotag(uint32_t arg0) { - -#define OFF { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(2035); } -#define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } - - uint8_t rawsignal = arg0 & 0xF; - - LED_A_ON(); - - // Switching to LF image on FPGA. This might empty BigBuff - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - // Set up FPGA, 132kHz to power up the tag - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 89); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC); - - // start clock - 1.5ticks is 1us - StartTicks(); - - //send COTAG start pulse - ON(740) OFF - ON(3330) OFF - ON(740) OFF - ON(1000) - - switch(rawsignal) { - case 0: doCotagAcquisition(50000); break; - case 1: doCotagAcquisitionManchester(); break; - case 2: DoAcquisition_config(true, 0); break; - } - - // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); +void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { + + uint8_t fwd_bit_count; + + //If password mode do login + if (PwdMode == 1) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_WRITE ); + fwd_bit_count += Prepare_Addr( Address ); + fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); + + SendForward(fwd_bit_count); + + //Wait for write to complete + SpinDelay(20); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_D_OFF(); } diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c deleted file mode 100644 index e0764063..00000000 --- a/armsrc/lfsampling.c +++ /dev/null @@ -1,402 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// Miscellaneous routines for low frequency sampling. -//----------------------------------------------------------------------------- - -#include "proxmark3.h" -#include "apps.h" -#include "util.h" -#include "string.h" -#include "lfsampling.h" -#include "usb_cdc.h" // for usb_poll_validate_length -#include "fpgaloader.h" - -sample_config config = { 1, 8, 1, 95, 0, 0 } ; - -void printConfig() -{ - Dbprintf("LF Sampling config: "); - Dbprintf(" [q] divisor: %d ", config.divisor); - Dbprintf(" [b] bps: %d ", config.bits_per_sample); - Dbprintf(" [d] decimation: %d ", config.decimation); - Dbprintf(" [a] averaging: %d ", config.averaging); - Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); - Dbprintf(" [s] samples to skip: %d ", config.samples_to_skip); -} - - -/** - * Called from the USB-handler to set the sampling configuration - * The sampling config is used for std reading and snooping. - * - * Other functions may read samples and ignore the sampling config, - * such as functions to read the UID from a prox tag or similar. - * - * Values set to '0' implies no change (except for averaging, threshold, samples_to_skip) - * @brief setSamplingConfig - * @param sc - */ -void setSamplingConfig(uint8_t *config_data) { - sample_config *sc = (sample_config *)config_data; - if (sc->divisor != 0) config.divisor = sc->divisor; - if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; - if (sc->decimation != 0) config.decimation = sc->decimation; - if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; - if (sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; - - config.averaging= sc->averaging; - if (config.bits_per_sample > 8) config.bits_per_sample = 8; - if (config.decimation < 1) config.decimation = 1; - - printConfig(); -} - -sample_config* getSamplingConfig() -{ - return &config; -} - -typedef struct { - uint8_t * buffer; - uint32_t numbits; - uint32_t position; -} BitstreamOut; - -/** - * @brief Pushes bit onto the stream - * @param stream - * @param bit - */ -void pushBit( BitstreamOut* stream, uint8_t bit) -{ - int bytepos = stream->position >> 3; // divide by 8 - int bitpos = stream->position & 7; - *(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos); - stream->position++; - stream->numbits++; -} - -/** -* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream -* if not already loaded, sets divisor and starts up the antenna. -* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz -* 0 or 95 ==> 125 KHz -* -**/ -void LFSetupFPGAForADC(int divisor, bool lf_field) -{ - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz - else if (divisor == 0) - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - else - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); - - // Connect the A/D to the peak-detected low-frequency path. - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(50); - // Now set up the SSC to get the ADC samples that are now streaming at us. - FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC); -} - -/** - * Does the sample acquisition. If threshold is specified, the actual sampling - * is not commenced until the threshold has been reached. - * This method implements decimation and quantization in order to - * be able to provide longer sample traces. - * Uses the following global settings: - * @param decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc. - * @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample. - * @param averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample - * value that will be used is the average value of the three samples. - * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set - * to -1 to ignore threshold. - * @param silent - is true, now outputs are made. If false, dbprints the status - * @return the number of bits occupied by the samples. - */ -uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after, int samples_to_skip) -{ - //. - uint8_t *dest = BigBuf_get_addr(); - bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); - - //memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow) - - if(bits_per_sample < 1) bits_per_sample = 1; - if(bits_per_sample > 8) bits_per_sample = 8; - - if(decimation < 1) decimation = 1; - - // Use a bit stream to handle the output - BitstreamOut data = { dest , 0, 0}; - int sample_counter = 0; - uint8_t sample = 0; - //If we want to do averaging - uint32_t sample_sum =0 ; - uint32_t sample_total_numbers =0 ; - uint32_t sample_total_saved =0 ; - uint32_t cancel_counter = 0; - uint32_t samples_skipped = 0; - - while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - // threshold either high or low values 128 = center 0. if trigger = 178 - if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) { // - if (cancel_after > 0) { - cancel_counter++; - if (cancel_after == cancel_counter) break; - } - continue; - } - trigger_threshold = 0; - if (samples_to_skip > samples_skipped) { - samples_skipped++; - continue; - } - sample_total_numbers++; - - if(averaging) - { - sample_sum += sample; - } - //Check decimation - if(decimation > 1) - { - sample_counter++; - if(sample_counter < decimation) continue; - sample_counter = 0; - } - //Averaging - if(averaging && decimation > 1) { - sample = sample_sum / decimation; - sample_sum =0; - } - //Store the sample - sample_total_saved ++; - if(bits_per_sample == 8){ - dest[sample_total_saved-1] = sample; - data.numbits = sample_total_saved << 3;//Get the return value correct - if(sample_total_saved >= bufsize) break; - } - else{ - pushBit(&data, sample & 0x80); - if(bits_per_sample > 1) pushBit(&data, sample & 0x40); - if(bits_per_sample > 2) pushBit(&data, sample & 0x20); - if(bits_per_sample > 3) pushBit(&data, sample & 0x10); - if(bits_per_sample > 4) pushBit(&data, sample & 0x08); - if(bits_per_sample > 5) pushBit(&data, sample & 0x04); - if(bits_per_sample > 6) pushBit(&data, sample & 0x02); - //Not needed, 8bps is covered above - //if(bits_per_sample > 7) pushBit(&data, sample & 0x01); - if((data.numbits >> 3) +1 >= bufsize) break; - } - } - } - - if(!silent) - { - Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample",sample_total_saved, sample_total_numbers,bits_per_sample); - Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", - dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); - } - return data.numbits; -} -/** - * @brief Does sample acquisition, ignoring the config values set in the sample_config. - * This method is typically used by tag-specific readers who just wants to read the samples - * the normal way - * @param trigger_threshold - * @param silent - * @return number of bits sampled - */ -uint32_t DoAcquisition_default(int trigger_threshold, bool silent) -{ - return DoAcquisition(1,8,0,trigger_threshold,silent,0,0,0); -} -uint32_t DoAcquisition_config(bool silent, int sample_size) -{ - return DoAcquisition(config.decimation - ,config.bits_per_sample - ,config.averaging - ,config.trigger_threshold - ,silent - ,sample_size - ,0 - ,config.samples_to_skip); -} - -uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) { - return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after,0); -} - -uint32_t ReadLF(bool activeField, bool silent, int sample_size) -{ - if (!silent) printConfig(); - LFSetupFPGAForADC(config.divisor, activeField); - // Now call the acquisition routine - return DoAcquisition_config(silent, sample_size); -} - -/** -* Initializes the FPGA for reader-mode (field on), and acquires the samples. -* @return number of bits sampled -**/ -uint32_t SampleLF(bool printCfg, int sample_size) -{ - uint32_t ret = ReadLF(true, printCfg, sample_size); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - return ret; -} -/** -* Initializes the FPGA for snoop-mode (field off), and acquires the samples. -* @return number of bits sampled -**/ - -uint32_t SnoopLF() -{ - uint32_t ret = ReadLF(false, true, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - return ret; -} - -/** -* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 -* and is Manchester?, we directly gather the manchester data into bigbuff -**/ -#define COTAG_T1 384 -#define COTAG_T2 (COTAG_T1>>1) -#define COTAG_ONE_THRESHOLD 128+30 -#define COTAG_ZERO_THRESHOLD 128-30 -#ifndef COTAG_BITS -#define COTAG_BITS 264 -#endif -void doCotagAcquisition(size_t sample_size) { - - uint8_t *dest = BigBuf_get_addr(); - uint16_t bufsize = BigBuf_max_traceLen(); - - if ( bufsize > sample_size ) - bufsize = sample_size; - - dest[0] = 0; - uint8_t sample = 0, firsthigh = 0, firstlow = 0; - uint16_t i = 0; - - while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) ) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - - // find first peak - if ( !firsthigh ) { - if (sample < COTAG_ONE_THRESHOLD) - continue; - firsthigh = 1; - } - if ( !firstlow ){ - if (sample > COTAG_ZERO_THRESHOLD ) - continue; - firstlow = 1; - } - - ++i; - - if ( sample > COTAG_ONE_THRESHOLD) - dest[i] = 255; - else if ( sample < COTAG_ZERO_THRESHOLD) - dest[i] = 0; - else - dest[i] = dest[i-1]; - } - } -} - -uint32_t doCotagAcquisitionManchester() { - - uint8_t *dest = BigBuf_get_addr(); - uint16_t bufsize = BigBuf_max_traceLen(); - - if ( bufsize > COTAG_BITS ) - bufsize = COTAG_BITS; - - dest[0] = 0; - uint8_t sample = 0, firsthigh = 0, firstlow = 0; - uint16_t sample_counter = 0, period = 0; - uint8_t curr = 0, prev = 0; - uint16_t noise_counter = 0; - while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1<<1)) ) { - WDT_HIT(); - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - AT91C_BASE_SSC->SSC_THR = 0x43; - LED_D_ON(); - } - - if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - LED_D_OFF(); - - // find first peak - if ( !firsthigh ) { - if (sample < COTAG_ONE_THRESHOLD) { - noise_counter++; - continue; - } - noise_counter = 0; - firsthigh = 1; - } - - if ( !firstlow ){ - if (sample > COTAG_ZERO_THRESHOLD ) { - noise_counter++; - continue; - } - noise_counter=0; - firstlow = 1; - } - - // set sample 255, 0, or previous - if ( sample > COTAG_ONE_THRESHOLD){ - prev = curr; - curr = 1; - } - else if ( sample < COTAG_ZERO_THRESHOLD) { - prev = curr; - curr = 0; - } - else { - curr = prev; - } - - // full T1 periods, - if ( period > 0 ) { - --period; - continue; - } - - dest[sample_counter] = curr; - ++sample_counter; - period = COTAG_T1; - } - } - return sample_counter; -} diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h deleted file mode 100644 index 3c0fc93e..00000000 --- a/armsrc/lfsampling.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef LFSAMPLING_H__ -#define LFSAMPLING_H__ - -/** -* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 -* and is Manchester?, we directly gather the manchester data into bigbuff -**/ -void doCotagAcquisition(size_t sample_size); -uint32_t doCotagAcquisitionManchester(void); - -/** -* Initializes the FPGA for reader-mode (field on), and acquires the samples. -* @return number of bits sampled -**/ -uint32_t SampleLF(bool silent, int sample_size); - -/** -* Initializes the FPGA for snoop-mode (field off), and acquires the samples. -* @return number of bits sampled -**/ -uint32_t SnoopLF(); - -// adds sample size to default options -uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after); - -/** - * @brief Does sample acquisition, ignoring the config values set in the sample_config. - * This method is typically used by tag-specific readers who just wants to read the samples - * the normal way - * @param trigger_threshold - * @param silent - * @return number of bits sampled - */ -uint32_t DoAcquisition_default(int trigger_threshold, bool silent); -/** - * @brief Does sample acquisition, using the config values set in the sample_config. - * @param trigger_threshold - * @param silent - * @return number of bits sampled - */ - -uint32_t DoAcquisition_config(bool silent, int sample_size); - -/** -* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream -* if not already loaded, sets divisor and starts up the antenna. -* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz -* 0 or 95 ==> 125 KHz -* -**/ -void LFSetupFPGAForADC(int divisor, bool lf_field); - -/** - * Called from the USB-handler to set the sampling configuration - * The sampling config is used for std reading and snooping. - * - * Other functions may read samples and ignore the sampling config, - * such as functions to read the UID from a prox tag or similar. - * - * Values set to '0' implies no change (except for averaging) - * @brief setSamplingConfig - * @param sc - */ -void setSamplingConfig(uint8_t *config_data); - -sample_config *getSamplingConfig(); - -void printConfig(); - - -#endif // LFSAMPLING_H diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 15db8f11..c934a280 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2,9 +2,6 @@ // Merlok - June 2011, 2012 // Gerhard de Koning Gans - May 2008 // Hagen Fritsch - June 2010 -// Midnitesnake - Dec 2013 -// Andy Davies - Apr 2014 -// Iceman - May 2014 // // 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 @@ -14,61 +11,21 @@ //----------------------------------------------------------------------------- #include "mifarecmd.h" - -#include - -#include "proxmark3.h" -#include "usb_cdc.h" -#include "crapto1/crapto1.h" -#include "iso14443a.h" -#include "BigBuf.h" -#include "mifareutil.h" #include "apps.h" -#include "protocols.h" -#include "util.h" -#include "parity.h" -#include "crc.h" -#include "fpgaloader.h" - -#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) -#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication - -/* -// the block number for the ISO14443-4 PCB -static uint8_t pcb_blocknum = 0; -// Deselect card by sending a s-block. the crc is precalced for speed -static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; - -static void OnSuccess(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} -*/ - -static void OnError(uint8_t reason){ - // pcb_blocknum = 0; - // ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - cmd_send(CMD_ACK,0,reason,0,0,0); - LED_A_OFF(); -} //----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. +// Select, Authenticaate, Read an MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - LED_A_ON(); - + // params uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + + // variables byte_t isOK = 0; byte_t dataoutbuf[16]; uint8_t uid[10]; @@ -77,142 +34,123 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State *pcs; pcs = &mpcs; + // clear trace + iso14a_clear_trace(); +// iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; - + if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; - + isOK = 1; break; } - + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); +// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; +// memcpy(ack.d.asBytes, dataoutbuf, 16); + LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - LEDsoff(); -} - -void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ - - LED_A_ON(); - bool turnOffField = (arg0 == 1); - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); - OnError(0); - return; - }; - - if (!mifare_ultra_auth(keybytes)){ - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed"); - OnError(1); - return; - } - - if (turnOffField) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - } - - cmd_send(CMD_ACK,1,0,0,0,0); - LED_A_OFF(); -} - -// Arg0 = BlockNo, -// Arg1 = UsePwd bool -// datain = PWD bytes, -void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) -{ - LED_A_ON(); - - uint8_t blockNo = arg0; - byte_t dataout[16] = {0x00}; - bool useKey = (arg1 == 1); //UL_C - bool usePwd = (arg1 == 2); //UL_EV1/NTAG - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); - if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); - OnError(1); - return; - } - - // UL-C authentication - if (useKey) { - uint8_t key[16] = {0x00}; - memcpy(key, datain, sizeof(key) ); - - if ( !mifare_ultra_auth(key) ) { - OnError(1); - return; - } - } - - // UL-EV1 / NTAG authentication - if (usePwd) { - uint8_t pwd[4] = {0x00}; - memcpy(pwd, datain, 4); - uint8_t pack[4] = {0,0,0,0}; - if (!mifare_ul_ev1_auth(pwd, pack)) { - OnError(1); - return; - } - } - - if (mifare_ultra_readblock(blockNo, dataout)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error"); - OnError(2); - return; - } - - if (mifare_ultra_halt()) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error"); - OnError(3); - return; - } + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - cmd_send(CMD_ACK,1,0,0,dataout,16); - LED_A_OFF(); -} - -//----------------------------------------------------------------------------- -// Select, Authenticate, Read a MIFARE tag. -// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes) + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +void MifareUReadBlock(uint8_t arg0,uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read sector (data = 4 x 16 bytes = 64 bytes) //----------------------------------------------------------------------------- void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { @@ -221,162 +159,155 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + // variables byte_t isOK = 0; - byte_t dataoutbuf[16 * 16]; + byte_t dataoutbuf[16 * 4]; 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 + iso14a_clear_trace(); +// iso14a_set_tracing(false); - clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - isOK = 1; - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - isOK = 0; - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - } - - - if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST, NULL)) { - isOK = 0; - if (MF_DBGLEVEL >= 1) 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 (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; - } - } + }; - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - } + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf + 16 * 1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf + 16 * 2)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf + 16 * 3)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error"); + break; + }; + + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + isOK = 1; + break; + } + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - + if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + +// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; +// memcpy(ack.d.asBytes, dataoutbuf, 16 * 2); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,32); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); +// SpinDelay(100); + +// memcpy(ack.d.asBytes, dataoutbuf + 16 * 2, 16 * 2); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32); + LED_B_OFF(); + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo)); - LED_B_OFF(); - LEDsoff(); -} - -// arg0 = blockNo (start) -// arg1 = Pages (number of blocks) -// arg2 = useKey -// datain = KEY bytes -void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) -{ - LED_A_ON(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // free eventually allocated BigBuf memory - BigBuf_free(); - - // params - uint8_t blockNo = arg0; - uint16_t blocks = arg1; - bool useKey = (arg2 == 1); //UL_C - bool usePwd = (arg2 == 2); //UL_EV1/NTAG - uint32_t countblocks = 0; - uint8_t *dataout = BigBuf_malloc(CARD_MEMORY_SIZE); - if (dataout == NULL){ - Dbprintf("out of memory"); - OnError(1); - return; - } - - int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); - if (!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len); - OnError(1); - return; - } - - // UL-C authentication - if (useKey) { - uint8_t key[16] = {0x00}; - memcpy(key, datain, sizeof(key) ); - - if ( !mifare_ultra_auth(key) ) { - OnError(1); - return; - } - } - - // UL-EV1 / NTAG authentication - if (usePwd) { - uint8_t pwd[4] = {0x00}; - memcpy(pwd, datain, sizeof(pwd)); - uint8_t pack[4] = {0,0,0,0}; - - if (!mifare_ul_ev1_auth(pwd, pack)){ - OnError(1); - return; - } - } - - for (int i = 0; i < blocks; i++){ - if ((i*4) + 4 >= CARD_MEMORY_SIZE) { - Dbprintf("Data exceeds buffer!!"); - break; - } - - len = mifare_ultra_readblock(blockNo + i, dataout + 4 * i); - - if (len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block %d error",i); - // if no blocks read - error out - if (i==0){ - OnError(2); - return; - } else { - //stop at last successful read block and return what we got - break; - } - } else { - countblocks++; - } - } - - len = mifare_ultra_halt(); - if (len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error"); - OnError(3); - return; - } - - if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); - - BigBuf_free(); - LED_A_OFF(); -} - -//----------------------------------------------------------------------------- -// Select, Authenticate, Write a MIFARE tag. -// read block +// iso14a_set_tracing(TRUE); + +} + +void MifareUReadCard(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t sectorNo = arg0; + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); +// iso14a_set_tracing(false); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + for(int sec=0;sec<16;sec++){ + if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec); + break; + }; + } + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64); + //cmd_send(CMD_ACK,isOK,0,0,dataoutbuf+32, 32); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read block //----------------------------------------------------------------------------- void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { @@ -388,7 +319,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); memcpy(blockdata, datain + 10, 16); - + // variables byte_t isOK = 0; uint8_t uid[10]; @@ -397,373 +328,206 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) struct Crypto1State *pcs; pcs = &mpcs; - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + // clear trace + iso14a_clear_trace(); +// iso14a_set_tracing(false); - clear_trace(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); LED_A_ON(); LED_B_OFF(); LED_C_OFF(); while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; - + if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; - + isOK = 1; break; } - + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); +// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - LEDsoff(); -} - -/* // Command not needed but left for future testing -void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) -{ - uint8_t blockNo = arg0; - byte_t blockdata[16] = {0x00}; - - memcpy(blockdata, datain, 16); - - uint8_t uid[10] = {0x00}; - - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - clear_trace(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if(!iso14443a_select_card(uid, NULL, NULL, true, 0)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - OnError(0); - return; - }; - - if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(0); - return; }; - - if(mifare_ultra_halt()) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - OnError(0); - return; - }; - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - cmd_send(CMD_ACK,1,0,0,0,0); LEDsoff(); -} -*/ - -// Arg0 : Block to write to. -// Arg1 : 0 = use no authentication. -// 1 = use 0x1A authentication. -// 2 = use 0x1B authentication. -// datain : 4 first bytes is data to be written. -// : 4/16 next bytes is authentication key. -void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) -{ - uint8_t blockNo = arg0; - bool useKey = (arg1 == 1); //UL_C - bool usePwd = (arg1 == 2); //UL_EV1/NTAG - byte_t blockdata[4] = {0x00}; - - memcpy(blockdata, datain,4); - - LEDsoff(); - LED_A_ON(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - - if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - OnError(0); - return; - }; - - // UL-C authentication - if ( useKey ) { - uint8_t key[16] = {0x00}; - memcpy(key, datain+4, sizeof(key) ); - - if ( !mifare_ultra_auth(key) ) { - OnError(1); - return; - } - } - - // UL-EV1 / NTAG authentication - if (usePwd) { - uint8_t pwd[4] = {0x00}; - memcpy(pwd, datain+4, 4); - uint8_t pack[4] = {0,0,0,0}; - if (!mifare_ul_ev1_auth(pwd, pack)) { - OnError(1); - return; - } - } - - if(mifare_ultra_writeblock(blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(0); - return; - }; - - if(mifare_ultra_halt()) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - OnError(0); - return; - }; - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - cmd_send(CMD_ACK,1,0,0,0,0); - LEDsoff(); -} - -void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ - - uint8_t pwd[16] = {0x00}; - byte_t blockdata[4] = {0x00}; - - memcpy(pwd, datain, 16); - - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - - if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - OnError(0); - return; - }; - - blockdata[0] = pwd[7]; - blockdata[1] = pwd[6]; - blockdata[2] = pwd[5]; - blockdata[3] = pwd[4]; - if(mifare_ultra_writeblock( 44, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(44); - return; - }; - - blockdata[0] = pwd[3]; - blockdata[1] = pwd[2]; - blockdata[2] = pwd[1]; - blockdata[3] = pwd[0]; - if(mifare_ultra_writeblock( 45, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(45); - return; - }; - - blockdata[0] = pwd[15]; - blockdata[1] = pwd[14]; - blockdata[2] = pwd[13]; - blockdata[3] = pwd[12]; - if(mifare_ultra_writeblock( 46, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(46); - return; - }; - - blockdata[0] = pwd[11]; - blockdata[1] = pwd[10]; - blockdata[2] = pwd[9]; - blockdata[3] = pwd[8]; - if(mifare_ultra_writeblock( 47, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - OnError(47); - return; - }; - - if(mifare_ultra_halt()) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - OnError(0); - return; - }; - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - cmd_send(CMD_ACK,1,0,0,0,0); - LEDsoff(); -} - -// Return 1 if the nonce is invalid else return 0 -int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) { - return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ - (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ - (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; -} - - -//----------------------------------------------------------------------------- -// acquire encrypted nonces in order to perform the attack described in -// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened -// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on -// Computer and Communications Security, 2015 -//----------------------------------------------------------------------------- -void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain) { - uint64_t ui64Key = 0; - uint8_t uid[10]; - uint32_t cuid; - uint8_t cascade_levels = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - int16_t isOK = 0; - uint8_t par_enc[1]; - uint8_t nt_par_enc = 0; - uint8_t buf[USB_CMD_DATA_SIZE]; - uint32_t timeout; - - uint8_t blockNo = arg0 & 0xff; - uint8_t keyType = (arg0 >> 8) & 0xff; - uint8_t targetBlockNo = arg1 & 0xff; - uint8_t targetKeyType = (arg1 >> 8) & 0xff; - ui64Key = bytes_to_num(datain, 6); - bool initialize = flags & 0x0001; - bool slow = flags & 0x0002; - bool field_off = flags & 0x0004; - - LED_A_ON(); - - if (initialize) { +// iso14a_set_tracing(TRUE); + +} + +void MifareUWriteBlock(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + byte_t blockdata[16]; + + memset(blockdata,'\0',16); + memcpy(blockdata, datain,16); + + // variables + byte_t isOK = 0; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + // iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - set_tracing(true); - } - - uint16_t num_nonces = 0; - bool have_uid = false; - for (uint16_t i = 0; i <= USB_CMD_DATA_SIZE - 9; ) { - - // Test if the action was cancelled - if(BUTTON_PRESS()) { - isOK = 2; - field_off = true; - break; - } - - 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 (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); - continue; - } - switch (card_info.uidlen) { - case 4 : cascade_levels = 1; break; - case 7 : cascade_levels = 2; break; - case 10: cascade_levels = 3; break; - default: break; - } - 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 (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); - continue; - } - } - - if (slow) { - timeout = GetCountSspClk() + HARDNESTED_PRE_AUTHENTICATION_LEADTIME; - while(GetCountSspClk() < timeout); - } - - uint32_t nt1; - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); - continue; - } - - // nested authentication - uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL); - if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); - continue; - } - - // send an incomplete dummy response in order to trigger the card's authentication failure timeout - uint8_t dummy_answer[1] = {0}; - ReaderTransmit(dummy_answer, 1, NULL); - - timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT; - - num_nonces++; - if (num_nonces % 2) { - memcpy(buf+i, receivedAnswer, 4); - nt_par_enc = par_enc[0] & 0xf0; - } else { - nt_par_enc |= par_enc[0] >> 4; - memcpy(buf+i+4, receivedAnswer, 4); - memcpy(buf+i+8, &nt_par_enc, 1); - i += 9; - } - - // wait for the card to become ready again - while(GetCountSspClk() < timeout); - - } - - crypto1_destroy(pcs); - - if (field_off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - } - - if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); - - cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); - - LED_A_OFF(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,0,0); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + byte_t blockdata[4]; + + memcpy(blockdata, datain,4); + + // variables + byte_t isOK = 0; + uint8_t uid[10]; + uint32_t cuid; + + // clear trace + iso14a_clear_trace(); + // iso14a_set_tracing(false); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if(mifare_ultra_halt(cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,0,0); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +// Return 1 if the nonce is invalid else return 0 +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { + return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; } -//----------------------------------------------------------------------------- -// MIFARE nested authentication. -// -//----------------------------------------------------------------------------- -void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain) { +//----------------------------------------------------------------------------- +// MIFARE nested authentication. +// +//----------------------------------------------------------------------------- +void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain) +{ + // params uint8_t blockNo = arg0 & 0xff; uint8_t keyType = (arg0 >> 8) & 0xff; uint8_t targetBlockNo = arg1 & 0xff; @@ -771,91 +535,80 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - + + // variables uint16_t rtr, i, j, len; uint16_t davg; static uint16_t dmin, dmax; uint8_t uid[10]; - uint32_t cuid, nt1, nt2_enc, nttmp, nttest, ks1; - uint8_t par[1]; + uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1; uint32_t target_nt[2], target_ks[2]; - uint32_t fixed_nt = 0; - uint8_t target_nt_duplicate_count = 0; - + uint8_t par_array[4]; uint16_t ncount = 0; struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); - uint32_t auth1_time, auth2_time, authentication_timeout = 0; + uint32_t auth1_time, auth2_time; static uint16_t delta_time; - LED_A_ON(); + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(false); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - // free eventually allocated BigBuf memory - BigBuf_free(); + LED_A_ON(); + LED_C_OFF(); - if (calibrate) clear_trace(); - set_tracing(true); // statistics on nonce distance - int16_t isOK = 0; - #define NESTED_MAX_TRIES 12 - uint16_t unsuccessfull_tries = 0; - if (calibrate) { // for first call only. Otherwise reuse previous calibration - WDT_HIT(); + if (calibrate) { // for first call only. Otherwise reuse previous calibration + LED_B_ON(); davg = dmax = 0; dmin = 2000; delta_time = 0; - + for (rtr = 0; rtr < 17; rtr++) { // prepare next select. No need to power down the card. - if (mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); rtr--; continue; } - // Test if the action was cancelled - if (BUTTON_PRESS()) { - isOK = -2; - break; - } - - if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); rtr--; continue; }; auth1_time = 0; - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); rtr--; continue; }; - fixed_nt = nt1; if (delta_time) { auth2_time = auth1_time + delta_time; } else { auth2_time = 0; } - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2_enc, &auth2_time, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); rtr--; continue; }; - nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 + nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 101; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); - if (nttmp == nt2_enc) break; + if (nttmp == nt2) break; } if (i != 1200) { @@ -868,78 +621,73 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing } if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i); - } else { - unsuccessfull_tries++; - if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) - isOK = -3; - } } } + + if (rtr <= 1) return; davg = (davg + (rtr - 1)/2) / (rtr - 1); - - if (MF_DBGLEVEL >= 3) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, dmin, dmax, davg, delta_time); + + if (MF_DBGLEVEL >= 3) Dbprintf("min=%d max=%d avg=%d, delta_time=%d", dmin, dmax, davg, delta_time); dmin = davg - 2; dmax = davg + 2; - + + LED_B_OFF(); + } - // ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- + + LED_C_ON(); // get crypted nonces for target sector - for (i = 0; i < 2 && !isOK; i++) { // look for exactly two different nonces + for(i=0; i < 2; i++) { // look for exactly two different nonces target_nt[i] = 0; - while (target_nt[i] == 0 && !isOK) { // continue until we have an unambiguous nonce - + while(target_nt[i] == 0) { // continue until we have an unambiguous nonce + // prepare next select. No need to power down the card. - if (mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); continue; } - // break out of the loop on button press - if (BUTTON_PRESS()) { - isOK = -2; - break; - } - - if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); continue; - } - + }; + auth1_time = 0; - authentication_timeout = 0; - if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time, &authentication_timeout)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); continue; - } + }; // nested authentication auth2_time = auth1_time + delta_time; - len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); + len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par, &auth2_time); if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; - } - - nt2_enc = bytes_to_num(receivedAnswer, 4); - if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2_enc, par[0]); - + }; + + nt2 = bytes_to_num(receivedAnswer, 4); + if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par); + // Parity validity check for (j = 0; j < 4; j++) { - par_array[j] = (oddparity8(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01)); + par_array[j] = (oddparity(receivedAnswer[j]) != ((par & 0x08) >> 3)); + par = par << 1; } - + ncount = 0; nttest = prng_successor(nt1, dmin - 1); for (j = dmin; j < dmax + 1; j++) { nttest = prng_successor(nttest, 1); - ks1 = nt2_enc ^ nttest; + ks1 = nt2 ^ nttest; - if (valid_nonce(nttest, nt2_enc, ks1, par_array)){ - if (ncount > 0) { // we are only interested in disambiguous nonces, try again + if (valid_nonce(nttest, nt2, ks1, par_array)){ + if (ncount > 0) { // we are only interested in disambiguous nonces, try again if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j); target_nt[i] = 0; break; @@ -948,12 +696,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat target_ks[i] = ks1; ncount++; if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces - if( ++target_nt_duplicate_count >= NESTED_MAX_TRIES ) { // unable to get a 2nd nonce after NESTED_MAX_TRIES tries, probably a fixed nonce - if (MF_DBGLEVEL >= 2) Dbprintf("Nonce#2: cannot get nonce that != nonce#1, continuing anyway with single nonce! ntdist=%d", j); - break; - } - - target_nt[1] = 0; + target_nt[i] = 0; if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j); break; } @@ -964,153 +707,116 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat } } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - + LED_C_OFF(); + + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); - uint8_t buf[4 + 4 * 4 + 4 + 4]; + byte_t buf[4 + 4 * 4]; memcpy(buf, &cuid, 4); memcpy(buf+4, &target_nt[0], 4); memcpy(buf+8, &target_ks[0], 4); memcpy(buf+12, &target_nt[1], 4); memcpy(buf+16, &target_ks[1], 4); - memcpy(buf+20, &authentication_timeout, 4); - memcpy(buf+24, &fixed_nt, 4); - - if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - - cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); - - LED_A_OFF(); -} - - -//----------------------------------------------------------------------------- -// MIFARE check keys. key count up to 85. -// -//----------------------------------------------------------------------------- -void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain) { - - uint8_t blockNo = arg0 & 0xff; - uint8_t keyType = arg0 >> 8; - bool clearTrace = arg1 & 0x01; - bool multisectorCheck = arg1 & 0x02; - bool init = arg1 & 0x04; - bool drop_field = arg1 & 0x08; - bool fixed_nonce = arg1 & 0x10; - uint32_t auth_timeout = arg1 >> 16; - uint8_t keyCount = arg2; - - LED_A_ON(); - - if (init) { - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - } - if (clearTrace) { - clear_trace(); - } - set_tracing(true); + LED_B_ON(); + cmd_send(CMD_ACK, 0, 2, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); + LED_B_OFF(); - // clear debug level. We are expecting lots of authentication failures... - int OLD_MF_DBGLEVEL = MF_DBGLEVEL; - MF_DBGLEVEL = MF_DBG_NONE; + if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - int res = 0; - if (multisectorCheck) { - TKeyIndex keyIndex = {{0}}; - uint8_t sectorCnt = blockNo; - res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, &auth_timeout, OLD_MF_DBGLEVEL, &keyIndex); - if (res >= 0) { - cmd_send(CMD_ACK, 1, res, 0, keyIndex, 80); - } else { - cmd_send(CMD_ACK, 0, res, 0, NULL, 0); - } - } else if (fixed_nonce) { - res = MifareChkBlockKeysFixedNonce(datain, keyCount, blockNo, keyType, &auth_timeout, OLD_MF_DBGLEVEL); - if (res > 0) { - cmd_send(CMD_ACK, 1, res, 0, NULL, 0); // key found - } else { - cmd_send(CMD_ACK, 0, res, 0, NULL, 0); // no key found or aborted - } - } else { - res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, &auth_timeout, OLD_MF_DBGLEVEL); - if (res > 0) { - cmd_send(CMD_ACK, 1, res, 0, datain + (res - 1) * 6, 6); - } else { - cmd_send(CMD_ACK, 0, res, 0, NULL, 0); - } - } - - if (drop_field || res != 0) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - } - - // restore debug level - MF_DBGLEVEL = OLD_MF_DBGLEVEL; - - LED_A_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + iso14a_set_tracing(TRUE); } - //----------------------------------------------------------------------------- -// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID +// MIFARE check keys. key count up to 85. +// //----------------------------------------------------------------------------- -void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *data) { - +void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint8_t keyCount = arg2; + uint64_t ui64Key = 0; + + // variables + int i; + byte_t isOK = 0; uint8_t uid[10]; uint32_t cuid; struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; - - LED_A_ON(); - clear_trace(); + + // clear debug level + int OLD_MF_DBGLEVEL = MF_DBGLEVEL; + MF_DBGLEVEL = MF_DBG_NONE; + + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - bool isOK = false; - while (true) { - if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + +// SpinDelay(300); + for (i = 0; i < keyCount; i++) { +// FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +// SpinDelay(100); +// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + // prepare next select by sending a HALT. There is no need to power down the card. + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error"); } - uint8_t block_number = 0; - uint64_t key = bytes_to_num(data, 6); - if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + // SpinDelay(50); + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card"); 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 (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - break;; - } - isOK = true; + ui64Key = bytes_to_num(datain + i * 6, 6); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + continue; + }; + + isOK = 1; break; } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - + + // ----------------------------- crypto1 destroy crypto1_destroy(pcs); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); - if (MF_DBGLEVEL >= 2) DbpString("PERSONALIZE UID FINISHED"); + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6); + LED_B_OFF(); - cmd_send(CMD_ACK, isOK, 0, 0, NULL, 0); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); - LED_A_OFF(); + // restore debug level + MF_DBGLEVEL = OLD_MF_DBGLEVEL; } //----------------------------------------------------------------------------- // MIFARE commands set debug level -// +// //----------------------------------------------------------------------------- void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ MF_DBGLEVEL = arg0; @@ -1119,38 +825,35 @@ void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai //----------------------------------------------------------------------------- // Work with emulator memory -// -// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) here although FPGA is not -// involved in dealing with emulator memory. But if it is called later, it might -// destroy the Emulator Memory. +// //----------------------------------------------------------------------------- - void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); emlClearMem(); } void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); emlSetMem(datain, arg0, arg1); // data, block num, blocks count } void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - byte_t buf[USB_CMD_DATA_SIZE]; - emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4) +// UsbCommand ack = {CMD_ACK, {arg0, arg1, 0}}; + + byte_t buf[48]; + emlGetMem(buf, arg0, arg1); // data, block num, blocks count LED_B_ON(); - cmd_send(CMD_ACK,arg0,arg1,0,buf,USB_CMD_DATA_SIZE); + cmd_send(CMD_ACK,arg0,arg1,0,buf,48); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); } //----------------------------------------------------------------------------- // Load a card into the emulator memory -// +// //----------------------------------------------------------------------------- void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - uint8_t numSectors = arg0; + int i; + uint8_t sectorNo = 0; uint8_t keyType = arg1; uint64_t ui64Key = 0; uint32_t cuid; @@ -1163,215 +866,99 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai byte_t dataoutbuf2[16]; uint8_t uid[10]; + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(false); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(false); - - bool isOK = true; - - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - } - - for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { - ui64Key = emlGetKey(sectorNo, keyType); - if (sectorNo == 0){ - if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST, NULL)) { - isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); - break; - } - } else { - if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED, NULL)) { - isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); - break; - } - } - - for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { - if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { - isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); - break; - }; - if (isOK) { - if (blockNo < NumBlocksPerSector(sectorNo) - 1) { - emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); - } else { // sector trailer, keep the keys, set only the AC - emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); - memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); - emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + for (i = 0; i < 16; i++) { + sectorNo = i; + ui64Key = emlGetKey(sectorNo, keyType); + + if (!i){ + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth error", i); + break; + } + } else { + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_NESTED)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth nested error", i); + break; } } + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 0, 1); + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 1, 1); + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 2, 1); + + // get block 3 bytes 6-9 + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error"); + break; + }; + emlGetMem(dataoutbuf2, sectorNo * 4 + 3, 1); + memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); + emlSetMem(dataoutbuf2, sectorNo * 4 + 3, 1); } - } - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - }; + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + break; + } // ----------------------------- crypto1 destroy crypto1_destroy(pcs); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - + if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); } +//----------------------------------------------------------------------------- +// MIFARE 1k emulator +// +//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn) -// +// //----------------------------------------------------------------------------- - -static bool isBlockTrailer(int blockN) { - if (blockN >= 0 && blockN < 128) { - return ((blockN & 0x03) == 0x03); - } - if (blockN >= 128 && blockN <= 256) { - return ((blockN & 0x0F) == 0x0F); - } - return false; -} - -void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - // var - byte_t isOK = 0; - uint32_t numBlocks = arg0; - // cmdParams: - // bit 0 - wipe gen1a - // bit 1 - fill card with default data - // bit 2 - gen1a = 0, gen1b = 1 - uint8_t cmdParams = arg1; - bool needWipe = cmdParams & 0x01; - bool needFill = cmdParams & 0x02; - bool gen1b = cmdParams & 0x04; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; - uint8_t block1[16] = {0x00}; - uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t d_block[18] = {0x00}; - - // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - uint8_t wipeC[] = { 0x41 }; - - // iso14443 setup - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - // tracing - clear_trace(); - set_tracing(true); - - while (true){ - // wipe - if (needWipe){ - ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); - break; - }; - - ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); - break; - }; - - if(mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); - }; - }; - - // put default data - if (needFill){ - // select commands - ReaderTransmitBitsPar(wupC1, 7, 0, NULL); - - // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) - if (!gen1b) { - - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); - break; - }; - - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); - break; - }; - } - - // send blocks command - for (int blockNo = 0; blockNo < numBlocks; blockNo++) { - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); - break; - }; - - // check type of block and add crc - if (!isBlockTrailer(blockNo)){ - memcpy(d_block, block1, 16); - } else { - memcpy(d_block, blockK, 16); - } - if (blockNo == 0) { - memcpy(d_block, block0, 16); - } - AppendCrc14443a(d_block, 16); - - // send write command - ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); - break; - }; - } - - // halt - // do no issue halt command for gen1b - if (!gen1b) { - if (mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); - break; - } - } - } - break; - } - - // reset fpga - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - // send USB response - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,NULL,0); - LED_B_OFF(); - - LEDsoff(); - - return; -} - void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - + // params uint8_t needWipe = arg0; // bit 0 - need get UID @@ -1379,319 +966,231 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // bit 2 - need HALT after sequence // bit 3 - need init FPGA and field before sequence // bit 4 - need reset FPGA and LED - // bit 6 - gen1b backdoor type uint8_t workFlags = arg1; uint8_t blockNo = arg2; - + // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - uint8_t wipeC[] = { 0x41 }; - + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + uint8_t wipeC[] = { 0x41 }; + // variables byte_t isOK = 0; - uint8_t uid[10] = {0x00}; - uint8_t d_block[18] = {0x00}; + uint8_t uid[10]; + uint8_t d_block[18]; uint32_t cuid; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - // reset FPGA and LED + + memset(uid, 0x00, 10); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + if (workFlags & 0x08) { + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); + + SpinDelay(300); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); } while (true) { - // get UID from chip if (workFlags & 0x01) { - if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - // Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work. - //break; - }; + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; - if(mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); - // Continue, some magic tags misbehavies and send an answer to it. - // break; - }; + if(mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; }; - + // reset chip - // Wipe command don't work with gen1b - if (needWipe && !(workFlags & 0x40)){ - ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if (needWipe){ + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; - if(mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); - // Continue, some magic tags misbehavies and send an answer to it. - // break; + if(mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; }; - }; + }; // write block if (workFlags & 0x02) { - ReaderTransmitBitsPar(wupC1,7,0, NULL); + ReaderTransmitBitsPar(wupC1,7,0, NULL); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + break; + }; - // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) - if (!(workFlags & 0x40)) { - - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); - break; - }; - - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); - break; - }; - } + ReaderTransmit(wupC2, sizeof(wupC2), NULL); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + break; + }; } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); break; }; - + memcpy(d_block, datain, 16); AppendCrc14443a(d_block, 16); - + ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + if ((ReaderReceive(receivedAnswer) != 1) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; - }; - + }; + if (workFlags & 0x04) { - // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) - if (!(workFlags & 0x40)) { - if (mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); - // Continue, some magic tags misbehavies and send an answer to it. - // break; - } - } + if (mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; } - + isOK = 1; break; } - - if ((workFlags & 0x10) || (!isOK)) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - } + +// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; +// if (isOK) memcpy(ack.d.asBytes, uid, 4); + + // add trace trailer + /** + * Removed by Martin, the uid is overwritten with 0x44, + * which can 't be intended. + * + * memset(uid, 0x44, 4); + * LogTrace(uid, 4, 0, 0, TRUE); + **/ + LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,uid,4); + cmd_send(CMD_ACK,isOK,0,0,uid,4); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - LEDsoff(); + if ((workFlags & 0x10) || (!isOK)) { + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + } } - void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ - - // params + + // params // bit 1 - need wupC // bit 2 - need HALT after sequence // bit 3 - need init FPGA and field before sequence // bit 4 - need reset FPGA and LED - // bit 5 - need to set datain instead of issuing USB reply (called via ARM for StandAloneMode14a) - // bit 6 - gen1b backdoor type uint8_t workFlags = arg0; uint8_t blockNo = arg2; - + // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - + uint8_t wupC1[] = { 0x40 }; + uint8_t wupC2[] = { 0x43 }; + // variables byte_t isOK = 0; - uint8_t data[18] = {0x00}; + uint8_t data[18]; uint32_t cuid = 0; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + + memset(data, 0x00, 18); + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + if (workFlags & 0x08) { + // clear trace + iso14a_clear_trace(); + iso14a_set_tracing(TRUE); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); + + SpinDelay(300); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); } while (true) { if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; - }; - // do no issue for gen1b magic tag - if (!(workFlags & 0x40)) { + }; + ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer) || (receivedAnswer[0] != 0x0a)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } - } // read block - if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { - if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); + if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, NULL) != 18)) { + if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); break; }; memcpy(data, receivedAnswer, 18); - + if (workFlags & 0x04) { - // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) - if (!(workFlags & 0x40)) { - if (mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL > 1) Dbprintf("Halt error"); - // Continue, some magic tags misbehavies and send an answer to it. - // break; - } - } + if (mifare_classic_halt(NULL, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; } - + isOK = 1; break; } + +// UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; +// if (isOK) memcpy(ack.d.asBytes, data, 18); + + // add trace trailer + /* + * Removed by Martin, this piece of overwrites the 'data' variable + * which is sent two lines down, and is obviously not correct. + * + * memset(data, 0x44, 4); + * LogTrace(data, 4, 0, 0, TRUE); + */ + LED_B_ON(); + cmd_send(CMD_ACK,isOK,0,0,data,18); +// UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); if ((workFlags & 0x10) || (!isOK)) { + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } - - LED_B_ON(); - if (workFlags & 0x20) { - if (isOK) - memcpy(datain, data, 18); - } - else - cmd_send(CMD_ACK,isOK,0,0,data,18); - LED_B_OFF(); - - LEDsoff(); -} - -void MifareCIdent(){ - - // card commands - uint8_t wupC1[] = { 0x40 }; - uint8_t wupC2[] = { 0x43 }; - - // variables - byte_t isOK = 0; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - clear_trace(); - set_tracing(true); - - ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { - isOK = 2; - - ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { - isOK = 1; - }; - }; - - // From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it. - mifare_classic_halt(NULL, 0); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - LED_B_ON(); - cmd_send(CMD_ACK,isOK,0,0,0,0); - LED_B_OFF(); - - LEDsoff(); -} - -// -// DESFIRE -// - -void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ - - byte_t dataout[11] = {0x00}; - uint8_t uid[10] = {0x00}; - uint32_t cuid; - - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - - int len = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); - if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); - OnError(1); - return; - }; - - if(mifare_desfire_des_auth1(cuid, dataout)){ - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication part1: Fail."); - OnError(4); - return; - } - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED"); - - cmd_send(CMD_ACK, 1, cuid, 0, dataout, sizeof(dataout)); -} - -void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ - - uint32_t cuid = arg0; - uint8_t key[16] = {0x00}; - byte_t isOK = 0; - byte_t dataout[12] = {0x00}; - - memcpy(key, datain, 16); - - isOK = mifare_desfire_des_auth2(cuid, key, dataout); - - if (isOK) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); - OnError(4); - return; - } - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED"); - - cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout)); - LEDsoff(); } diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 40bfb965..3c00a343 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -10,36 +10,19 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#ifndef MIFARECMD_H__ -#define MIFARECMD_H__ +#ifndef __MIFARECMD_H +#define __MIFARECMD_H -#include +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" -extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); -extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain); -extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); -extern void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -extern void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -//extern void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); -extern void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -extern void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); -extern void MifareChkKeys(uint16_t arg0, uint32_t arg1, uint8_t arg2, uint8_t *datain); -extern void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card -extern void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -extern void MifareCIdent(); // is "magic chinese" card? -extern void MifareUSetPwd(uint8_t arg0, uint8_t *datain); -extern void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *datain); +#include "iso14443crc.h" +#include "iso14443a.h" +#include "crapto1.h" +#include "mifareutil.h" +#include "common.h" -//desfire -extern void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); -extern void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); -#endif +#endif \ No newline at end of file diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c deleted file mode 100644 index abf800ce..00000000 --- a/armsrc/mifaresim.c +++ /dev/null @@ -1,867 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011, 2012 -// Gerhard de Koning Gans - May 2008 -// Hagen Fritsch - June 2010 -// -// 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. -//----------------------------------------------------------------------------- -// Mifare Classic Card Simulation -//----------------------------------------------------------------------------- - -#include "mifaresim.h" -#include "iso14443a.h" -#include "iso14443crc.h" -#include "crapto1/crapto1.h" -#include "BigBuf.h" -#include "string.h" -#include "mifareutil.h" -#include "fpgaloader.h" -#include "proxmark3.h" -#include "usb_cdc.h" -#include "protocols.h" -#include "apps.h" -#include "util.h" - - -//mifare emulator states -#define MFEMUL_NOFIELD 0 -#define MFEMUL_IDLE 1 -#define MFEMUL_SELECT1 2 -#define MFEMUL_SELECT2 3 -#define MFEMUL_SELECT3 4 -#define MFEMUL_AUTH1 5 -#define MFEMUL_AUTH2 6 -#define MFEMUL_WORK 7 -#define MFEMUL_WRITEBL2 8 -#define MFEMUL_INTREG_INC 9 -#define MFEMUL_INTREG_DEC 10 -#define MFEMUL_INTREG_REST 11 -#define MFEMUL_HALTED 12 - -#define AC_DATA_READ 0 -#define AC_DATA_WRITE 1 -#define AC_DATA_INC 2 -#define AC_DATA_DEC_TRANS_REST 3 -#define AC_KEYA_READ 0 -#define AC_KEYA_WRITE 1 -#define AC_KEYB_READ 2 -#define AC_KEYB_WRITE 3 -#define AC_AC_READ 4 -#define AC_AC_WRITE 5 - -#define AUTHKEYA 0 -#define AUTHKEYB 1 -#define AUTHKEYNONE 0xff - - -static int ParamCardSizeBlocks(const char c) { - int numBlocks = 16 * 4; - switch (c) { - case '0' : numBlocks = 5 * 4; break; - case '2' : numBlocks = 32 * 4; break; - case '4' : numBlocks = 32 * 4 + 8 * 16; break; - default: numBlocks = 16 * 4; - } - return numBlocks; -} - -static uint8_t BlockToSector(int block_num) { - if (block_num < 32 * 4) { // 4 blocks per sector - return (block_num / 4); - } else { // 16 blocks per sector - return 32 + (block_num - 32 * 4) / 16; - } -} - -static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { - uint8_t sector_trailer[16]; - emlGetMem(sector_trailer, blockNo, 1); - uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) - | ((sector_trailer[8] >> 2) & 0x02) - | ((sector_trailer[8] >> 7) & 0x01); - switch (action) { - case AC_KEYA_READ: { - return false; - break; - } - case AC_KEYA_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); - break; - } - case AC_KEYB_READ: { - return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01)); - break; - } - case AC_KEYB_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); - break; - } - case AC_AC_READ: { - return ((keytype == AUTHKEYA) - || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); - break; - } - case AC_AC_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); - break; - } - default: return false; - } -} - - -static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) -{ - uint8_t sector_trailer[16]; - emlGetMem(sector_trailer, SectorTrailer(blockNo), 1); - - uint8_t sector_block; - if (blockNo < 32*4) { - sector_block = blockNo & 0x03; - } else { - sector_block = (blockNo & 0x0f) / 5; - } - - uint8_t AC; - switch (sector_block) { - case 0x00: { - AC = ((sector_trailer[7] >> 2) & 0x04) - | ((sector_trailer[8] << 1) & 0x02) - | ((sector_trailer[8] >> 4) & 0x01); - break; - } - case 0x01: { - AC = ((sector_trailer[7] >> 3) & 0x04) - | ((sector_trailer[8] >> 0) & 0x02) - | ((sector_trailer[8] >> 5) & 0x01); - break; - } - case 0x02: { - AC = ((sector_trailer[7] >> 4) & 0x04) - | ((sector_trailer[8] >> 1) & 0x02) - | ((sector_trailer[8] >> 6) & 0x01); - break; - } - default: - return false; - } - - switch (action) { - case AC_DATA_READ: { - return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) - || (keytype == AUTHKEYB && !(AC == 0x07))); - break; - } - case AC_DATA_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); - break; - } - case AC_DATA_INC: { - return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); - break; - } - case AC_DATA_DEC_TRANS_REST: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); - break; - } - } - - return false; -} - - -static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { - if (IsSectorTrailer(blockNo)) { - return IsTrailerAccessAllowed(blockNo, keytype, action); - } else { - return IsDataAccessAllowed(blockNo, keytype, action); - } -} - - -static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t cardsize) { - - #define TAG_RESPONSE_COUNT 5 // number of precompiled responses - static uint8_t rATQA[] = {0x00, 0x00}; - static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level - static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level - static uint8_t rSAKfinal[]= {0x00, 0x00, 0x00}; // SAK after UID complete - static uint8_t rSAK1[] = {0x00, 0x00, 0x00}; // indicate UID not finished - - *uid_len = 4; - // UID can be set from emulator memory or incoming data and can be 4 or 7 bytes long - if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain - memcpy(rUIDBCC1, datain, 4); - } else if (flags & FLAG_7B_UID_IN_DATA) { - rUIDBCC1[0] = 0x88; - memcpy(rUIDBCC1+1, datain, 3); - memcpy(rUIDBCC2, datain+3, 4); - *uid_len = 7; - } else { - uint8_t probable_atqa; - emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length - if (probable_atqa == 0x00) { // ---------- 4BUID - emlGetMemBt(rUIDBCC1, 0, 4); - } else { // ---------- 7BUID - rUIDBCC1[0] = 0x88; - emlGetMemBt(rUIDBCC1+1, 0, 3); - emlGetMemBt(rUIDBCC2, 3, 4); - *uid_len = 7; - } - } - - switch (*uid_len) { - case 4: - *cuid = bytes_to_num(rUIDBCC1, 4); - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (MF_DBGLEVEL >= MF_DBG_INFO) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] ); - } - break; - case 7: - *cuid = bytes_to_num(rUIDBCC2, 4); - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - if (MF_DBGLEVEL >= MF_DBG_INFO) { - Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", - rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3] ); - } - break; - default: - break; - } - - // set SAK based on cardsize - switch (cardsize) { - case '0': rSAKfinal[0] = 0x09; break; // Mifare Mini - case '2': rSAKfinal[0] = 0x10; break; // Mifare 2K - case '4': rSAKfinal[0] = 0x18; break; // Mifare 4K - default: rSAKfinal[0] = 0x08; // Mifare 1K - } - ComputeCrc14443(CRC_14443_A, rSAKfinal, 1, rSAKfinal + 1, rSAKfinal + 2); - if (MF_DBGLEVEL >= MF_DBG_INFO) { - Dbprintf("SAK: %02x", rSAKfinal[0]); - } - - // set SAK for incomplete UID - rSAK1[0] = 0x04; // Bit 3 indicates incomplete UID - ComputeCrc14443(CRC_14443_A, rSAK1, 1, rSAK1 + 1, rSAK1 + 2); - - // set ATQA based on cardsize and UIDlen - if (cardsize == '4') { - rATQA[0] = 0x02; - } else { - rATQA[0] = 0x04; - } - if (*uid_len == 7) { - rATQA[0] |= 0x40; - } - if (MF_DBGLEVEL >= MF_DBG_INFO) { - Dbprintf("ATQA: %02x %02x", rATQA[1], rATQA[0]); - } - - static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { - { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type - { .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid - { .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid - { .response = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade - { .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades - }; - - // Prepare ("precompile") the responses of the anticollision phase. There will be not enough time to do this at the moment the reader sends its REQA or SELECT - // There are 5 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) - // 18 * 8 data bits, 18 * 1 parity bits, 5 start bits, 5 stop bits, 5 correction bits -> need 177 bytes buffer - #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses - - uint8_t *free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); - size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; - for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) { - prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size); - } - - *responses = responses_init; - - // indices into responses array: - #define ATQA 0 - #define UIDBCC1 1 - #define UIDBCC2 2 - #define SAKfinal 3 - #define SAK1 4 - -} - - -static bool HasValidCRC(uint8_t *receivedCmd, uint16_t receivedCmd_len) { - uint8_t CRC_byte_1, CRC_byte_2; - ComputeCrc14443(CRC_14443_A, receivedCmd, receivedCmd_len-2, &CRC_byte_1, &CRC_byte_2); - return (receivedCmd[receivedCmd_len-2] == CRC_byte_1 && receivedCmd[receivedCmd_len-1] == CRC_byte_2); -} - - -/** - *MIFARE simulate. - * - *@param flags : - * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK - * FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that - * FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that - * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later - * FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack) - *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... - * (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) - */ -void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain) -{ - LED_A_ON(); - - tag_response_info_t *responses; - uint8_t uid_len = 4; - uint32_t cuid = 0; - uint8_t cardWRBL = 0; - uint8_t cardAUTHSC = 0; - uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication - uint32_t cardRr = 0; - //uint32_t rn_enc = 0; - uint32_t ans = 0; - uint32_t cardINTREG = 0; - uint8_t cardINTBLOCK = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs = &mpcs; - uint32_t numReads = 0; //Counts numer of times reader reads a block - uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE]; - uint16_t receivedCmd_len; - uint8_t response[MAX_MIFARE_FRAME_SIZE]; - uint8_t response_par[MAX_MIFARE_PARITY_SIZE]; - uint8_t fixed_nonce[] = {0x01, 0x02, 0x03, 0x04}; - - int num_blocks = ParamCardSizeBlocks(cardsize); - - // Here we collect UID, sector, keytype, NT, AR, NR, NT2, AR2, NR2 - // This will be used in the reader-only attack. - - // allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys - #define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7) - nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes - memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - - uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; // *2 for 2nd attack type (moebius) - memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - uint8_t nonce1_count = 0; - uint8_t nonce2_count = 0; - uint8_t moebius_n_count = 0; - bool gettingMoebius = false; - uint8_t mM = 0; // moebius_modifier for collection storage - - // Authenticate response - nonce - uint32_t nonce; - if (flags & FLAG_RANDOM_NONCE) { - nonce = prand(); - } else { - nonce = bytes_to_num(fixed_nonce, 4); - } - - // free eventually allocated BigBuf memory but keep Emulator Memory - BigBuf_free_keep_EM(); - - MifareSimInit(flags, datain, &responses, &cuid, &uid_len, cardsize); - - // We need to listen to the high-frequency, peak-detected path. - iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); - - // clear trace - clear_trace(); - set_tracing(true); - ResetSspClk(); - - bool finished = false; - bool button_pushed = BUTTON_PRESS(); - int cardSTATE = MFEMUL_NOFIELD; - - while (!button_pushed && !finished && !usb_poll_validate_length()) { - WDT_HIT(); - - if (cardSTATE == MFEMUL_NOFIELD) { - // wait for reader HF field - int vHf = (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10; - if (vHf > MF_MINFIELDV) { - LED_D_ON(); - cardSTATE = MFEMUL_IDLE; - } - button_pushed = BUTTON_PRESS(); - continue; - } - - //Now, get data - FpgaEnableTracing(); - int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); - - if (res == 2) { // Reader has dropped the HF field. Power off. - FpgaDisableTracing(); - LED_D_OFF(); - cardSTATE = MFEMUL_NOFIELD; - continue; - } else if (res == 1) { // button pressed - FpgaDisableTracing(); - button_pushed = true; - break; - } - - // WUPA in HALTED state or REQA or WUPA in any other state - if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { - EmSendPrecompiledCmd(&responses[ATQA]); - FpgaDisableTracing(); - - // init crypto block - crypto1_destroy(pcs); - cardAUTHKEY = AUTHKEYNONE; - if (flags & FLAG_RANDOM_NONCE) { - nonce = prand(); - } - cardSTATE = MFEMUL_SELECT1; - continue; - } - - switch (cardSTATE) { - case MFEMUL_NOFIELD: - case MFEMUL_HALTED: - case MFEMUL_IDLE:{ - break; - } - - case MFEMUL_SELECT1:{ - // select all - 0x93 0x20 - if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { - EmSendPrecompiledCmd(&responses[UIDBCC1]); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL1 received"); - break; - } - // select card - 0x93 0x70 ... - if (receivedCmd_len == 9 && - (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC1].response, 4) == 0)) { - if (uid_len == 4) { - EmSendPrecompiledCmd(&responses[SAKfinal]); - cardSTATE = MFEMUL_WORK; - } else if (uid_len == 7) { - EmSendPrecompiledCmd(&responses[SAK1]); - cardSTATE = MFEMUL_SELECT2; - } - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); - break; - } - cardSTATE = MFEMUL_IDLE; - break; - } - - case MFEMUL_SELECT2:{ - // select all cl2 - 0x95 0x20 - if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { - EmSendPrecompiledCmd(&responses[UIDBCC2]); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL2 received"); - break; - } - // select cl2 card - 0x95 0x70 xxxxxxxxxxxx - if (receivedCmd_len == 9 && - (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) { - if (uid_len == 7) { - EmSendPrecompiledCmd(&responses[SAKfinal]); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); - cardSTATE = MFEMUL_WORK; - break; - } - } - cardSTATE = MFEMUL_IDLE; - break; - } - - case MFEMUL_WORK:{ - if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes - break; - } - bool encrypted_data = (cardAUTHKEY != AUTHKEYNONE) ; - if (encrypted_data) { - // decrypt seqence - mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); - } else { - memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len); - } - if (!HasValidCRC(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_TR)); - break; - } - - if (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB) { - // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack - if (receivedCmd_dec[1] >= num_blocks && !(flags & FLAG_NR_AR_ATTACK)) { - //is this the correct response to an auth on a out of range block? marshmellow - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]); - break; - } - cardAUTHSC = BlockToSector(receivedCmd_dec[1]); // received block num - cardAUTHKEY = receivedCmd_dec[0] & 0x01; - crypto1_destroy(pcs);//Added by martin - crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); - if (!encrypted_data) { // first authentication - crypto1_word(pcs, cuid ^ nonce, 0); // Update crypto state - num_to_bytes(nonce, 4, response); // Send unencrypted nonce - EmSendCmd(response, sizeof(nonce)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - } else { // nested authentication - num_to_bytes(nonce, sizeof(nonce), response); - uint8_t pcs_in[4] = {0}; - num_to_bytes(cuid ^ nonce, sizeof(nonce), pcs_in); - mf_crypto1_encryptEx(pcs, response, pcs_in, sizeof(nonce), response_par); - EmSendCmdPar(response, sizeof(nonce), response_par); // send encrypted nonce - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - } - cardSTATE = MFEMUL_AUTH1; - break; - } - - // halt can be sent encrypted or in clear - if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("--> HALTED."); - cardSTATE = MFEMUL_HALTED; - break; - } - - if(receivedCmd_dec[0] == MIFARE_CMD_READBLOCK - || receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK - || receivedCmd_dec[0] == MIFARE_CMD_INC - || receivedCmd_dec[0] == MIFARE_CMD_DEC - || receivedCmd_dec[0] == MIFARE_CMD_RESTORE - || receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { - if (receivedCmd_dec[1] >= num_blocks) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); - break; - } - if (BlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC); - break; - } - } - - if (receivedCmd_dec[0] == MIFARE_CMD_READBLOCK) { - uint8_t blockNo = receivedCmd_dec[1]; - emlGetMem(response, blockNo, 1); - if (IsSectorTrailer(blockNo)) { - memset(response, 0x00, 6); // keyA can never be read - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) { - memset(response+10, 0x00, 6); // keyB cannot be read - } - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) { - memset(response+6, 0x00, 4); // AC bits cannot be read - } - } else { - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) { - memset(response, 0x00, 16); // datablock cannot be read - } - } - AppendCrc14443a(response, 16); - mf_crypto1_encrypt(pcs, response, 18, response_par); - EmSendCmdPar(response, 18, response_par); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo); - } - numReads++; - if(exitAfterNReads > 0 && numReads == exitAfterNReads) { - Dbprintf("%d reads done, exiting", numReads); - finished = true; - } - break; - } - - if (receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK) { - uint8_t blockNo = receivedCmd_dec[1]; - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo); - cardWRBL = blockNo; - cardSTATE = MFEMUL_WRITEBL2; - break; - } - - if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) { - uint8_t blockNo = receivedCmd_dec[1]; - if (emlCheckValBl(blockNo)) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); - } - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); - break; - } - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); - } - cardWRBL = blockNo; - if (receivedCmd_dec[0] == MIFARE_CMD_INC) - cardSTATE = MFEMUL_INTREG_INC; - if (receivedCmd_dec[0] == MIFARE_CMD_DEC) - cardSTATE = MFEMUL_INTREG_DEC; - if (receivedCmd_dec[0] == MIFARE_CMD_RESTORE) - cardSTATE = MFEMUL_INTREG_REST; - break; - } - - if (receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { - uint8_t blockNo = receivedCmd_dec[1]; - if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1])) - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - else - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); - break; - } - - // command not allowed - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Received command not allowed, nacking"); - cardSTATE = MFEMUL_IDLE; - break; - } - - case MFEMUL_AUTH1:{ - if (receivedCmd_len != 8) { - cardSTATE = MFEMUL_IDLE; - break; - } - - uint32_t nr = bytes_to_num(receivedCmd, 4); - uint32_t ar = bytes_to_num(&receivedCmd[4], 4); - - // Collect AR/NR per keytype & sector - if(flags & FLAG_NR_AR_ATTACK) { - for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) { - // if first auth for sector, or matches sector and keytype of previous auth - if (ar_nr_collected[i+mM] < 2) { - // if we haven't already collected 2 nonces for this sector - if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { - // Avoid duplicates... probably not necessary, ar should vary. - if (ar_nr_collected[i+mM]==0) { - // first nonce collect - ar_nr_resp[i+mM].cuid = cuid; - ar_nr_resp[i+mM].sector = cardAUTHSC; - ar_nr_resp[i+mM].keytype = cardAUTHKEY; - ar_nr_resp[i+mM].nonce = nonce; - ar_nr_resp[i+mM].nr = nr; - ar_nr_resp[i+mM].ar = ar; - nonce1_count++; - // add this nonce to first moebius nonce - ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid; - ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC; - ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY; - ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce; - ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr; - ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar; - ar_nr_collected[i+ATTACK_KEY_COUNT]++; - } else { // second nonce collect (std and moebius) - ar_nr_resp[i+mM].nonce2 = nonce; - ar_nr_resp[i+mM].nr2 = nr; - ar_nr_resp[i+mM].ar2 = ar; - if (!gettingMoebius) { - nonce2_count++; - // check if this was the last second nonce we need for std attack - if ( nonce2_count == nonce1_count ) { - // done collecting std test switch to moebius - // first finish incrementing last sample - ar_nr_collected[i+mM]++; - // switch to moebius collection - gettingMoebius = true; - mM = ATTACK_KEY_COUNT; - if (flags & FLAG_RANDOM_NONCE) { - nonce = prand(); - } else { - nonce = nonce*7; - } - break; - } - } else { - moebius_n_count++; - // if we've collected all the nonces we need - finish. - if (nonce1_count == moebius_n_count) finished = true; - } - } - ar_nr_collected[i+mM]++; - } - } - // we found right spot for this nonce stop looking - break; - } - } - } - - // --- crypto - crypto1_word(pcs, nr , 1); - cardRr = ar ^ crypto1_word(pcs, 0, 0); - - // test if auth OK - if (cardRr != prng_successor(nonce, 64)){ - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", - cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B', - cardRr, prng_successor(nonce, 64)); - // Shouldn't we respond anything here? - // Right now, we don't nack or anything, which causes the - // reader to do a WUPA after a while. /Martin - // -- which is the correct response. /piwi - cardAUTHKEY = AUTHKEYNONE; // not authenticated - cardSTATE = MFEMUL_IDLE; - break; - } - ans = prng_successor(nonce, 96); - num_to_bytes(ans, 4, response); - mf_crypto1_encrypt(pcs, response, 4, response_par); - EmSendCmdPar(response, 4, response_par); - FpgaDisableTracing(); - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); - cardSTATE = MFEMUL_WORK; - break; - } - - case MFEMUL_WRITEBL2:{ - if (receivedCmd_len == 18) { - mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); - if (HasValidCRC(receivedCmd_dec, receivedCmd_len)) { - if (IsSectorTrailer(cardWRBL)) { - emlGetMem(response, cardWRBL, 1); - if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE)) { - memcpy(receivedCmd_dec, response, 6); // don't change KeyA - } - if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE)) { - memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA - } - if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE)) { - memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits - } - } else { - if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE)) { - memcpy(receivedCmd_dec, response, 16); // don't change anything - } - } - emlSetMem(receivedCmd_dec, cardWRBL, 1); - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? - cardSTATE = MFEMUL_WORK; - break; - } - } - cardSTATE = MFEMUL_IDLE; - break; - } - - case MFEMUL_INTREG_INC:{ - if (receivedCmd_len == 6) { - mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); - if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE = MFEMUL_IDLE; - break; - } - cardINTREG = cardINTREG + ans; - cardSTATE = MFEMUL_WORK; - } - break; - } - - case MFEMUL_INTREG_DEC:{ - if (receivedCmd_len == 6) { - mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); - if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE = MFEMUL_IDLE; - break; - } - cardINTREG = cardINTREG - ans; - cardSTATE = MFEMUL_WORK; - } - break; - } - - case MFEMUL_INTREG_REST:{ - mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); - if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE = MFEMUL_IDLE; - break; - } - cardSTATE = MFEMUL_WORK; - break; - } - - } // end of switch - - FpgaDisableTracing(); - button_pushed = BUTTON_PRESS(); - - } // end of while - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - - if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= MF_DBG_INFO) { - for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { - if (ar_nr_collected[i] == 2) { - Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= MF_DBG_INFO) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); - - if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK - //Send the collected ar_nr in the response - cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); - } - - LED_A_OFF(); -} diff --git a/armsrc/mifaresim.h b/armsrc/mifaresim.h deleted file mode 100644 index 8f089b85..00000000 --- a/armsrc/mifaresim.h +++ /dev/null @@ -1,20 +0,0 @@ -//----------------------------------------------------------------------------- -// Merlok - June 2011, 2012 -// Gerhard de Koning Gans - May 2008 -// Hagen Fritsch - June 2010 -// -// 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. -//----------------------------------------------------------------------------- -// Mifare Classic Card Simulation -//----------------------------------------------------------------------------- - -#ifndef __MIFARESIM_H -#define __MIFARESIM_H - -#include - -extern void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain); - -#endif diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index f3ee4a3f..3e5570f9 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -1,169 +1,173 @@ -//----------------------------------------------------------------------------- -// Merlok - 2012 -// -// 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. -//----------------------------------------------------------------------------- -// Routines to support mifare classic sniffer. -//----------------------------------------------------------------------------- - -#include "mifaresniff.h" - -#include "proxmark3.h" -#include "util.h" -#include "string.h" -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" -#include "usb_cdc.h" -#include "BigBuf.h" -#include "fpgaloader.h" - - -static int sniffState = SNF_INIT; -static uint8_t sniffUIDType; -static uint8_t sniffUID[8] = {0x00}; -static uint8_t sniffATQA[2] = {0x00}; -static uint8_t sniffSAK; -static uint8_t sniffBuf[16] = {0x00}; -static uint32_t timerData = 0; - - -bool MfSniffInit(void){ - memset(sniffUID, 0x00, 8); - memset(sniffATQA, 0x00, 2); - sniffSAK = 0; - sniffUIDType = SNF_UID_4; - - return false; -} - -bool MfSniffEnd(void){ - LED_B_ON(); - cmd_send(CMD_ACK,0,0,0,0,0); - LED_B_OFF(); - - return false; -} - -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) { - - if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader - sniffState = SNF_INIT; - } - - switch (sniffState) { - case SNF_INIT:{ - if ((len == 1) && (reader) && (bitCnt == 7) ) { // REQA or WUPA from reader - sniffUIDType = SNF_UID_4; - memset(sniffUID, 0x00, 8); - memset(sniffATQA, 0x00, 2); - sniffSAK = 0; - sniffState = SNF_ATQA; - if (data[0] == 0x40) - sniffState = SNF_MAGIC_WUPC2; - } - break; - } - case SNF_MAGIC_WUPC2: - if ((len == 1) && (reader) && (data[0] == 0x43) ) { - sniffState = SNF_CARD_IDLE; - } - break; - case SNF_ATQA:{ - if ((!reader) && (len == 2)) { // ATQA from tag - memcpy(sniffATQA, data, 2); - sniffState = SNF_UID1; - } - break; - } +//----------------------------------------------------------------------------- +// Merlok - 2012 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support mifare classic sniffer. +//----------------------------------------------------------------------------- + +#include "mifaresniff.h" +#include "apps.h" + +static int sniffState = SNF_INIT; +static uint8_t sniffUIDType; +static uint8_t sniffUID[8]; +static uint8_t sniffATQA[2]; +static uint8_t sniffSAK; +static uint8_t sniffBuf[16]; +static uint32_t timerData = 0; + + +bool MfSniffInit(void){ + memset(sniffUID, 0x00, 8); + memset(sniffATQA, 0x00, 2); + sniffSAK = 0; + sniffUIDType = SNF_UID_4; + + return FALSE; +} + +bool MfSniffEnd(void){ + LED_B_ON(); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_B_OFF(); + + return FALSE; +} + +bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader) { + + if (reader && (len == 1) && (bitCnt == 7)) { // reset on 7-Bit commands from reader + sniffState = SNF_INIT; + } + + switch (sniffState) { + case SNF_INIT:{ + if ((len == 1) && (reader) && (bitCnt == 7) ) { // REQA or WUPA from reader + sniffUIDType = SNF_UID_4; + memset(sniffUID, 0x00, 8); + memset(sniffATQA, 0x00, 2); + sniffSAK = 0; + sniffState = SNF_WUPREQ; + } + break; + } + case SNF_WUPREQ:{ + if ((!reader) && (len == 2)) { // ATQA from tag + memcpy(sniffATQA, data, 2); + sniffState = SNF_ATQA; + } + break; + } + case SNF_ATQA:{ + if ((reader) && (len == 2) && (data[0] == 0x93) && (data[1] == 0x20)) { // Select ALL from reader + sniffState = SNF_ANTICOL1; + } + break; + } + case SNF_ANTICOL1:{ + if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // UID from tag (CL1) + memcpy(sniffUID + 3, data, 4); + sniffState = SNF_UID1; + } + break; + } case SNF_UID1:{ if ((reader) && (len == 9) && (data[0] == 0x93) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 4 Byte UID from reader - memcpy(sniffUID + 3, &data[2], 4); - sniffState = SNF_SAK; - } - break; - } - case SNF_SAK:{ - if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card? - sniffSAK = data[0]; - if ((sniffUID[3] == 0x88) && (sniffUIDType == SNF_UID_4)) { // CL2 UID part to be expected - sniffUIDType = SNF_UID_7; - memcpy(sniffUID, sniffUID + 4, 3); - sniffState = SNF_UID2; - } else { // select completed - sniffState = SNF_CARD_IDLE; - } - } - break; - } - case SNF_UID2:{ - if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { - memcpy(sniffUID + 3, &data[2], 4); sniffState = SNF_SAK; } break; } - case SNF_CARD_IDLE:{ // trace the card select sequence - sniffBuf[0] = 0xFF; - sniffBuf[1] = 0xFF; - memcpy(sniffBuf + 2, sniffUID, 7); - memcpy(sniffBuf + 9, sniffATQA, 2); - sniffBuf[11] = sniffSAK; - sniffBuf[12] = 0xFF; - sniffBuf[13] = 0xFF; - LogTrace(sniffBuf, 14, 0, 0, NULL, true); - sniffState = SNF_CARD_CMD; - } // intentionally no break; - case SNF_CARD_CMD:{ - LogTrace(data, len, 0, 0, parity, reader); - timerData = GetTickCount(); - break; - } - - default: - sniffState = SNF_INIT; - break; - } - - - return false; -} - -bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) { - if (BigBuf_get_traceLen() && (GetTickCount() > timerData + maxTimeoutMs)) { - return intMfSniffSend(); - } - return false; -} - -// internal sending function. not a RAMFUNC. -bool intMfSniffSend() { - - int pckSize = 0; - int pckLen = BigBuf_get_traceLen(); - int pckNum = 0; - uint8_t *trace = BigBuf_get_addr(); - - FpgaDisableSscDma(); - while (pckLen > 0) { - pckSize = MIN(USB_CMD_DATA_SIZE, pckLen); - LED_B_ON(); - cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize); - LED_B_OFF(); - - pckLen -= pckSize; - pckNum++; - } - - LED_B_ON(); - cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,2,0,0,0,0); - LED_B_OFF(); - - clear_trace(); - - return true; -} + case SNF_SAK:{ + if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card? + sniffSAK = data[0]; + if (sniffUID[3] == 0x88) { // CL2 UID part to be expected + sniffState = SNF_ANTICOL2; + } else { // select completed + sniffState = SNF_CARD_IDLE; + } + } + break; + } + case SNF_ANTICOL2:{ + if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // CL2 UID + memcpy(sniffUID, sniffUID+4, 3); + memcpy(sniffUID+3, data, 4); + sniffUIDType = SNF_UID_7; + sniffState = SNF_UID2; + } + break; + } + case SNF_UID2:{ + if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 2nd part of 7 Byte UID + sniffState = SNF_SAK; + } + break; + } + case SNF_CARD_IDLE:{ // trace the card select sequence + sniffBuf[0] = 0xFF; + sniffBuf[1] = 0xFF; + memcpy(sniffBuf + 2, sniffUID, 7); + memcpy(sniffBuf + 9, sniffATQA, 2); + sniffBuf[11] = sniffSAK; + sniffBuf[12] = 0xFF; + sniffBuf[13] = 0xFF; + LogTrace(sniffBuf, 14, 0, parity, true); + } // intentionally no break; + case SNF_CARD_CMD:{ + LogTrace(data, len, 0, parity, true); + sniffState = SNF_CARD_RESP; + timerData = GetTickCount(); + break; + } + case SNF_CARD_RESP:{ + LogTrace(data, len, 0, parity, false); + sniffState = SNF_CARD_CMD; + timerData = GetTickCount(); + break; + } + + default: + sniffState = SNF_INIT; + break; + } + + + return FALSE; +} + +bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) { + if (traceLen && (GetTickCount() > timerData + maxTimeoutMs)) { + return intMfSniffSend(); + } + return FALSE; +} + +// internal sending function. not a RAMFUNC. +bool intMfSniffSend() { + + int pckSize = 0; + int pckLen = traceLen; + int pckNum = 0; + + FpgaDisableSscDma(); + while (pckLen > 0) { + pckSize = MIN(USB_CMD_DATA_SIZE, pckLen); + LED_B_ON(); + cmd_send(CMD_ACK, 1, pckSize, pckNum, trace + traceLen - pckLen, pckSize); + LED_B_OFF(); + + pckLen -= pckSize; + pckNum++; + } + + LED_B_ON(); + cmd_send(CMD_ACK,2,0,0,0,0); + LED_B_OFF(); + + iso14a_clear_trace(); + + return TRUE; +} diff --git a/armsrc/mifaresniff.h b/armsrc/mifaresniff.h index b181f982..1065fa61 100644 --- a/armsrc/mifaresniff.h +++ b/armsrc/mifaresniff.h @@ -11,31 +11,37 @@ #ifndef __MIFARESNIFF_H #define __MIFARESNIFF_H -#include -#include +#include "proxmark3.h" +#include "apps.h" #include "util.h" +#include "string.h" + +#include "iso14443crc.h" +#include "iso14443a.h" +#include "crapto1.h" +#include "mifareutil.h" +#include "common.h" #define SNF_INIT 0 -#define SNF_NO_FIELD 1 -#define SNF_WUPREQ 2 +#define SNF_NO_FIELD 1 +#define SNF_WUPREQ 2 #define SNF_ATQA 3 -#define SNF_ANTICOL1 4 +#define SNF_ANTICOL1 4 #define SNF_UID1 5 -#define SNF_ANTICOL2 6 +#define SNF_ANTICOL2 6 #define SNF_UID2 7 #define SNF_SAK 8 -#define SNF_CARD_IDLE 9 -#define SNF_CARD_CMD 10 -#define SNF_CARD_RESP 11 -#define SNF_MAGIC_WUPC2 12 +#define SNF_CARD_IDLE 9 +#define SNF_CARD_CMD 10 +#define SNF_CARD_RESP 11 #define SNF_UID_4 0 #define SNF_UID_7 0 bool MfSniffInit(void); -bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader); +bool RAMFUNC MfSniffLogic(const uint8_t * data, uint16_t len, uint32_t parity, uint16_t bitCnt, bool reader); bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs); bool intMfSniffSend(); bool MfSniffEnd(void); -#endif +#endif \ No newline at end of file diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index e46c5515..b847043b 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -9,125 +9,142 @@ // Work with mifare cards. //----------------------------------------------------------------------------- -#include "mifareutil.h" - -#include -#include - #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "parity.h" +#include "string.h" + #include "iso14443crc.h" #include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mbedtls/des.h" -#include "protocols.h" +#include "crapto1.h" +#include "mifareutil.h" -int MF_DBGLEVEL = MF_DBG_INFO; +int MF_DBGLEVEL = MF_DBG_ALL; + +// memory management +uint8_t* mifare_get_bigbufptr(void) { + return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET); // was 3560 - tied to other size changes +} +uint8_t* eml_get_bigbufptr_sendbuf(void) { + return (((uint8_t *)BigBuf) + RECV_CMD_OFFSET); +} +uint8_t* eml_get_bigbufptr_recbuf(void) { + return (((uint8_t *)BigBuf) + MIFARE_BUFF_OFFSET); +} +uint8_t* eml_get_bigbufptr_cardmem(void) { + return (((uint8_t *)BigBuf) + CARD_MEMORY); +} // crypto1 helpers -void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){ - uint8_t bt = 0; +void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){ + uint8_t bt = 0; int i; - + if (len != 1) { for (i = 0; i < len; i++) - data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i]; + data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; } else { bt = 0; for (i = 0; i < 4; i++) - bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], i)) << i; - - data_out[0] = bt; + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data[0], i)) << i; + + data[0] = bt; } return; } -void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){ - mf_crypto1_decryptEx(pcs, data, len, data); -} - -void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par) { +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par) { uint8_t bt = 0; int i; - par[0] = 0; - + uint32_t mltpl = 1 << (len - 1); // for len=18 it=0x20000 + *par = 0; for (i = 0; i < len; i++) { bt = data[i]; - data[i] = crypto1_byte(pcs, in==NULL?0x00:in[i], 0) ^ data[i]; - if((i&0x0007) == 0) - par[i>>3] = 0; - par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); - } + data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; + *par = (*par >> 1) | ( ((filter(pcs->odd) ^ oddparity(bt)) & 0x01) * mltpl ); + } return; } -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { - mf_crypto1_encryptEx(pcs, data, NULL, len, par); -} - uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { uint8_t bt = 0; int i; for (i = 0; i < 4; i++) bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, i)) << i; - + return bt; } -// send X byte basic commands -int mifare_sendcmd(uint8_t cmd, uint8_t* data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[data_size+3]; - dcmd[0] = cmd; - memcpy(dcmd+1,data,data_size); - AppendCrc14443a(dcmd, data_size+1); - ReaderTransmit(dcmd, sizeof(dcmd), timing); - int len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("%02X Cmd failed. Card timeout.", cmd); - len = ReaderReceive(answer,answer_parity); - //return 0; - } - return len; -} +// send commands +int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing) +{ + return mifare_sendcmd_shortex(pcs, crypted, cmd, data, answer, NULL, timing); +} + +int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *timing) +{ + uint8_t dcmd[8];//, ecmd[4]; + //uint32_t par=0; + + dcmd[0] = cmd; + dcmd[1] = data[0]; + dcmd[2] = data[1]; + dcmd[3] = data[2]; + dcmd[4] = data[3]; + dcmd[5] = data[4]; + AppendCrc14443a(dcmd, 6); + //Dbprintf("Data command: %02x", dcmd[0]); + //Dbprintf("Data R: %02x %02x %02x %02x %02x %02x %02x", dcmd[1],dcmd[2],dcmd[3],dcmd[4],dcmd[5],dcmd[6],dcmd[7]); + + //memcpy(ecmd, dcmd, sizeof(dcmd)); + ReaderTransmit(dcmd, sizeof(dcmd), NULL); + int len = ReaderReceive(answer); + if(!len) + { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + return 2; + } + return len; +} + +int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing) +{ + uint8_t dcmd[4], ecmd[4]; + uint32_t pos, par, res; -// send 2 byte commands -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[4], ecmd[4]; - uint16_t pos, res; - uint8_t par[1]; // 1 Byte parity is enough here dcmd[0] = cmd; dcmd[1] = data; AppendCrc14443a(dcmd, 2); - + memcpy(ecmd, dcmd, sizeof(dcmd)); - + if (crypted) { - par[0] = 0; + par = 0; for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos)); - } + par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(dcmd[pos])) & 0x01) * 0x08 ); + } + ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); + } else { ReaderTransmit(dcmd, sizeof(dcmd), timing); } - int len = ReaderReceive(answer, par); - - if (answer_parity) *answer_parity = par[0]; + int len = ReaderReceivePar(answer, &par); + + if (parptr) *parptr = par; if (crypted == CRYPT_ALL) { if (len == 1) { res = 0; for (pos = 0; pos < 4; pos++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], pos)) << pos; - + answer[0] = res; - + } else { for (pos = 0; pos < len; pos++) { @@ -135,41 +152,39 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, } } } - + return len; } - -// mifare classic commands -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *auth_timeout) { - - return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL, auth_timeout); +// mifare commands +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested) +{ + return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } - -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, uint32_t *auth_timeout) { - - int len; +int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing) +{ + // variables + int len; uint32_t pos; - uint8_t par[1] = {0x00}; - byte_t nr[4]; + uint8_t tmp4[4]; + byte_t par = 0; + byte_t ar[4]; uint32_t nt, ntpp; // Supplied tag nonce - + uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); // Transmit MIFARE_CLASSIC_AUTH - len = mifare_sendcmd_short(pcs, isNested, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, timing); - if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); + len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, timing); + if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len); if (len != 4) return 1; - - // "random" reader nonce: - nr[0] = 0x55; - nr[1] = 0x41; - nr[2] = 0x49; - nr[3] = 0x92; - + + ar[0] = 0x55; + ar[1] = 0x41; + ar[2] = 0x49; + ar[3] = 0x92; + // Save the tag nonce (nt) nt = bytes_to_num(receivedAnswer, 4); @@ -181,7 +196,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN crypto1_create(pcs, ui64Key); if (isNested == AUTH_NESTED) { - // decrypt nt with help of new key + // decrypt nt with help of new key nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; } else { // Load (plain) uid^nt into the cipher @@ -190,458 +205,275 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN // some statistic if (!ntptr && (MF_DBGLEVEL >= 3)) - Dbprintf("auth uid: %08x nt: %08x", uid, nt); - + Dbprintf("auth uid: %08x nt: %08x", uid, nt); + // save Nt if (ntptr) *ntptr = nt; + par = 0; // Generate (encrypted) nr+parity by loading it into the cipher (Nr) - par[0] = 0; - for (pos = 0; pos < 4; pos++) { - mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; - par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7-pos)); - } - + for (pos = 0; pos < 4; pos++) + { + mf_nr_ar[pos] = crypto1_byte(pcs, ar[pos], 0) ^ ar[pos]; + par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(ar[pos])) & 0x01) * 0x80 ); + } + // Skip 32 bits in pseudo random generator nt = prng_successor(nt,32); // ar+parity - for (pos = 4; pos < 8; pos++) { + for (pos = 4; pos < 8; pos++) + { nt = prng_successor(nt,8); - mf_nr_ar[pos] = crypto1_byte(pcs, 0x00, 0) ^ (nt & 0xff); - par[0] |= (((filter(pcs->odd) ^ oddparity8(nt)) & 0x01) << (7-pos)); - } - + mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); + par = (par >> 1)| ( ((filter(pcs->odd) ^ oddparity(nt & 0xff)) & 0x01) * 0x80 ); + } + // Transmit reader nonce and reader answer ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); - // Receive 4 byte tag answer - uint32_t save_timeout = iso14a_get_timeout(); // save standard timeout - if (auth_timeout && *auth_timeout) { - iso14a_set_timeout(*auth_timeout); // set timeout for authentication response - } - uint32_t auth_timeout_start = GetCountSspClk(); - len = ReaderReceive(receivedAnswer, receivedAnswerPar); - iso14a_set_timeout(save_timeout); // restore standard timeout - if (!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + // Receive 4 bit answer + len = ReaderReceive(receivedAnswer); + if (!len) + { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; } - if (auth_timeout && !*auth_timeout) { // measure time for future authentication response timeout - *auth_timeout = (GetCountSspClk() - auth_timeout_start - (len * 9 + 2) * 8) / 8 + 1; - } - - ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0); - - if (ntpp != bytes_to_num(receivedAnswer, 4)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); + + memcpy(tmp4, receivedAnswer, 4); + ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); + + if (ntpp != bytes_to_num(tmp4, 4)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); return 3; } return 0; } - -int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { +int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +{ // variables - int len; - uint8_t bt[2]; - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + int len; + uint8_t bt[2]; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, NULL); if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } if (len != 18) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); return 2; } memcpy(bt, receivedAnswer + 16, 2); AppendCrc14443a(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); return 3; } - + memcpy(blockData, receivedAnswer, 16); - return 0; -} - -// mifare ultralight commands -int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ - - uint16_t len; - uint8_t resp[4]; - uint8_t respPar[1]; - uint8_t key[4] = {0x00}; - memcpy(key, keybytes, 4); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); - len = mifare_sendcmd(MIFARE_ULEV1_AUTH, key, sizeof(key), resp, respPar, NULL); - //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); - if (len != 4) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len); - return 0; - } - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - Dbprintf("Auth Resp: %02x%02x%02x%02x", resp[0],resp[1],resp[2],resp[3]); - - memcpy(pack, resp, 4); - return 1; -} - -int mifare_ultra_auth(uint8_t *keybytes){ - - /// 3des2k - - mbedtls_des3_context ctx = { {0} }; - uint8_t random_a[8] = {1,1,1,1,1,1,1,1}; - uint8_t random_b[8] = {0x00}; - uint8_t enc_random_b[8] = {0x00}; - uint8_t rnd_ab[16] = {0x00}; - uint8_t IV[8] = {0x00}; - uint8_t key[16] = {0x00}; - memcpy(key, keybytes, 16); - - uint16_t len; - uint8_t resp[19] = {0x00}; - uint8_t respPar[3] = {0,0,0}; - - // REQUEST AUTHENTICATION - len = mifare_sendcmd_short(NULL, 1, MIFARE_ULC_AUTH_1, 0x00, resp, respPar ,NULL); - if (len != 11) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); - return 0; - } - - // tag nonce. - memcpy(enc_random_b,resp+1,8); - - // decrypt nonce. - // tdes_2key_dec(random_b, enc_random_b, sizeof(random_b), key, IV ); - mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , sizeof(random_b) // length - , IV // iv[8] - , enc_random_b // input - , random_b // output - ); - - rol(random_b,8); - memcpy(rnd_ab ,random_a,8); - memcpy(rnd_ab+8,random_b,8); - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("enc_B: %02x %02x %02x %02x %02x %02x %02x %02x", - enc_random_b[0],enc_random_b[1],enc_random_b[2],enc_random_b[3],enc_random_b[4],enc_random_b[5],enc_random_b[6],enc_random_b[7]); - - Dbprintf(" B: %02x %02x %02x %02x %02x %02x %02x %02x", - random_b[0],random_b[1],random_b[2],random_b[3],random_b[4],random_b[5],random_b[6],random_b[7]); - - Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x", - rnd_ab[0],rnd_ab[1],rnd_ab[2],rnd_ab[3],rnd_ab[4],rnd_ab[5],rnd_ab[6],rnd_ab[7]); - - Dbprintf("rnd_ab: %02x %02x %02x %02x %02x %02x %02x %02x", - rnd_ab[8],rnd_ab[9],rnd_ab[10],rnd_ab[11],rnd_ab[12],rnd_ab[13],rnd_ab[14],rnd_ab[15] ); - } - - // encrypt out, in, length, key, iv - //tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b); - mbedtls_des3_set2key_enc(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_ENCRYPT // int mode - , sizeof(rnd_ab) // length - , enc_random_b // iv[8] - , rnd_ab // input - , rnd_ab // output - ); - - //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); - len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); - if (len != 11) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); - return 0; - } - - uint8_t enc_resp[8] = { 0,0,0,0,0,0,0,0 }; - uint8_t resp_random_a[8] = { 0,0,0,0,0,0,0,0 }; - memcpy(enc_resp, resp+1, 8); - - // decrypt out, in, length, key, iv - // tdes_2key_dec(resp_random_a, enc_resp, 8, key, enc_random_b); - mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , 8 // length - , enc_random_b // iv[8] - , enc_resp // input - , resp_random_a // output - ); - if ( memcmp(resp_random_a, random_a, 8) != 0 ) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("failed authentication"); - return 0; - } - - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", - rnd_ab[0],rnd_ab[1],rnd_ab[2],rnd_ab[3], - rnd_ab[4],rnd_ab[5],rnd_ab[6],rnd_ab[7]); - - Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", - rnd_ab[8],rnd_ab[9],rnd_ab[10],rnd_ab[11], - rnd_ab[12],rnd_ab[13],rnd_ab[14],rnd_ab[15]); - - Dbprintf("a: %02x %02x %02x %02x %02x %02x %02x %02x", - random_a[0],random_a[1],random_a[2],random_a[3], - random_a[4],random_a[5],random_a[6],random_a[7]); - - Dbprintf("b: %02x %02x %02x %02x %02x %02x %02x %02x", - resp_random_a[0],resp_random_a[1],resp_random_a[2],resp_random_a[3], - resp_random_a[4],resp_random_a[5],resp_random_a[6],resp_random_a[7]); - } - return 1; -} - - -#define MFU_MAX_RETRIES 5 -int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) -{ - uint16_t len; - uint8_t bt[2]; - uint8_t receivedAnswer[MAX_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - uint8_t retries; - int result = 0; - - for (retries = 0; retries < MFU_MAX_RETRIES; retries++) { - len = mifare_sendcmd_short(NULL, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if (len == 1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - result = 1; - continue; - } - if (len != 18) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len); - result = 2; - continue; - } - - memcpy(bt, receivedAnswer + 16, 2); - AppendCrc14443a(receivedAnswer, 16); - if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd CRC response error."); - result = 3; - continue; - } - - // No errors encountered; don't retry - result = 0; - break; - } - - if (result != 0) { - Dbprintf("Cmd Error: too many retries; read failed"); - return result; - } - - memcpy(blockData, receivedAnswer, 16); - return 0; -} - -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) -{ - // variables - uint16_t len, i; + return 0; +} + +int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) +{ + // variables + int len; + uint8_t bt[2]; + + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + // command MIFARE_CLASSIC_READBLOCK + len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer,NULL); + if (len == 1) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return 1; + } + if (len != 18) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); + return 2; + } + + memcpy(bt, receivedAnswer + 16, 2); + AppendCrc14443a(receivedAnswer, 16); + if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); + return 3; + } + + memcpy(blockData, receivedAnswer, 14); + return 0; +} + + +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +{ + // variables + int len, i; uint32_t pos; - uint8_t par[3] = {0}; // enough for 18 Bytes to send + uint32_t par = 0; byte_t res; - + uint8_t d_block[18], d_block_enc[18]; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } - + memcpy(d_block, blockData, 16); AppendCrc14443a(d_block, 16); - + // crypto + par = 0; for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; - par[pos>>3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); - } + par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(d_block[pos])) & 0x01) * 0x20000 ); + } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); // Receive the response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); + len = ReaderReceive(receivedAnswer); res = 0; for (i = 0; i < 4; i++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], i)) << i; if ((len != 1) || (res != 0x0A)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); return 2; } + + return 0; +} + +int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) +{ + // variables + int len; + uint32_t par = 0; + + uint8_t d_block[18]; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + // command MIFARE_CLASSIC_WRITEBLOCK + len = mifare_sendcmd_short(NULL, 1, 0xA0, blockNo, receivedAnswer,NULL); + + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); + return 1; + } + + memset(d_block,'\0',18); + memcpy(d_block, blockData, 16); + AppendCrc14443a(d_block, 16); + + ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); + + // Receive the response + len = ReaderReceive(receivedAnswer); + + if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); + return 2; + } + + return 0; +} + +int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData) +{ + // variables + int len; + //uint32_t par = 0; + + uint8_t d_block[8]; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + // command MIFARE_CLASSIC_WRITEBLOCK + memset(d_block,'\0',8); + d_block[0]= blockNo; + memcpy(d_block+1,blockData,4); + AppendCrc14443a(d_block, 6); + + //i know the data send here is correct + len = mifare_sendcmd_short_special(NULL, 1, 0xA2, d_block, receivedAnswer,NULL); + + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); + return 1; + } + return 0; +} + +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) +{ + // variables + int len; + + // Mifare HALT + uint8_t* receivedAnswer = mifare_get_bigbufptr(); - return 0; -} - -/* // command not needed, but left for future testing -int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) -{ - uint16_t len; - uint8_t par[3] = {0}; // enough for 18 parity bits - uint8_t d_block[18] = {0x00}; - uint8_t receivedAnswer[MAX_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - - len = mifare_sendcmd_short(NULL, true, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); - return 1; - } - - memcpy(d_block, blockData, 16); - AppendCrc14443a(d_block, 16); - - ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); - - len = ReaderReceive(receivedAnswer, receivedAnswerPar); - - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); - return 2; - } - return 0; -} -*/ - -int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) -{ - uint16_t len; - uint8_t d_block[5] = {0x00}; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - // command MIFARE_CLASSIC_WRITEBLOCK - d_block[0]= blockNo; - memcpy(d_block+1,blockData,4); - //AppendCrc14443a(d_block, 6); - - len = mifare_sendcmd(0xA2, d_block, sizeof(d_block), receivedAnswer, receivedAnswerPar, NULL); - - if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0],len); - return 1; - } - return 0; -} - -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) -{ - uint16_t len; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, pcs == NULL ? 0:1, 0x50, 0x00, receivedAnswer, NULL); if (len != 0) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("halt error. response len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); return 1; } - return 0; -} - -int mifare_ultra_halt() -{ - uint16_t len; - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - len = mifare_sendcmd_short(NULL, true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL); - if (len != 0) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("halt error. response len: %x", len); - return 1; - } - return 0; -} - - -// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), -// plus evtl. 8 sectors with 16 blocks each (4k cards) -uint8_t NumBlocksPerSector(uint8_t sectorNo) -{ - if (sectorNo < 32) - return 4; - else - return 16; -} - -uint8_t FirstBlockOfSector(uint8_t sectorNo) -{ - if (sectorNo < 32) - return sectorNo * 4; - else - return 32*4 + (sectorNo - 32) * 16; - -} - -uint8_t SectorTrailer(uint8_t blockNo) -{ - if (blockNo < 32*4) { - return (blockNo | 0x03); - } else { - return (blockNo | 0x0f); - } -} - -bool IsSectorTrailer(uint8_t blockNo) -{ - return (blockNo == SectorTrailer(blockNo)); -} - -// work with emulator memory -void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + return 0; +} + +int mifare_ultra_halt(uint32_t uid) +{ + // variables + int len; + + // Mifare HALT + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + len = mifare_sendcmd_short(NULL, 1, 0x50, 0x00, receivedAnswer, NULL); + if (len != 0) { + if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); + return 1; + } + + return 0; +} + +// work with emulator memory +void emlSetMem(uint8_t *data, int blockNum, int blocksCount) { + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + memcpy(emCARD + blockNum * 16, data, blocksCount * 16); } void emlGetMem(uint8_t *data, int blockNum, int blocksCount) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + memcpy(data, emCARD + blockNum * 16, blocksCount * 16); } void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + memcpy(data, emCARD + bytePtr, byteCount); } int emlCheckValBl(int blockNum) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); uint8_t* data = emCARD + blockNum * 16; if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) || @@ -650,295 +482,65 @@ int emlCheckValBl(int blockNum) { (data[3] != (data[7] ^ 0xff)) || (data[3] != data[11]) || (data[12] != (data[13] ^ 0xff)) || (data[12] != data[14]) || (data[12] != (data[15] ^ 0xff)) - ) + ) return 1; return 0; } int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); uint8_t* data = emCARD + blockNum * 16; - + if (emlCheckValBl(blockNum)) { return 1; } - + memcpy(blReg, data, 4); *blBlock = data[12]; + return 0; } int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { - uint8_t* emCARD = BigBuf_get_EM_addr(); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); uint8_t* data = emCARD + blockNum * 16; - + memcpy(data + 0, &blReg, 4); memcpy(data + 8, &blReg, 4); blReg = blReg ^ 0xffffffff; memcpy(data + 4, &blReg, 4); - + data[12] = blBlock; data[13] = blBlock ^ 0xff; data[14] = blBlock; data[15] = blBlock ^ 0xff; - + return 0; } uint64_t emlGetKey(int sectorNum, int keyType) { uint8_t key[6]; - uint8_t* emCARD = BigBuf_get_EM_addr(); - - memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + + memcpy(key, emCARD + 3 * 16 + sectorNum * 4 * 16 + keyType * 10, 6); return bytes_to_num(key, 6); } void emlClearMem(void) { int b; - + const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04}; - uint8_t* emCARD = BigBuf_get_EM_addr(); - - memset(emCARD, 0, CARD_MEMORY_SIZE); - + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + + memset(emCARD, 0, CARD_MEMORY_LEN); + // fill sectors trailer data for(b = 3; b < 256; b<127?(b+=4):(b+=16)) { emlSetMem((uint8_t *)trailer, b , 1); - } + } // uid emlSetMem((uint8_t *)uid, 0, 1); return; } - - -// Mifare desfire commands -int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[5] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,2); - AppendCrc14443a(dcmd, 3); - - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, answer_parity); - if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Authentication failed. Card timeout."); - return 1; - } - return len; -} - -int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing) -{ - uint8_t dcmd[20] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,17); - AppendCrc14443a(dcmd, 18); - - ReaderTransmit(dcmd, sizeof(dcmd), NULL); - int len = ReaderReceive(answer, answer_parity); - if(!len){ - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Authentication failed. Card timeout."); - return 1; - } - return len; -} - -int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData){ - - int len; - // load key, keynumber - uint8_t data[2]={0x0a, 0x00}; - uint8_t receivedAnswer[MAX_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - - len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer,receivedAnswerPar,NULL); - if (len == 1) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; - } - - if (len == 12) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10],receivedAnswer[11]); - } - memcpy(blockData, receivedAnswer, 12); - return 0; - } - return 1; -} - -int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ - - int len; - uint8_t data[17] = {0x00}; - data[0] = 0xAF; - memcpy(data+1,key,16); - - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - - len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL); - - if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); - return 1; - } - - if (len == 12){ - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], - receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], - receivedAnswer[10],receivedAnswer[11]); - } - memcpy(blockData, receivedAnswer, 12); - return 0; - } - return 1; -} - -//----------------------------------------------------------------------------- -// MIFARE check keys -// -//----------------------------------------------------------------------------- -// one key check -static int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint8_t *key, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, bool fixed_nonce) { - - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - if (*cascade_levels == 0) { // 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 (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card"); - return -1; - } - switch (card_info.uidlen) { - case 4 : *cascade_levels = 1; break; - case 7 : *cascade_levels = 2; break; - case 10: *cascade_levels = 3; break; - default: break; - } - } else { // no need for anticollision. We can directly select the card - if (!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) { - if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels); - return -1; - } - } - - if (!fixed_nonce) { - uint64_t ui64Key = bytes_to_num(key, 6); - if (mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST, auth_timeout)) { // authentication failed - return -2; - } else { - mifare_classic_halt(pcs, *cuid); - } - } else { - uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - // Transmit MIFARE_CLASSIC_AUTH - int len = mifare_sendcmd_short(pcs, false, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if (len != 4) return -2; - // Transmit encrypted reader nonce and reader answer - uint8_t mf_nr_ar[8] = NESTED_FIXED_NR_ENC; - memcpy(mf_nr_ar + 4, key, 4); - ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), key + 4, NULL); - uint32_t save_timeout = iso14a_get_timeout(); // save standard timeout - iso14a_set_timeout(*auth_timeout); // set timeout for authentication response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); - iso14a_set_timeout(save_timeout); // restore standard timeout - if (!len) return -2; - } - - return 0; // success -} - -// multi key check -static int MifareChkBlockKeysEx(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, bool fixed_nonce) { - - uint8_t uid[10]; - uint32_t cuid = 0; - uint8_t cascade_levels = 0; - - int retryCount = 0; - for (uint8_t i = 0; i < keyCount; i++) { - uint8_t bytes_per_key = fixed_nonce ? 5 : 6; - int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, keys + i*bytes_per_key, blockNo, keyType, auth_timeout, debugLevel, fixed_nonce); - if (res == -1) { // couldn't select - retryCount++; - if (retryCount >= 5) { - Dbprintf("ChkKeys: block=%d key=%d. Couldn't select. Exit...", blockNo, keyType); - return -1; - } else { - --i; // try the same key once again - SpinDelay(20); - // Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType); - continue; - } - } - if (res == -2) { // couldn't authenticate with this key - retryCount = 0; - continue; - } - - return i + 1; // successful authentication - - } - - if (BUTTON_PRESS()) { - return -2; - } - - return 0; // couldn't authenticate with any key -} - - -int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel) { - return MifareChkBlockKeysEx(keys, keyCount, blockNo, keyType, auth_timeout, debugLevel, false); -} - - -// fixed nonce check -int MifareChkBlockKeysFixedNonce(uint8_t *ar_par, uint8_t ar_par_cnt, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel) { - return MifareChkBlockKeysEx(ar_par, ar_par_cnt, blockNo, keyType, auth_timeout, debugLevel, true); -} - - -// multisector multikey check -int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, TKeyIndex *keyIndex) { - int res = 0; - -// int clk = GetCountSspClk(); - - for(int sc = 0; sc < SectorCount; sc++){ - WDT_HIT(); - - int keyAB = keyType; - do { - res = MifareChkBlockKeys(keys, keyCount, FirstBlockOfSector(sc), keyAB & 0x01, auth_timeout, debugLevel); - if (res < 0) { - return res; - } - if (res > 0) { - (*keyIndex)[keyAB & 0x01][sc] = res; - } - } while(--keyAB > 0); - } - -// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1))); - - return 1; -} - - diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index c2bfc634..ad637ea0 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -9,71 +9,76 @@ // code for work with mifare cards. //----------------------------------------------------------------------------- -#ifndef MIFAREUTIL_H__ -#define MIFAREUTIL_H__ - -#include -#include - -#include "crapto1/crapto1.h" -#include "usb_cdc.h" +#ifndef __MIFAREUTIL_H +#define __MIFAREUTIL_H // mifare authentication -#define CRYPT_NONE 0 -#define CRYPT_ALL 1 -#define CRYPT_REQUEST 2 -#define AUTH_FIRST 0 -#define AUTH_NESTED 2 +#define CRYPT_NONE 0 +#define CRYPT_ALL 1 +#define CRYPT_REQUEST 2 +#define AUTH_FIRST 0 +#define AUTH_NESTED 2 + +// mifare 4bit card answers +#define CARD_ACK 0x0A // 1010 - ACK +#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) +#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error // reader voltage field detector #define MF_MINFIELDV 4000 // debug -#define MF_DBG_NONE 0 // no messages -#define MF_DBG_ERROR 1 // errors only -#define MF_DBG_INFO 2 // errors + info messages -#define MF_DBG_DEBUG 3 // errors + info + debug messages -#define MF_DBG_EXTENDED 4 // errors + info + debug + breaking debug messages +// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode +#define MF_DBG_NONE 0 +#define MF_DBG_ERROR 1 +#define MF_DBG_ALL 2 +#define MF_DBG_EXTENDED 4 extern int MF_DBGLEVEL; -//functions -int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); +//mifare emulator states +#define MFEMUL_NOFIELD 0 +#define MFEMUL_IDLE 1 +#define MFEMUL_SELECT1 2 +#define MFEMUL_SELECT2 3 +#define MFEMUL_AUTH1 4 +#define MFEMUL_AUTH2 5 +#define MFEMUL_WORK 6 +#define MFEMUL_WRITEBL2 7 +#define MFEMUL_INTREG_INC 8 +#define MFEMUL_INTREG_DEC 9 +#define MFEMUL_INTREG_REST 10 +#define MFEMUL_HALTED 11 -// mifare classic -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *auth_timeout); -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing, uint32_t *auth_timeout); -int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); -// Ultralight/NTAG... -int mifare_ul_ev1_auth(uint8_t *key, uint8_t *pack); -int mifare_ultra_auth(uint8_t *key); -int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData); -//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData); -int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData); -int mifare_ultra_halt(); - -// desfire -int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing); -int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing); -int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData); -int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); - -// crypto functions -void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); -void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out); -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par); -void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par); +//functions +uint8_t* mifare_get_bigbufptr(void); +int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t *timing); +int mifare_sendcmd_short_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t* amswer, uint8_t *timing); +int mifare_sendcmd_shortex(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint32_t * parptr, uint32_t *timing); + +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, \ + uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested); +int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, \ + uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint64_t isNested, uint32_t * ntptr, uint32_t *timing); +int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_readblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_special_writeblock(uint32_t uid, uint8_t blockNo, uint8_t *blockData); +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); +int mifare_ultra_halt(uint32_t uid); + +// crypto functions +void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, int len, uint32_t *par); uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data); -// Mifare memory structure -uint8_t NumBlocksPerSector(uint8_t sectorNo); -uint8_t FirstBlockOfSector(uint8_t sectorNo); -bool IsSectorTrailer(uint8_t blockNo); -uint8_t SectorTrailer(uint8_t blockNo); +// memory management +uint8_t* mifare_get_bigbufptr(void); +uint8_t* eml_get_bigbufptr_sendbuf(void); +uint8_t* eml_get_bigbufptr_recbuf(void); // emulator functions void emlClearMem(void); @@ -82,13 +87,7 @@ void emlGetMem(uint8_t *data, int blockNum, int blocksCount); void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount); uint64_t emlGetKey(int sectorNum, int keyType); int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum); -int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum); -int emlCheckValBl(int blockNum); - -// mifare check keys -typedef uint8_t TKeyIndex[2][40]; -int MifareChkBlockKeysFixedNonce(uint8_t *ar_par, uint8_t ar_par_cnt, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel); -int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel); -int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint32_t *auth_timeout, uint8_t debugLevel, TKeyIndex *keyIndex); - -#endif +int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum); +int emlCheckValBl(int blockNum); + +#endif diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c deleted file mode 100644 index 2ac72ec0..00000000 --- a/armsrc/optimized_cipher.c +++ /dev/null @@ -1,300 +0,0 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, or, at your option, any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - * - ****************************************************************************/ - -/** - - This file contains an optimized version of the MAC-calculation algorithm. Some measurements on - a std laptop showed it runs in about 1/3 of the time: - - Std: 0.428962 - Opt: 0.151609 - - Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can - be easily dropped into a code base. - - The optimizations have been performed in the following steps: - * Parameters passed by reference instead of by value. - * Iteration instead of recursion, un-nesting recursive loops into for-loops. - * Handling of bytes instead of individual bits, for less shuffling and masking - * Less creation of "objects", structs, and instead reuse of alloc:ed memory - * Inlining some functions via #define:s - - As a consequence, this implementation is less generic. Also, I haven't bothered documenting this. - For a thorough documentation, check out the MAC-calculation within cipher.c instead. - - -- MHS 2015 -**/ - -/** - - The runtime of opt_doTagMAC_2() with the MHS optimized version was 403 microseconds on Proxmark3. - This was still to slow for some newer readers which didn't want to wait that long. - - Further optimizations to speedup the MAC calculations: - * Optimized opt_Tt logic - * Look up table for opt_select - * Removing many unnecessary bit maskings (& 0x1) - * updating state in place instead of alternating use of a second state structure - * remove the necessity to reverse bits of input and output bytes - - opt_doTagMAC_2() now completes in 270 microseconds. - - -- piwi 2019 -**/ - -#include "optimized_cipher.h" -#include -#include -#include -#include "string.h" - -static const uint8_t opt_select_LUT[256] = { - 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, - 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, - 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06, - 07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, - 06, 05, 04, 07, 04, 05, 06, 07, 02, 01, 01, 02, 00, 01, 03, 02, - 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, - 00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, - 05, 06, 07, 04, 06, 07, 04, 05, 05, 06, 06, 05, 06, 07, 05, 04, - 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06, - 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, - 02, 01, 00, 03, 00, 01, 02, 03, 02, 01, 01, 02, 00, 01, 03, 02, - 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02, - 04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, - 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, - 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04, - 01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00 -}; - -/********************** the table above has been generated with this code: ******** -#include "util.h" -static void init_opt_select_LUT(void) { - for (int r = 0; r < 256; r++) { - uint8_t r_ls2 = r << 2; - uint8_t r_and_ls2 = r & r_ls2; - uint8_t r_or_ls2 = r | r_ls2; - uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); - uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r; - uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r; - opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1); - } - print_result("", opt_select_LUT, 256); -} -***********************************************************************************/ - -#define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\ - |(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\ - |(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x)) - -/* - * Some background on the expression above can be found here... -uint8_t xopt__select(bool x, bool y, uint8_t r) -{ - - //r: r0 r1 r2 r3 r4 r5 r6 r7 - //r_ls2: r2 r3 r4 r5 r6 r7 0 0 - // z0 - // z1 - -// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original - uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); - -// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original - uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1); - -// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original - uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x; - - return (z0 & 4) | (z1 & 2) | (z2 & 1); -} -*/ - -static void opt_successor(const uint8_t *k, State *s, uint8_t y) { -// #define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14) ^ (s->t >> 10) ^ (s->t >> 8) ^ (s->t >> 5) ^ (s->t >> 4)^ (s->t >> 1) ^ s->t)) - // uint8_t Tt = opt_T(s); - uint16_t Tt = s->t & 0xc533; - Tt = Tt ^ (Tt >> 1); - Tt = Tt ^ (Tt >> 4); - Tt = Tt ^ (Tt >> 10); - Tt = Tt ^ (Tt >> 8); - - s->t = (s->t >> 1); - s->t |= (Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15; - - uint8_t opt_B = s->b; - opt_B ^= s->b >> 6; - opt_B ^= s->b >> 5; - opt_B ^= s->b >> 4; - - s->b = s->b >> 1; - s->b |= (opt_B ^ s->r) << 7; - - uint8_t opt_select = opt_select_LUT[s->r] & 0x04; - opt_select |= (opt_select_LUT[s->r] ^ ((Tt ^ y) << 1)) & 0x02; - opt_select |= (opt_select_LUT[s->r] ^ Tt) & 0x01; - - uint8_t r = s->r; - s->r = (k[opt_select] ^ s->b) + s->l ; - s->l = s->r + r; -} - -static void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) { - for (int i = 0; i < length; i++) { - uint8_t head; - head = in[i]; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - - head >>= 1; - opt_successor(k, s, head); - } - //For tag MAC, an additional 32 zeroes - if (add32Zeroes) { - for(int i = 0; i < 16; i++) { - opt_successor(k, s, 0); - opt_successor(k, s, 0); - } - } -} - -static void opt_output(const uint8_t *k, State *s, uint8_t *buffer) { - for (uint8_t times = 0; times < 4; times++) { - uint8_t bout = 0; - bout |= (s->r & 0x4) >> 2; - opt_successor(k, s, 0); - bout |= (s->r & 0x4) >> 1; - opt_successor(k, s, 0); - bout |= (s->r & 0x4); - opt_successor(k, s, 0); - bout |= (s->r & 0x4) << 1; - opt_successor(k, s, 0); - bout |= (s->r & 0x4) << 2; - opt_successor(k, s, 0); - bout |= (s->r & 0x4) << 3; - opt_successor(k, s, 0); - bout |= (s->r & 0x4) << 4; - opt_successor(k, s, 0); - bout |= (s->r & 0x4) << 5; - opt_successor(k, s, 0); - buffer[times] = bout; - } -} - -static void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { - State _init = { - ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; - - opt_suc(k, &_init, input, 12, false); - //printf("\noutp "); - opt_output(k, &_init, out); -} - -void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { - uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; - opt_MAC(div_key_p, cc_nr_p, dest); - memcpy(mac, dest, 4); - return; -} - -void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { - State _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; - opt_suc(div_key_p, &_init, cc_p, 12, true); - opt_output(div_key_p, &_init, mac); - return; -} - -/** - * The tag MAC can be divided (both can, but no point in dividing the reader mac) into - * two functions, since the first 8 bytes are known, we can pre-calculate the state - * reached after feeding CC to the cipher. - * @param cc_p - * @param div_key_p - * @return the cipher state - */ -State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { - State _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; - opt_suc(div_key_p, &_init, cc_p, 8, false); - return _init; -} - -/** - * The second part of the tag MAC calculation, since the CC is already calculated into the state, - * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag - * MAC response. - * @param _init - precalculated cipher state - * @param nr - the reader challenge - * @param mac - where to store the MAC - * @param div_key_p - the key to use - */ -void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { - opt_suc(div_key_p, &_init, nr, 4, true); - opt_output(div_key_p, &_init, mac); - return; -} diff --git a/armsrc/optimized_cipher.h b/armsrc/optimized_cipher.h deleted file mode 100644 index be77a250..00000000 --- a/armsrc/optimized_cipher.h +++ /dev/null @@ -1,88 +0,0 @@ -/***************************************************************************** - * WARNING - * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. - * - ***************************************************************************** - * - * This file is part of loclass. It is a reconstructon of the cipher engine - * used in iClass, and RFID techology. - * - * The implementation is based on the work performed by - * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and - * Milosch Meriac in the paper "Dismantling IClass". - * - * Copyright (C) 2014 Martin Holst Swende - * - * This is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, or, at your option, any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with loclass. If not, see . - * - * - ****************************************************************************/ - -#ifndef OPTIMIZED_CIPHER_H__ -#define OPTIMIZED_CIPHER_H__ - -#include - -/** -* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2 -* consisting of the following four components: -* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ; -* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ; -* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 . -* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 . -**/ -typedef struct { - uint8_t l; - uint8_t r; - uint8_t b; - uint16_t t; -} State; - -/** The reader MAC is MAC(key, CC * NR ) - **/ -void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]); - -/** - * The tag MAC is MAC(key, CC * NR * 32x0)) - */ -void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]); - -/** - * The tag MAC can be divided (both can, but no point in dividing the reader mac) into - * two functions, since the first 8 bytes are known, we can pre-calculate the state - * reached after feeding CC to the cipher. - * @param cc_p - * @param div_key_p - * @return the cipher state - */ -State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); - -/** - * The second part of the tag MAC calculation, since the CC is already calculated into the state, - * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag - * MAC response. - * @param _init - precalculated cipher state - * @param nr - the reader challenge - * @param mac - where to store the MAC - * @param div_key_p - the key to use - */ -void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p); - -#endif // OPTIMIZED_CIPHER_H__ diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c deleted file mode 100644 index 2fae74cc..00000000 --- a/armsrc/pcf7931.c +++ /dev/null @@ -1,589 +0,0 @@ -#include "proxmark3.h" -#include "apps.h" -#include "usb_cdc.h" -#include "lfsampling.h" -#include "pcf7931.h" -#include "util.h" -#include "string.h" -#include "fpgaloader.h" - -#define T0_PCF 8 //period for the pcf7931 in us -#define ALLOC 16 - -size_t DemodPCF7931(uint8_t **outBlocks) { - uint8_t bits[256] = {0x00}; - uint8_t blocks[8][16]; - uint8_t *dest = BigBuf_get_addr(); - - int GraphTraceLen = BigBuf_max_traceLen(); - if (GraphTraceLen > 18000) - GraphTraceLen = 18000; - - int i, j, lastval, bitidx, half_switch; - int clock = 64; - int tolerance = clock / 8; - int pmc, block_done; - int lc, warnings = 0; - size_t num_blocks = 0; - int lmin=128, lmax=128; - uint8_t dir; - //clear read buffer - BigBuf_Clear_keep_EM(); - - LFSetupFPGAForADC(95, true); - DoAcquisition_default(0, true); - - lmin = 64; - lmax = 192; - - i = 2; - - /* Find first local max/min */ - if(dest[1] > dest[0]) { - while(i < GraphTraceLen) { - if( !(dest[i] > dest[i-1]) && dest[i] > lmax) - break; - i++; - } - dir = 0; - } else { - while(i < GraphTraceLen) { - if( !(dest[i] < dest[i-1]) && dest[i] < lmin) - break; - i++; - } - dir = 1; - } - - lastval = i++; - half_switch = 0; - pmc = 0; - block_done = 0; - - for (bitidx = 0; i < GraphTraceLen; i++) { - if ((dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) { - lc = i - lastval; - lastval = i; - - // Switch depending on lc length: - // Tolerance is 1/8 of clock rate (arbitrary) - if (ABS(lc-clock/4) < tolerance) { - // 16T0 - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33+16)-1; - lastval = i; - pmc = 0; - block_done = 1; - } else { - pmc = i; - } - } else if (ABS(lc-clock/2) < tolerance) { - // 32TO - if((i - pmc) == lc) { /* 16T0 was previous one */ - /* It's a PMC ! */ - i += (128+127+16+32+33)-1; - lastval = i; - pmc = 0; - block_done = 1; - } else if(half_switch == 1) { - bits[bitidx++] = 0; - half_switch = 0; - } - else - half_switch++; - } else if (ABS(lc-clock) < tolerance) { - // 64TO - bits[bitidx++] = 1; - } else { - // Error - if (++warnings > 10) { - Dbprintf("Error: too many detection errors, aborting."); - return 0; - } - } - - if(block_done == 1) { - if(bitidx == 128) { - for(j = 0; j < 16; ++j) { - blocks[num_blocks][j] = - 128 * bits[j*8 + 7]+ - 64 * bits[j*8 + 6] + - 32 * bits[j*8 + 5] + - 16 * bits[j*8 + 4] + - 8 * bits[j*8 + 3] + - 4 * bits[j*8 + 2] + - 2 * bits[j*8 + 1] + - bits[j*8] - ; - } - num_blocks++; - } - bitidx = 0; - block_done = 0; - half_switch = 0; - } - if(i < GraphTraceLen) - dir = (dest[i-1] > dest[i]) ? 0 : 1; - } - if(bitidx==255) - bitidx=0; - warnings = 0; - if(num_blocks == 4) break; - } - memcpy(outBlocks, blocks, 16 * num_blocks); - return num_blocks; -} - -bool IsBlock0PCF7931(uint8_t *block) { - // assuming all RFU bits are set to 0 - // if PAC is enabled password is set to 0 - if (block[7] == 0x01) - { - if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) - return true; - } - else if (block[7] == 0x00) - { - if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) - return true; - } - return false; -} - -bool IsBlock1PCF7931(uint8_t *block) { - // assuming all RFU bits are set to 0 - - uint8_t rb1 = block[14] & 0x80; - uint8_t rfb = block[14] & 0x7f; - uint8_t rlb = block[15]; - - if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) - // block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled - if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1)) - return true; - - return false; -} - -void ReadPCF7931() { - int found_blocks = 0; // successfully read blocks - int max_blocks = 8; // readable blocks - uint8_t memory_blocks[8][17]; // PCF content - - uint8_t single_blocks[8][17]; // PFC blocks with unknown position - int single_blocks_cnt = 0; - - size_t n = 0; // transmitted blocks - uint8_t tmp_blocks[4][16]; // temporary read buffer - - uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found - int errors = 0; // error counter - int tries = 0; // tries counter - - memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); - memset(single_blocks, 0, 8*17*sizeof(uint8_t)); - - int i = 0, j = 0; - - do { - i = 0; - - memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmp_blocks); - if(!n) - ++errors; - - // exit if no block is received - if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { - Dbprintf("Error, no tag or bad tag"); - return; - } - - // exit if too many errors during reading - if (tries > 50 && (2*errors > tries)) { - Dbprintf("Error reading the tag"); - Dbprintf("Here is the partial content"); - goto end; - } - - // our logic breaks if we don't get at least two blocks - if (n < 2) { - // skip if all 0s block or no blocks - if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) - continue; - - // add block to single blocks list - if (single_blocks_cnt < max_blocks) { - for (i = 0; i < single_blocks_cnt; ++i) { - if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) { - j = 1; - break; - } - } - if (j != 1) { - memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16); - print_result("got single block", single_blocks[single_blocks_cnt], 16); - single_blocks_cnt++; - } - j = 0; - } - ++tries; - continue; - } - - Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); - for (i = 0; i < n; ++i) - { - print_result("got consecutive blocks", tmp_blocks[i], 16); - } - - i = 0; - if(!found_0_1) { - while (i < n - 1) { - if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { - found_0_1 = 1; - memcpy(memory_blocks[0], tmp_blocks[i], 16); - memcpy(memory_blocks[1], tmp_blocks[i+1], 16); - memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1; - // block 1 tells how many blocks are going to be sent - max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; - found_blocks = 2; - - Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); - - // handle the following blocks - for (j = i + 2; j < n; ++j) { - memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); - memory_blocks[found_blocks][ALLOC] = 1; - ++found_blocks; - } - break; - } - ++i; - } - } else { - // Trying to re-order blocks - // Look for identical block in memory blocks - while (i < n-1) { - // skip all zeroes blocks - if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { - for (j = 1; j < max_blocks - 1; ++j) { - if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) { - memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16); - memory_blocks[j+1][ALLOC] = 1; - if (++found_blocks >= max_blocks) goto end; - } - } - } - if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { - for (j = 0; j < max_blocks; ++j) { - if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) { - if (j == 0) { - memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16); - memory_blocks[max_blocks - 1][ALLOC] = 1; - } else { - memcpy(memory_blocks[j-1], tmp_blocks[i], 16); - memory_blocks[j-1][ALLOC] = 1; - } - if (++found_blocks >= max_blocks) goto end; - } - } - } - ++i; - } - } - ++tries; - if (BUTTON_PRESS()) { - Dbprintf("Button pressed, stopping."); - goto end; - } - } - while (found_blocks < max_blocks); - - end: - Dbprintf("-----------------------------------------"); - Dbprintf("Memory content:"); - Dbprintf("-----------------------------------------"); - for (i = 0; i < max_blocks; ++i) { - if (memory_blocks[i][ALLOC]) - print_result("Block", memory_blocks[i], 16); - else - Dbprintf("", i); - } - Dbprintf("-----------------------------------------"); - - if (found_blocks < max_blocks) { - Dbprintf("-----------------------------------------"); - Dbprintf("Blocks with unknown position:"); - Dbprintf("-----------------------------------------"); - for (i = 0; i < single_blocks_cnt; ++i) - print_result("Block", single_blocks[i], 16); - - Dbprintf("-----------------------------------------"); - } - cmd_send(CMD_ACK,0,0,0,0,0); -} - -static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { - uint32_t tab[1024]={0}; // data times frame - uint32_t u = 0; - uint8_t parity = 0; - bool comp = 0; - - //BUILD OF THE DATA FRAME - //alimentation of the tag (time for initializing) - AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); - AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); - //password indication bit - AddBitPCF7931(1, tab, l, p); - // password (on 56 bits) - AddBytePCF7931(pass[0], tab, l, p); - AddBytePCF7931(pass[1], tab, l, p); - AddBytePCF7931(pass[2], tab, l, p); - AddBytePCF7931(pass[3], tab, l, p); - AddBytePCF7931(pass[4], tab, l, p); - AddBytePCF7931(pass[5], tab, l, p); - AddBytePCF7931(pass[6], tab, l, p); - //programming mode (0 or 1) - AddBitPCF7931(0, tab, l, p); - - //block adress on 6 bits - for (u = 0; u < 6; ++u) { - if (address & (1 << u)) { // bit 1 - ++parity; - AddBitPCF7931(1, tab, l, p); - } else { // bit 0 - AddBitPCF7931(0, tab, l, p); - } - } - - //byte address on 4 bits - for (u = 0; u < 4; ++u) - { - if (byte & (1 << u)) { // bit 1 - parity++; - AddBitPCF7931(1, tab, l, p); - } - else // bit 0 - AddBitPCF7931(0, tab, l, p); - } - - //data on 8 bits - for (u=0; u<8; u++) - { - if (data&(1< 0xFFFF) { - tab[u] -= 0xFFFF; - comp = 0; - } - } - - SendCmdPCF7931(tab); -} - -void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p) { - uint8_t i = 0; - uint8_t pass_array[7]; - - while (password < 0x00FFFFFFFFFFFFFF) { - if (BUTTON_PRESS()) { - Dbprintf("Button pressed, stopping bruteforce ..."); - return; - } - - num_to_bytes(password, 7, pass_array); - - Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", - pass_array[0], - pass_array[1], - pass_array[2], - pass_array[3], - pass_array[4], - pass_array[5], - pass_array[6]); - - for (i = 0; i < tries; ++i) - RealWritePCF7931 - ( - pass_array, - init_delay, - l, - p, - 0, - 7, - 0x01 - ); - - ++password; - } -} - -/* Write on a byte of a PCF7931 tag - * @param address : address of the block to write - @param byte : address of the byte to write - @param data : data to write - */ -void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { - Dbprintf("Initialization delay : %d us", init_delay); - Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); - Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7); - Dbprintf("Block address : %02x", address); - Dbprintf("Byte address : %02x", byte); - Dbprintf("Data : %02x", data); - - uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; - - RealWritePCF7931 (password, init_delay, l, p, address, byte, data); -} - - - -/* Send a trame to a PCF7931 tags - * @param tab : array of the data frame - */ - -void SendCmdPCF7931(uint32_t * tab) { - uint16_t u=0; - uint16_t tempo=0; - - Dbprintf("Sending data frame ..."); - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); - - LED_A_ON(); - - // steal this pin from the SSP and use it to control the modulation - AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; - - //initialization of the timer - AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; - AT91C_BASE_TCB->TCB_BCR = 1; - - tempo = AT91C_BASE_TC0->TC_CV; - for (u = 0; tab[u] != 0; u += 3) { - // modulate antenna - HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]) - tempo = AT91C_BASE_TC0->TC_CV; - - // stop modulating antenna - LOW(GPIO_SSC_DOUT); - while(tempo != tab[u+1]) - tempo = AT91C_BASE_TC0->TC_CV; - - // modulate antenna - HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u+2]) - tempo = AT91C_BASE_TC0->TC_CV; - } - - LED_A_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - DbpString("Data frame sent (multiple sends may be needed)"); - LED(0xFFFF, 1000); -} - - -/* Add a byte for building the data frame of PCF7931 tags - * @param b : byte to add - * @param tab : array of the data frame - * @param l : offset on low pulse width - * @param p : offset on low pulse positioning - */ -bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { - uint32_t u; - for (u = 0; u < 8; ++u) { - if (byte & (1 << u)) { //bit is 1 - if(AddBitPCF7931(1, tab, l, p)==1)return 1; - } else { //bit is 0 - if(AddBitPCF7931(0, tab, l, p)==1)return 1; - } - } - - return 0; -} - -/* Add a bits for building the data frame of PCF7931 tags - * @param b : bit to add - * @param tab : array of the data frame - * @param l : offset on low pulse width - * @param p : offset on low pulse positioning - */ -bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p) { - uint8_t u = 0; - - for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - - if (b == 1) { //add a bit 1 - if (u == 0) tab[u] = 34 * T0_PCF + p; - else tab[u] = 34 * T0_PCF + tab[u-1] + p; - - tab[u+1] = 6 * T0_PCF+tab[u] + l; - tab[u+2] = 88 * T0_PCF+tab[u + 1] - l - p; - return 0; - } else { //add a bit 0 - - if (u == 0) tab[u] = 98 * T0_PCF + p; - else tab[u] = 98 * T0_PCF + tab[u-1] + p; - - tab[u + 1] = 6 * T0_PCF + tab[u] + l; - tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p; - return 0; - } - - return 1; -} - -/* Add a custom pattern in the data frame - * @param a : delay of the first high pulse - * @param b : delay of the low pulse - * @param c : delay of the last high pulse - * @param tab : array of the data frame - */ -bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab) { - uint32_t u = 0; - for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - - if (u == 0) tab[u] = a; - else tab[u] = a + tab[u - 1]; - - tab[u + 1] = b + tab[u]; - tab[u + 2] = c + tab[u + 1]; - - return 0; -} diff --git a/armsrc/pcf7931.h b/armsrc/pcf7931.h deleted file mode 100644 index 67aad29a..00000000 --- a/armsrc/pcf7931.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __PCF7931_H -#define __PCF7931_H - -size_t DemodPCF7931(uint8_t **outBlocks); -bool IsBlock0PCF7931(uint8_t *Block); -bool IsBlock1PCF7931(uint8_t *Block); -void ReadPCF7931(); -void SendCmdPCF7931(uint32_t * tab); -bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p); -bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p); -bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab); -void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data); -void BruteForcePCF7931(uint64_t start_password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p); - -#endif diff --git a/armsrc/printf.c b/armsrc/printf.c index 79c123df..d5e61798 100644 --- a/armsrc/printf.c +++ b/armsrc/printf.c @@ -40,6 +40,9 @@ #include "util.h" #include "string.h" +typedef uint32_t uintmax_t; +typedef int32_t intmax_t; + typedef unsigned char u_char; typedef unsigned int u_int; typedef unsigned long u_long; @@ -175,7 +178,6 @@ reswitch: switch (ch = (u_char)*fmt++) { padc = '0'; goto reswitch; } - // intentionally fall through to next case case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': for (n = 0;; ++fmt) { diff --git a/armsrc/start.c b/armsrc/start.c index f1e58ab0..d7332bda 100644 --- a/armsrc/start.c +++ b/armsrc/start.c @@ -11,75 +11,23 @@ #include "proxmark3.h" #include "apps.h" -#include "zlib.h" -#include "BigBuf.h" - -static uint8_t *next_free_memory; -extern struct common_area common_area; -extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__; - - -static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size) -{ - uint8_t *allocated_memory; - - allocated_memory = next_free_memory; - next_free_memory += items*size; - return allocated_memory; -} - - -static void inflate_free(voidpf opaque, voidpf address) -{ - // nothing to do - -} - -static void uncompress_data_section(void) -{ - z_stream data_section; - - next_free_memory = BigBuf_get_addr(); - - // initialize zstream structure - data_section.next_in = (uint8_t *) &__data_src_start__; - data_section.avail_in = &__data_end__ - &__data_start__; // uncompressed size. Wrong but doesn't matter. - data_section.next_out = (uint8_t *) &__data_start__; - data_section.avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct. - data_section.zalloc = &inflate_malloc; - data_section.zfree = &inflate_free; - data_section.opaque = NULL; - - // initialize zlib for inflate - inflateInit2(&data_section, 15); - - // uncompress data segment to RAM - inflate(&data_section, Z_FINISH); - - // save the size of the compressed data section - common_area.arg1 = data_section.total_in; -} - +extern char __data_start__, __data_src_start__, __data_end__, __bss_start__, __bss_end__; void __attribute__((section(".startos"))) Vector(void) { /* Stack should have been set up by the bootloader */ - // char *src; - char *dst, *end; - - uncompress_data_section(); + char *src, *dst, *end; /* Set up (that is: clear) BSS. */ dst = &__bss_start__; end = &__bss_end__; while(dst < end) *dst++ = 0; - // Set up data segment: Copy from flash to ram - // src = &__data_src_start__; - // dst = &__data_start__; - // end = &__data_end__; - // while(dst < end) *dst++ = *src++; - + /* Set up data segment: Copy from flash to ram */ + src = &__data_src_start__; + dst = &__data_start__; + end = &__data_end__; + while(dst < end) *dst++ = *src++; AppMain(); } diff --git a/bootrom/string.h b/armsrc/stdint.h similarity index 50% rename from bootrom/string.h rename to armsrc/stdint.h index 87058391..78a0b051 100644 --- a/bootrom/string.h +++ b/armsrc/stdint.h @@ -1,25 +1,27 @@ //----------------------------------------------------------------------------- -// Jonathan Westhues, Aug 2005 // Copyright (C) 2010 Hector Martin "marcan" // // 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. //----------------------------------------------------------------------------- -// Common string.h functions +// Replacement stdint.h because GCC doesn't come with it yet (C99) //----------------------------------------------------------------------------- -#ifndef __STRING_H -#define __STRING_H +#ifndef __STDINT_H +#define __STDINT_H -#include +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long long int int64_t; -void *memcpy(void *dest, const void *src, size_t len); -void *memset(void *dest, int c, size_t len); -void *memmove(void *dest, const void *src, size_t len); -int memcmp(const void *av, const void *bv, size_t len); -size_t strlen(const char *str); -char *strncat(char *dest, const char *src, size_t n); -char *strcat(char *dest, const char *src); +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; -#endif /* __STRING_H */ +typedef int intptr_t; +typedef unsigned int uintptr_t; + +#endif /* __STDINT_H */ diff --git a/armsrc/string.c b/armsrc/string.c index b2710d07..cc71276c 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -11,7 +11,8 @@ #include "string.h" #include -void *memcpy(void *dest, const void *src, size_t len) { +void *memcpy(void *dest, const void *src, int len) +{ uint8_t *d = dest; const uint8_t *s = src; while((len--) > 0) { @@ -22,8 +23,8 @@ void *memcpy(void *dest, const void *src, size_t len) { return dest; } - -void *memset(void *dest, int c, size_t len) { +void *memset(void *dest, int c, int len) +{ uint8_t *d = dest; while((len--) > 0) { *d = c; @@ -32,30 +33,8 @@ void *memset(void *dest, int c, size_t len) { return dest; } - -void *memmove(void *dest, const void *src, size_t len) { - uint8_t *d = dest; - const uint8_t *s = src; - if (dest <= src) { - while((len--) > 0) { - *d = *s; - d++; - s++; - } - } else { - d = d + len - 1; - s = s + len - 1; - while((len--) > 0) { - *d = *s; - d--; - s--; - } - } - return dest; -} - - -int memcmp(const void *av, const void *bv, size_t len) { +int memcmp(const void *av, const void *bv, int len) +{ const uint8_t *a = av; const uint8_t *b = bv; @@ -69,8 +48,8 @@ int memcmp(const void *av, const void *bv, size_t len) { return 0; } - -size_t strlen(const char *str) { +int strlen(const char *str) +{ int l = 0; while(*str) { l++; @@ -79,8 +58,8 @@ size_t strlen(const char *str) { return l; } - -char* strncat(char *dest, const char *src, size_t n) { +char* strncat(char *dest, const char *src, unsigned int n) +{ unsigned int dest_len = strlen(dest); unsigned int i; @@ -91,8 +70,8 @@ char* strncat(char *dest, const char *src, size_t n) { return dest; } - -char* strcat(char *dest, const char *src) { +char* strcat(char *dest, const char *src) +{ unsigned int dest_len = strlen(dest); unsigned int i; @@ -102,3 +81,35 @@ char* strcat(char *dest, const char *src) { return dest; } +////////////////////////////////////////// code to do 'itoa' + +/* reverse: reverse string s in place */ +void strreverse(char s[]) +{ + int c, i, j; + + for (i = 0, j = strlen(s)-1; i 0); /* delete it */ + if (sign < 0) + s[i++] = '-'; + s[i] = '\0'; + strreverse(s); +} + +//////////////////////////////////////// END 'itoa' CODE diff --git a/armsrc/string.h b/armsrc/string.h index 87058391..46ee218d 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -12,14 +12,14 @@ #ifndef __STRING_H #define __STRING_H -#include - -void *memcpy(void *dest, const void *src, size_t len); -void *memset(void *dest, int c, size_t len); -void *memmove(void *dest, const void *src, size_t len); -int memcmp(const void *av, const void *bv, size_t len); -size_t strlen(const char *str); -char *strncat(char *dest, const char *src, size_t n); +int strlen(const char *str); +void *memcpy(void *dest, const void *src, int len); +void *memset(void *dest, int c, int len); +int memcmp(const void *av, const void *bv, int len); +char *strncat(char *dest, const char *src, unsigned int n); char *strcat(char *dest, const char *src); +void strreverse(char s[]); +void itoa(int n, char s[]); + #endif /* __STRING_H */ diff --git a/armsrc/util.c b/armsrc/util.c index b0cd1818..905bad25 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -12,30 +12,9 @@ #include "util.h" #include "string.h" #include "apps.h" -#include "BigBuf.h" - - - -void print_result(char *name, uint8_t *buf, size_t len) { - uint8_t *p = buf; - - if ( len % 16 == 0 ) { - for(; p-buf < len; p += 16) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - name, - p-buf, - len, - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15] - ); - } - else { - for(; p-buf < len; p += 8) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - } -} size_t nbytes(size_t nbits) { - return (nbits >> 3)+((nbits % 8) > 0); + return (nbits/8)+((nbits%8)>0); } uint32_t SwapBits(uint32_t value, int nrbits) { @@ -66,21 +45,6 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } -// RotateLeft - Ultralight, Desfire -void rol(uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; -} -void lsl (uint8_t *data, size_t len) { - for (size_t n = 0; n < len - 1; n++) { - data[n] = (data[n] << 1) | (data[n+1] >> 7); - } - data[len - 1] <<= 1; -} - void LEDsoff() { LED_A_OFF(); @@ -89,22 +53,6 @@ void LEDsoff() LED_D_OFF(); } -void LEDson() -{ - LED_A_ON(); - LED_B_ON(); - LED_C_ON(); - LED_D_ON(); -} - -void LEDsinvert() -{ - LED_A_INV(); - LED_B_INV(); - LED_C_INV(); - LED_D_INV(); -} - // LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8] void LED(int led, int ms) { @@ -137,7 +85,8 @@ void LED(int led, int ms) // not clicked, or held down (for ms || 1sec) // In general, don't use this function unless you expect a // double click, otherwise it will waste 500ms -- use BUTTON_HELD instead -int BUTTON_CLICKED(int ms) { +int BUTTON_CLICKED(int ms) +{ // Up to 500ms in between clicks to mean a double click int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -199,7 +148,8 @@ int BUTTON_CLICKED(int ms) { } // Determine if a button is held down -int BUTTON_HELD(int ms) { +int BUTTON_HELD(int ms) +{ // If button is held for one second int ticks = (48000 * (ms ? ms : 1000)) >> 10; @@ -216,7 +166,8 @@ int BUTTON_HELD(int ms) { uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - for(;;) { + for(;;) + { uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; // As soon as our button let go, we didn't hold long enough @@ -224,7 +175,8 @@ int BUTTON_HELD(int ms) { return BUTTON_SINGLE_CLICK; // Have we waited the full second? - else if (now == (uint16_t)(start + ticks)) + else + if (now == (uint16_t)(start + ticks)) return BUTTON_HOLD; WDT_HIT(); @@ -236,7 +188,8 @@ int BUTTON_HELD(int ms) { // attempt at high resolution microsecond timer // beware: timer counts in 21.3uS increments (1024/48Mhz) -void SpinDelayUs(int us) { +void SpinDelayUs(int us) +{ int ticks = (48*us) >> 10; // Borrow a PWM unit for my real-time clock @@ -257,7 +210,8 @@ void SpinDelayUs(int us) { } } -void SpinDelay(int ms) { +void SpinDelay(int ms) +{ // convert to uS and call microsecond delay function SpinDelayUs(ms*1000); } @@ -271,67 +225,64 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers { struct version_information *v = (struct version_information*)version_information; dst[0] = 0; - strncat(dst, prefix, len-1); + strncat(dst, prefix, len); if(v->magic != VERSION_INFORMATION_MAGIC) { - strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1); + strncat(dst, "Missing/Invalid version information", len); return; } if(v->versionversion != 1) { - strncat(dst, "Version information not understood\n", len - strlen(dst) - 1); + strncat(dst, "Version information not understood", len); return; } if(!v->present) { - strncat(dst, "Version information not available\n", len - strlen(dst) - 1); + strncat(dst, "Version information not available", len); return; } - strncat(dst, v->gitversion, len - strlen(dst) - 1); + strncat(dst, v->svnversion, len); if(v->clean == 0) { - strncat(dst, "-unclean", len - strlen(dst) - 1); + strncat(dst, "-unclean", len); } else if(v->clean == 2) { - strncat(dst, "-suspect", len - strlen(dst) - 1); + strncat(dst, "-suspect", len); } - strncat(dst, " ", len - strlen(dst) - 1); - strncat(dst, v->buildtime, len - strlen(dst) - 1); - strncat(dst, "\n", len - strlen(dst) - 1); + strncat(dst, " ", len); + strncat(dst, v->buildtime, len); } - // ------------------------------------------------------------------------- // timer lib // ------------------------------------------------------------------------- // test procedure: // -// ti = GetTickCount(); -// SpinDelay(1000); -// ti = GetTickCount() - ti; -// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); +// ti = GetTickCount(); +// SpinDelay(1000); +// ti = GetTickCount() - ti; +// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); -void StartTickCount() { - // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. - // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. - uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency - // set RealTimeCounter divider to count at 1kHz: - AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf); - // note: worst case precision is approx 2.5% +void StartTickCount() +{ +// must be 0x40, but on my cpu - included divider is optimal +// 0x20 - 1 ms / bit +// 0x40 - 2 ms / bit + + AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST + 0x001D; // was 0x003B } - /* * Get the current count. */ -uint32_t RAMFUNC GetTickCount(void) { +uint32_t RAMFUNC GetTickCount(){ return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; } - // ------------------------------------------------------------------------- -// microseconds timer +// microseconds timer // ------------------------------------------------------------------------- -void StartCountUS(void) { +void StartCountUS() +{ AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); -// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; +// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; // fast clock @@ -341,24 +292,22 @@ void StartCountUS(void) { AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; AT91C_BASE_TC0->TC_RA = 1; AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000 - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0 - + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TCB->TCB_BCR = 1; } - -uint32_t RAMFUNC GetCountUS(void) { - return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10); +uint32_t RAMFUNC GetCountUS(){ + return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); } - static uint32_t GlobalUsCounter = 0; -uint32_t RAMFUNC GetDeltaCountUS(void) { +uint32_t RAMFUNC GetDeltaCountUS(){ uint32_t g_cnt = GetCountUS(); uint32_t g_res = g_cnt - GlobalUsCounter; GlobalUsCounter = g_cnt; @@ -367,201 +316,76 @@ uint32_t RAMFUNC GetDeltaCountUS(void) { // ------------------------------------------------------------------------- -// Timer for iso14443 commands. Uses ssp_clk from FPGA +// Timer for iso14443 commands. Uses ssp_clk from FPGA // ------------------------------------------------------------------------- -void StartCountSspClk(void) { +void StartCountSspClk() +{ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 - | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none - | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 + | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none + | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 // configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs: - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz - | AT91C_TC_CPCSTOP // Stop clock on RC compare - | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event - | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4) - | AT91C_TC_ENETRG // Enable external trigger event - | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_AEEVT_SET // Set TIOA1 on external event - | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 1; // RC Compare value = 1; pulse width to TC0 + | AT91C_TC_CPCSTOP // Stop clock on RC compare + | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event + | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) + | AT91C_TC_ENETRG // Enable external trigger event + | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_AEEVT_SET // Set TIOA1 on external event + | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare + AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04 // use TC0 to count TIOA1 pulses - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP // just count - | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare - | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare - AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 - AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP // just count + | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare + | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare + AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 + AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow // use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk) - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 - AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP; // just count - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1 - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 + AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP; // just count + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2 // - // synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present + // synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14446 mode, otherwise the frame signal would not be present // - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame - if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame - } + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high + // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge - AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) - // at the next (3rd/7th) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) - // at the next (4th/8th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, - // whenever the last three/four bits of our counter go 0, we can be sure to be in the middle of a frame transfer. - + AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) + // at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) + // at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, + // whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer. + // (just started with the transfer of the 4th Bit). // The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before // we can use the counter. - while (AT91C_BASE_TC0->TC_CV < 0xFFFF); - // Note: needs one more SSP_CLK cycle (1.18 us) until TC2 resets. Don't call GetCountSspClk() that soon. + while (AT91C_BASE_TC0->TC_CV < 0xFFF0); } -void ResetSspClk(void) { - //enable clock of timer and software trigger - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC2->TC_CV > 0); -} - -uint32_t GetCountSspClk(){ - uint32_t hi, lo; - - do { - hi = AT91C_BASE_TC2->TC_CV; - lo = AT91C_BASE_TC0->TC_CV; - } while (hi != AT91C_BASE_TC2->TC_CV); - - return (hi << 16) | lo; -} - -// ------------------------------------------------------------------------- -// Timer for bitbanging, or LF stuff when you need a very precis timer -// 1us = 1.5ticks -// ------------------------------------------------------------------------- -void StartTicks(void){ - // initialization of the timer - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; - - // disable TC0 and TC1 for re-configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // first configure TC1 (higher, 0xFFFF0000) 16 bit counter - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 - - // second configure TC0 (lower, 0x0000FFFF) 16 bit counter - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 - AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | - AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) - AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit) - AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) - AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero - AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer - - // synchronized startup procedure - while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero - while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared) - - // return to zero - AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); -} - - -uint32_t GetTicks(void) { - uint32_t hi, lo; - - do { - hi = AT91C_BASE_TC1->TC_CV; - lo = AT91C_BASE_TC0->TC_CV; - } while(hi != AT91C_BASE_TC1->TC_CV); - - return (hi << 16) | lo; -} - - -// Wait - Spindelay in ticks. -// if called with a high number, this will trigger the WDT... -void WaitTicks(uint32_t ticks){ - if ( ticks == 0 ) return; - ticks += GetTicks(); - while (GetTicks() < ticks); -} - - -// Wait / Spindelay in us (microseconds) -// 1us = 1.5ticks. -void WaitUS(uint16_t us){ - WaitTicks( (uint32_t)us * 3 / 2 ) ; -} - - -void WaitMS(uint16_t ms){ - WaitTicks( (uint32_t)ms * 1500 ); -} - - -// Starts Clock and waits until its reset -void ResetTicks(void){ - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV > 0); -} - - -void ResetTimer(AT91PS_TC timer){ - timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while(timer->TC_CV > 0) ; -} - - -// stop clock -void StopTicks(void){ - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; -} - - -static uint64_t next_random = 1; - -/* Generates a (non-cryptographically secure) 32-bit random number. - * - * We don't have an implementation of the "rand" function or a clock to seed it - * with, so we just call GetTickCount the first time to seed ourselves. - */ -uint32_t prand() { - if (next_random == 1) { - next_random = GetTickCount(); +uint32_t RAMFUNC GetCountSspClk(){ + uint32_t tmp_count; + tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; + if ((tmp_count & 0x0000ffff) == 0) { //small chance that we may have missed an increment in TC2 + return (AT91C_BASE_TC2->TC_CV << 16); + } + else { + return tmp_count; } - - next_random = next_random * 6364136223846793005 + 1; - return (uint32_t)(next_random >> 32) % 0xffffffff; } + + diff --git a/armsrc/util.h b/armsrc/util.h index bdb7fafd..e8b9cdff 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -8,77 +8,46 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#ifndef UTIL_H__ -#define UTIL_H__ +#ifndef __UTIL_H +#define __UTIL_H #include #include -#include "common.h" -#include "at91sam7s512.h" +#include #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) -#define LED_RED 1 +#define LED_RED 1 #define LED_ORANGE 2 -#define LED_GREEN 4 -#define LED_RED2 8 +#define LED_GREEN 4 +#define LED_RED2 8 +#define BUTTON_HOLD 1 +#define BUTTON_NO_CLICK 0 +#define BUTTON_SINGLE_CLICK -1 +#define BUTTON_DOUBLE_CLICK -2 +#define BUTTON_ERROR -99 -#define BUTTON_HOLD 1 -#define BUTTON_NO_CLICK 0 -#define BUTTON_SINGLE_CLICK -1 -#define BUTTON_DOUBLE_CLICK -2 -#define BUTTON_ERROR -99 +size_t nbytes(size_t nbits); +uint32_t SwapBits(uint32_t value, int nrbits); +void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +uint64_t bytes_to_num(uint8_t* src, size_t len); -#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7)) -#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8)) -#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16)) -#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32)) +void SpinDelay(int ms); +void SpinDelayUs(int us); +void LED(int led, int ms); +void LEDsoff(); +int BUTTON_CLICKED(int ms); +int BUTTON_HELD(int ms); +void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); -extern void print_result(char *name, uint8_t *buf, size_t len); -extern size_t nbytes(size_t nbits); -extern uint32_t SwapBits(uint32_t value, int nrbits); -extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); -extern uint64_t bytes_to_num(uint8_t* src, size_t len); -extern void rol(uint8_t *data, const size_t len); -extern void lsl (uint8_t *data, size_t len); +void StartTickCount(); +uint32_t RAMFUNC GetTickCount(); -extern void LED(int led, int ms); -extern void LEDsoff(); -extern void LEDson(); -extern void LEDsinvert(); -extern int BUTTON_CLICKED(int ms); -extern int BUTTON_HELD(int ms); -extern void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); +void StartCountUS(); +uint32_t RAMFUNC GetCountUS(); +uint32_t RAMFUNC GetDeltaCountUS(); -//iceman's ticks.h -#ifndef GET_TICKS -# define GET_TICKS GetTicks() -#endif - -extern void SpinDelay(int ms); -extern void SpinDelayUs(int us); - -extern void StartTickCount(); -extern uint32_t RAMFUNC GetTickCount(); - -extern void StartCountUS(); -extern uint32_t RAMFUNC GetCountUS(); -extern uint32_t RAMFUNC GetDeltaCountUS(); - -extern void StartCountSspClk(); -extern void ResetSspClk(void); -extern uint32_t GetCountSspClk(); - -extern void StartTicks(void); -extern uint32_t GetTicks(void); -extern void WaitTicks(uint32_t ticks); -extern void WaitUS(uint16_t us); -extern void WaitMS(uint16_t ms); -extern void ResetTicks(); -extern void ResetTimer(AT91PS_TC timer); -extern void StopTicks(void); -// end iceman's ticks.h - -extern uint32_t prand(); +void StartCountSspClk(); +uint32_t RAMFUNC GetCountSspClk(); #endif diff --git a/bootrom/Makefile b/bootrom/Makefile index a2cd1b40..92373995 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -7,10 +7,9 @@ #----------------------------------------------------------------------------- # DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code -ARMSRC = string.c -THUMBSRC = usb_cdc.c bootrom.c +ARMSRC = +THUMBSRC = cmd.c usb_cdc.c bootrom.c ASMSRC = ram-reset.s flash-reset.s -VERSIONSRC = version.c ## There is a strange bug with the linker: Sometimes it will not emit the glue to call ## BootROM from ARM mode. The symbol is emitted, but the section will be filled with @@ -19,13 +18,9 @@ VERSIONSRC = version.c # ARMSRC := $(ARMSRC) $(THUMBSRC) # THUMBSRC := +# stdint.h provided locally until GCC 4.5 becomes C99 compliant APP_CFLAGS = -I. -# version.c should be remade on every compilation -.PHONY: version.c -version.c: default_version.c - perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@ - # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC include ../common/Makefile.common diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c index 81742176..0c4831c8 100644 --- a/bootrom/bootrom.c +++ b/bootrom/bootrom.c @@ -6,15 +6,17 @@ // Main code for the bootloader //----------------------------------------------------------------------------- -#include "proxmark3.h" +#include #include "usb_cdc.h" +#include "cmd.h" +//#include "usb_hid.h" void DbpString(char *str) { - uint8_t len = 0; + byte_t len = 0; while (str[len] != 0x00) { len++; } - cmd_send_old(CMD_DEBUG_PRINT_STRING,len,0,0,(uint8_t*)str,len); + cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len); } struct common_area common_area __attribute__((section(".commonarea"))); @@ -87,22 +89,28 @@ static void Fatal(void) for(;;); } -void UsbPacketReceived(UsbCommand *c) { +void UsbPacketReceived(uint8_t *packet, int len) { int i, dont_ack=0; + UsbCommand* c = (UsbCommand *)packet; volatile uint32_t *p; + if(len != sizeof(UsbCommand)) { + Fatal(); + } + uint32_t arg0 = (uint32_t)c->arg[0]; switch(c->cmd) { case CMD_DEVICE_INFO: { dont_ack = 1; - arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT - | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM - | DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH; +// c->cmd = CMD_DEVICE_INFO; + arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM | + DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH; if(common_area.flags.osimage_present) { arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT; } - cmd_send_old(CMD_DEVICE_INFO,arg0,1,2,0,0); +// UsbSendPacket(packet, len); + cmd_send(CMD_DEVICE_INFO,arg0,1,2,0,0); } break; case CMD_SETUP_WRITE: { @@ -117,8 +125,10 @@ void UsbPacketReceived(UsbCommand *c) { case CMD_FINISH_WRITE: { uint32_t* flash_mem = (uint32_t*)(&_flash_start); +// p = (volatile uint32_t *)&_flash_start; for (size_t j=0; j<2; j++) { for(i = 0+(64*j); i < 64+(64*j); i++) { + //p[i+60] = c->d.asDwords[i]; flash_mem[i] = c->d.asDwords[i]; } @@ -128,13 +138,16 @@ void UsbPacketReceived(UsbCommand *c) { if( ((flash_address+AT91C_IFLASH_PAGE_SIZE-1) >= end_addr) || (flash_address < start_addr) ) { /* Disallow write */ dont_ack = 1; - cmd_send_old(CMD_NACK,0,0,0,0,0); + // c->cmd = CMD_NACK; + // UsbSendPacket(packet, len); + cmd_send(CMD_NACK,0,0,0,0,0); } else { uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE; /* Translate address to flash page and do flash, update here for the 512k part */ AT91C_BASE_EFC0->EFC_FCR = MC_FLASH_COMMAND_KEY | MC_FLASH_COMMAND_PAGEN(page_n) | AT91C_MC_FCMD_START_PROG; + // arg0 = (address - ((uint32_t)flash_s)); } // Wait until flashing of page finishes @@ -142,12 +155,15 @@ void UsbPacketReceived(UsbCommand *c) { while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY)); if(sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { dont_ack = 1; - cmd_send_old(CMD_NACK,0,0,0,0,0); + // c->cmd = CMD_NACK; + cmd_send(CMD_NACK,0,0,0,0,0); + // UsbSendPacket(packet, len); } } } break; case CMD_HARDWARE_RESET: { +// USB_D_PLUS_PULLUP_OFF(); usb_disable(); AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; } break; @@ -173,7 +189,9 @@ void UsbPacketReceived(UsbCommand *c) { } else { start_addr = end_addr = 0; dont_ack = 1; - cmd_send_old(CMD_NACK,0,0,0,0,0); +// c->cmd = CMD_NACK; +// UsbSendPacket(packet, len); + cmd_send(CMD_NACK,0,0,0,0,0); } } } break; @@ -184,7 +202,9 @@ void UsbPacketReceived(UsbCommand *c) { } if(!dont_ack) { - cmd_send_old(CMD_ACK,arg0,0,0,0,0); +// c->cmd = CMD_ACK; +// UsbSendPacket(packet, len); + cmd_send(CMD_ACK,arg0,0,0,0,0); } } @@ -193,20 +213,29 @@ static void flash_mode(int externally_entered) start_addr = 0; end_addr = 0; bootrom_unlocked = 0; - UsbCommand rx; + byte_t rx[sizeof(UsbCommand)]; + size_t rx_len; - usb_enable(); - for (volatile size_t i=0; i<0x100000; i++) {}; + usb_enable(); + for (volatile size_t i=0; i<0x100000; i++); +// UsbStart(); for(;;) { WDT_HIT(); - if (cmd_receive(&rx)) { - UsbPacketReceived(&rx); - } + if (usb_poll()) { + rx_len = usb_read(rx,sizeof(UsbCommand)); + if (rx_len) { +// DbpString("starting to flash"); + UsbPacketReceived(rx,rx_len); + } + } + +// UsbPoll(TRUE); if(!externally_entered && !BUTTON_PRESS()) { /* Perform a reset to leave flash mode */ +// USB_D_PLUS_PULLUP_OFF(); usb_disable(); LED_B_ON(); AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST; diff --git a/bootrom/string.c b/bootrom/string.c deleted file mode 100644 index b2710d07..00000000 --- a/bootrom/string.c +++ /dev/null @@ -1,104 +0,0 @@ -//----------------------------------------------------------------------------- -// Jonathan Westhues, Sept 2005 -// -// 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. -//----------------------------------------------------------------------------- -// Common string.h functions -//----------------------------------------------------------------------------- - -#include "string.h" -#include - -void *memcpy(void *dest, const void *src, size_t len) { - uint8_t *d = dest; - const uint8_t *s = src; - while((len--) > 0) { - *d = *s; - d++; - s++; - } - return dest; -} - - -void *memset(void *dest, int c, size_t len) { - uint8_t *d = dest; - while((len--) > 0) { - *d = c; - d++; - } - return dest; -} - - -void *memmove(void *dest, const void *src, size_t len) { - uint8_t *d = dest; - const uint8_t *s = src; - if (dest <= src) { - while((len--) > 0) { - *d = *s; - d++; - s++; - } - } else { - d = d + len - 1; - s = s + len - 1; - while((len--) > 0) { - *d = *s; - d--; - s--; - } - } - return dest; -} - - -int memcmp(const void *av, const void *bv, size_t len) { - const uint8_t *a = av; - const uint8_t *b = bv; - - while((len--) > 0) { - if(*a != *b) { - return *a - *b; - } - a++; - b++; - } - return 0; -} - - -size_t strlen(const char *str) { - int l = 0; - while(*str) { - l++; - str++; - } - return l; -} - - -char* strncat(char *dest, const char *src, size_t n) { - unsigned int dest_len = strlen(dest); - unsigned int i; - - for (i = 0 ; i < n && src[i] != '\0' ; i++) - dest[dest_len + i] = src[i]; - dest[dest_len + i] = '\0'; - - return dest; -} - - -char* strcat(char *dest, const char *src) { - unsigned int dest_len = strlen(dest); - unsigned int i; - - for (i = 0 ; src[i] != '\0' ; i++) - dest[dest_len + i] = src[i]; - dest[dest_len + i] = '\0'; - - return dest; -} diff --git a/client/Info.plist b/client/Info.plist new file mode 100644 index 00000000..d1f87572 --- /dev/null +++ b/client/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion English + CFBundleIdentifier org.proxmark + CFBundleIconFile + CFBundleInfoDictionaryVersion 6.0 + CFBundlePackageType KEXT + CFBundleSignature ???? + CFBundleVersion 1.0.0 + IOKitPersonalities + + Proxmark3 + + CFBundleIdentifiercom.apple.kernel.iokit + IOClassIOService + IOProviderClassIOUSBInterface + bConfigurationValue 1 + bInterfaceNumber 0 + idProduct19343 + idVendor39620 + + + OSBundleLibraries + + com.apple.iokit.IOUSBFamily1.8 + + + diff --git a/client/Makefile b/client/Makefile index 2b5e9ae6..6d75b4bb 100644 --- a/client/Makefile +++ b/client/Makefile @@ -3,178 +3,68 @@ # at your option, any later version. See the LICENSE.txt file for the text of # the license. #----------------------------------------------------------------------------- +include ../common/Makefile.common -CC = gcc -CXX = g++ -LD = g++ -TAR = tar -TARFLAGS = -C .. --ignore-failed-read -rvf -RM = rm -f -MV = mv -ENV_LDFLAGS := $(LDFLAGS) -ENV_CFLAGS := $(CFLAGS) -VPATH = ../common ../zlib ../uart +CC=gcc +CXX=g++ +#COMMON_FLAGS = -m32 + +VPATH = ../common OBJDIR = obj -LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm -LUALIB = ../liblua/liblua.a -JANSSONLIBPATH = ./jansson -JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a -MBEDTLSLIBPATH = ../common/mbedtls -MBEDTLSLIB = $(MBEDTLSLIBPATH)/libmbedtls.a -CBORLIBPATH = ./tinycbor -CBORLIB = $(CBORLIBPATH)/tinycbor.a -LIBINCLUDES = -I../zlib -I../uart -I../liblua -I$(MBEDTLSLIBPATH) -I$(JANSSONLIBPATH) -I$(CBORLIBPATH) -INCLUDES_CLIENT = -I. -I../include -I../common -I/opt/local/include $(LIBINCLUDES) -LDFLAGS = $(ENV_LDFLAGS) -CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE $(INCLUDES_CLIENT) -Wall -g -O3 -CXXFLAGS = -I../include -Wall -O3 - -APP_CFLAGS = -include ../common/Makefile_Enabled_Options.common -CFLAGS += $(APP_CFLAGS) -ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS))) - SRC_SMARTCARD = cmdsmartcard.c pcsc.c -else - SRC_SMARTCARD = -endif - -platform = $(shell uname) - -ifneq (,$(findstring MINGW,$(platform))) - PCSC_INCLUDES := - PCSC_LIBS = -lwinscard -else - ifeq ($(platform),Darwin) - PCSC_INCLUDES = - PCSC_LIBS = -framework PCSC - else - PCSC_INCLUDES := $(shell pkg-config --cflags libpcsclite) - PCSC_LIBS := $(shell pkg-config --libs libpcsclite) - endif -endif - +LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread ../liblua/liblua.a +LDFLAGS = $(COMMON_FLAGS) +CFLAGS = -std=c99 -I. -I../include -I../common -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O4 LUAPLATFORM = generic + ifneq (,$(findstring MINGW,$(platform))) - LUAPLATFORM = mingw +CXXFLAGS = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui +QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 +MOC = $(QTDIR)/bin/moc +LUAPLATFORM = mingw +else ifeq ($(platform),Darwin) +CXXFLAGS = -I/Library/Frameworks/QtGui.framework/Versions/Current/Headers -I/Library/Frameworks/QtCore.framework/Versions/Current/Headers +QTLDLIBS = -framework QtGui -framework QtCore +MOC = moc +LUAPLATFORM = macosx else - ifeq ($(platform),Darwin) - LUAPLATFORM = macosx - OBJCSRCS = util_darwin.m - LDFLAGS += -framework Foundation -framework AppKit - else - LUALIB += -ldl - LDLIBS += -ltermcap -lncurses - LUAPLATFORM = linux - endif -endif +CXXFLAGS = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) -Wall -O4 +QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) +MOC = $(shell pkg-config --variable=moc_location QtCore) +LDLIBS += -ldl -ifneq (,$(findstring WITH_GUI,$(APP_CFLAGS))) - # Check for correctly configured Qt5 - QTINCLUDES = $(shell pkg-config --cflags Qt5Core Qt5Widgets 2>/dev/null) - QTLDLIBS = $(shell pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null) - MOC = $(shell pkg-config --variable=host_bins Qt5Core)/moc - UIC = $(shell pkg-config --variable=host_bins Qt5Core)/uic - ifeq ($(QTINCLUDES), ) - # if Qt5 not found check for correctly configured Qt4 - QTINCLUDES = $(shell pkg-config --cflags QtCore QtGui 2>/dev/null) - QTLDLIBS = $(shell pkg-config --libs QtCore QtGui 2>/dev/null) - MOC = $(shell pkg-config --variable=moc_location QtCore) - UIC = $(shell pkg-config --variable=uic_location QtCore) - else - CXXFLAGS += -std=c++11 -fPIC - endif - ifeq ($(QTINCLUDES), ) - # if both pkg-config commands failed, search in common places - ifneq ($(QTDIR), ) - QTINCLUDES = -I$(QTDIR)/include -I$(QTDIR)/include/QtCore -I$(QTDIR)/include/QtGui - QTLDLIBS = -L$(QTDIR)/lib -lQtCore4 -lQtGui4 - ifneq ($(wildcard $(QTDIR)/include/QtWidgets),) - QTINCLUDES += -I$(QTDIR)/include/QtWidgets - QTLDLIBS = -L$(QTDIR)/lib -lQt5Widgets -lQt5Gui -lQt5Core - CXXFLAGS += -std=c++11 -fPIC - endif - MOC = $(QTDIR)/bin/moc - UIC = $(QTDIR)/bin/uic - endif - endif +# Below is a variant you can use if you have problems compiling with QT5 on ubuntu. see http://www.proxmark.org/forum/viewtopic.php?id=1661 for more info. +#MOC = /usr/lib/x86_64-linux-gnu/qt4/bin/moc +LUAPLATFORM = linux endif -ifneq ($(QTLDLIBS), ) - QTGUIOBJS = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o - CFLAGS += -DHAVE_GUI +ifneq ($(QTLDLIBS),) +QTGUI = $(OBJDIR)/proxgui.o $(OBJDIR)/proxguiqt.o $(OBJDIR)/proxguiqt.moc.o +CFLAGS += -DHAVE_GUI +LINK.o = $(LINK.cpp) else - QTGUIOBJS = $(OBJDIR)/guidummy.o +QTGUI = guidummy.o endif -# Flags to generate temporary dependency files -DEPFLAGS = -MT $@ -MMD -MP -MF $(OBJDIR)/$*.Td -# make temporary to final dependeny files after successful compilation -POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d +CORESRCS = uart.c \ + util.c \ + sleep.c -CORESRCS = uart_posix.c \ - uart_win32.c \ - util.c \ - util_posix.c \ - ui.c \ - comms.c - -CMDSRCS = $(SRC_SMARTCARD) \ - crapto1/crapto1.c\ - crapto1/crypto1.c\ - crypto/libpcrypto.c\ - crypto/asn1utils.c\ - crypto/asn1dump.c\ - cliparser/argtable3.c\ - cliparser/cliparser.c\ - fido/additional_ca.c \ - fido/cose.c \ - fido/cbortools.c \ - fido/fidocore.c \ - mifare/mfkey.c \ - loclass/cipher.c \ - loclass/cipherutils.c \ - loclass/ikeys.c \ - loclass/elite_crack.c\ - loclass/fileutils.c\ - whereami.c\ - mifare/mifarehost.c\ - mifare/mifare4.c\ - mifare/mad.c \ - mifare/ndef.c \ - parity.c\ - crc.c \ +CMDSRCS = nonce2key/crapto1.c\ + nonce2key/crypto1.c\ + nonce2key/nonce2key.c\ + mifarehost.c\ crc16.c \ - crc64.c \ iso14443crc.c \ iso15693tools.c \ + data.c \ graph.c \ + ui.c \ cmddata.c \ - lfdemod.c \ - emv/crypto_polarssl.c\ - emv/crypto.c\ - emv/emv_pk.c\ - emv/emv_pki.c\ - emv/emv_pki_priv.c\ - emv/test/cryptotest.c\ - emv/apduinfo.c\ - emv/dump.c\ - emv/tlv.c\ - emv/emv_tags.c\ - emv/dol.c\ - emv/emvjson.c\ - emv/emvcore.c\ - emv/test/crypto_test.c\ - emv/test/sda_test.c\ - emv/test/dda_test.c\ - emv/test/cda_test.c\ - emv/cmdemv.c\ - emv/emv_roca.c \ cmdhf.c \ - cmdhflist.c \ cmdhf14a.c \ cmdhf14b.c \ cmdhf15.c \ @@ -182,200 +72,77 @@ CMDSRCS = $(SRC_SMARTCARD) \ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ - cmdhfmfp.c \ - cmdhfmfu.c \ - cmdhfmfhard.c \ - hardnested/hardnested_bruteforce.c \ - cmdhftopaz.c \ - cmdhffido.c \ cmdhw.c \ cmdlf.c \ - cmdlfawid.c \ - cmdlfcotag.c\ - cmdlfem4x.c \ - cmdlffdx.c \ - cmdlfgproxii.c \ - hidcardformatutils.c\ - hidcardformats.c\ cmdlfhid.c \ - cmdlfhitag.c \ cmdlfio.c \ - cmdlfindala.c \ - cmdlfjablotron.c \ - cmdlfnexwatch.c \ - cmdlfnoralsy.c \ - cmdlfparadox.c \ - cmdlfpcf7931.c \ - cmdlfpresco.c \ - cmdlfpyramid.c \ - cmdlfsecurakey.c \ - cmdlft55xx.c \ + cmdlfem4x.c \ + cmdlfhitag.c \ cmdlfti.c \ - cmdlfviking.c\ - cmdlfvisa2000.c\ - cmdlfpac.c\ cmdparser.c \ cmdmain.c \ + cmdlft55xx.c \ + cmdlfpcf7931.c\ + pm3_binlib.c\ scripting.c\ cmdscript.c\ - pm3_binlib.c\ pm3_bitlib.c\ - protocols.c\ - taginfo.c -cpu_arch = $(shell uname -m) -ifneq ($(findstring 86, $(cpu_arch)), ) - MULTIARCHSRCS = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c -endif -ifneq ($(findstring amd64, $(cpu_arch)), ) - MULTIARCHSRCS = hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c -endif -ifeq ($(MULTIARCHSRCS), ) - CMDSRCS += hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c -endif - -ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c -ZLIBFLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED -#-DDEBUG -Dverbose=1 - -QTGUISRCS = proxgui.cpp proxguiqt.cpp proxguiqt.moc.cpp guidummy.cpp COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o) CMDOBJS = $(CMDSRCS:%.c=$(OBJDIR)/%.o) -OBJCOBJS = $(OBJCSRCS:%.m=$(OBJDIR)/%.o) -ZLIBOBJS = $(ZLIBSRCS:%.c=$(OBJDIR)/%.o) -MULTIARCHOBJS = $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_NOSIMD.o) \ - $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_MMX.o) \ - $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_SSE2.o) \ - $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX.o) \ - $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX2.o) -SUPPORTS_AVX512 := $(shell echo | gcc -E -mavx512f - > /dev/null 2>&1 && echo "True" ) -HARD_SWITCH_NOSIMD = -mno-mmx -mno-sse2 -mno-avx -mno-avx2 -HARD_SWITCH_MMX = -mmmx -mno-sse2 -mno-avx -mno-avx2 -HARD_SWITCH_SSE2 = -mmmx -msse2 -mno-avx -mno-avx2 -HARD_SWITCH_AVX = -mmmx -msse2 -mavx -mno-avx2 -HARD_SWITCH_AVX2 = -mmmx -msse2 -mavx -mavx2 -HARD_SWITCH_AVX512 = -mmmx -msse2 -mavx -mavx2 -mavx512f -ifeq "$(SUPPORTS_AVX512)" "True" - HARD_SWITCH_NOSIMD += -mno-avx512f - HARD_SWITCH_MMX += -mno-avx512f - HARD_SWITCH_SSE2 += -mno-avx512f - HARD_SWITCH_AVX += -mno-avx512f - HARD_SWITCH_AVX2 += -mno-avx512f - MULTIARCHOBJS += $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX512.o) -endif - -BINS = proxmark3 flasher fpga_compress -WINBINS = $(patsubst %, %.exe, $(BINS)) -CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua +RM = rm -f +BINS = proxmark3 flasher #snooper cli +CLEAN = cli cli.exe flasher flasher.exe proxmark3 proxmark3.exe snooper snooper.exe $(CMDOBJS) $(OBJDIR)/*.o *.o *.moc.cpp -# need to assign dependancies to build these first... -all: lua_build jansson_build mbedtls_build cbor_build $(BINS) +all: lua_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) -all-static: proxmark3 flasher fpga_compress +all-static: snooper cli flasher + +proxmark3: LDLIBS+=$(QTLDLIBS) +proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUI) + $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@ -proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) $(PCSC_LIBS) -proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua - $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ +snooper: $(OBJDIR)/snooper.o $(COREOBJS) $(CMDOBJS) $(OBJDIR)/guidummy.o + $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@ -flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS) $(OBJCOBJS) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ +cli: $(OBJDIR)/cli.o $(COREOBJS) $(CMDOBJS) $(OBJDIR)/guidummy.o + $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@ -fpga_compress: $(OBJDIR)/fpga_compress.o $(ZLIBOBJS) - $(LD) $(LDFLAGS) $(ZLIBFLAGS) $^ $(LDLIBS) -o $@ +flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS) + $(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $@ -proxgui.cpp: ui/ui_overlays.h +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +$(OBJDIR)/%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< proxguiqt.moc.cpp: proxguiqt.h $(MOC) -o$@ $^ -ui/ui_overlays.h: ui/overlays.ui - $(UIC) $^ > $@ - -lualibs/usb_cmd.lua: ../include/usb_cmd.h - awk -f usb_cmd_h2lua.awk $^ > $@ - clean: $(RM) $(CLEAN) cd ../liblua && make clean - cd $(JANSSONLIBPATH) && make clean - cd $(MBEDTLSLIBPATH) && make clean - cd $(CBORLIBPATH) && make clean tarbin: $(BINS) - $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) + $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) + +# must be run as root +install_kext: Info.plist + mkdir -p /System/Library/Extensions/Proxmark3.kext/Contents + cp Info.plist /System/Library/Extensions/Proxmark3.kext/Contents + chown -R root:wheel /System/Library/Extensions/Proxmark3.kext + chmod 755 /System/Library/Extensions/Proxmark3.kext /System/Library/Extensions/Proxmark3.kext/Contents + chmod 644 /System/Library/Extensions/Proxmark3.kext/Contents/Info.plist + rm -rf /System/Library/Caches/com.apple.kext.caches + touch /System/Library/Extensions + @echo "*** You may need to reboot for the kext to take effect." lua_build: @echo Compiling liblua, using platform $(LUAPLATFORM) cd ../liblua && make $(LUAPLATFORM) - -jansson_build: - @echo Compiling jansson - cd $(JANSSONLIBPATH) && make all - -mbedtls_build: - @echo Compiling mbedtls - cd $(MBEDTLSLIBPATH) && make all - -cbor_build: - @echo Compiling tinycbor - cd $(CBORLIBPATH) && make all - + .PHONY: all clean - -$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_NOSIMD) -c -o $@ $< - -$(OBJDIR)/%_MMX.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_MMX) -c -o $@ $< - -$(OBJDIR)/%_SSE2.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $< - -$(OBJDIR)/%_AVX.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $< - -$(OBJDIR)/%_AVX2.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $< - -$(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $< - -%.o: %.c -$(OBJDIR)/%.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) $(PCSC_INCLUDES) -c -o $@ $< - $(POSTCOMPILE) - -%.o: %.cpp -$(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d - $(CXX) $(DEPFLAGS) $(CXXFLAGS) $(QTINCLUDES) -c -o $@ $< - $(POSTCOMPILE) - -%.o: %.m -$(OBJDIR)/%.o : %.m $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $< - $(POSTCOMPILE) - -#$(CMDOBJS) $(COREOBJS): $(notdir $(%.c)) %.d -# $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $< -# $(POSTCOMPILE) - -#$(ZLIBOBJS): $(notdir $(%.c)) %.d -# $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $< -# $(POSTCOMPILE) - -#$(QTGUIOBJS): $(notdir $(%.cpp)) %.d -# $(CXX) $(DEPFLAGS) $(CXXFLAGS) -c -o $@ $< -# $(POSTCOMPILE) - -DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBSRCS) $(MULTIARCHSRCS)) \ - $(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \ - $(patsubst %.m, $(OBJDIR)/%.d, $(OBJCSRCS)) \ - $(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d - -$(DEPENDENCY_FILES): ; -.PRECIOUS: $(DEPENDENCY_FILES) - --include $(DEPENDENCY_FILES) diff --git a/client/cli.c b/client/cli.c new file mode 100644 index 00000000..c5c2acf4 --- /dev/null +++ b/client/cli.c @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Command line binary +//----------------------------------------------------------------------------- + +#include +#include "sleep.h" +#include "ui.h" +#include "proxusb.h" +#include "cmdmain.h" + +#define HANDLE_ERROR if (error_occured) { \ + error_occured = 0;\ + break;\ +} + +int main(int argc, char **argv) +{ + if (argc != 3 && argc != 4) + { + printf("\n\tusage: cli [logfile (default cli.log)]\n"); + printf("\n"); + printf("\texample: cli hi14asnoop hi14alist h14a.log\n"); + printf("\n"); + return -1; + } + + usb_init(); + if (argc == 4) + SetLogFilename(argv[3]); + else + SetLogFilename("cli.log"); + + return_on_error = 1; + + while (1) { + while (!OpenProxmark(0)) { sleep(1); } + while (1) { + UsbCommand cmdbuf; + CommandReceived(argv[1]); + HANDLE_ERROR; + ReceiveCommand(&cmdbuf); + HANDLE_ERROR; + for (int i = 0; i < 5; ++i) { + ReceiveCommandPoll(&cmdbuf); + } + HANDLE_ERROR; + CommandReceived(argv[2]); + HANDLE_ERROR; + } + } + + CloseProxmark(); + return 0; +} diff --git a/client/cliparser/README.md b/client/cliparser/README.md deleted file mode 100644 index 2b321946..00000000 --- a/client/cliparser/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Command line parser - -cliparser - librari for proxmark with command line parsing high level functions. - -## External libraries: - -### argtable - -Argtable3 is a single-file, ANSI C, command-line parsing library that parses GNU-style command-line options. - -You can download argtable3 from this repository https://github.com/argtable/argtable3 - -[argtable3 license](https://github.com/argtable/argtable3/blob/master/LICENSE) diff --git a/client/cliparser/argtable3.c b/client/cliparser/argtable3.c deleted file mode 100644 index dfcc9c19..00000000 --- a/client/cliparser/argtable3.c +++ /dev/null @@ -1,5996 +0,0 @@ -/******************************************************************************* - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#define ARG_AMALGAMATION - -/******************************************************************************* - * argtable3_private: Declares private types, constants, and interfaces - * - * This file is part of the argtable3 library. - * - * Copyright (C) 2013-2019 Tom G. Huang - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#ifndef ARG_UTILS_H -#define ARG_UTILS_H - -#include - -#define ARG_ENABLE_TRACE 0 -#define ARG_ENABLE_LOG 1 - -#ifdef __cplusplus -extern "C" { -#endif - -enum { ARG_ERR_MINCOUNT = 1, ARG_ERR_MAXCOUNT, ARG_ERR_BADINT, ARG_ERR_OVERFLOW, ARG_ERR_BADDOUBLE, ARG_ERR_BADDATE, ARG_ERR_REGNOMATCH }; - -typedef void(arg_panicfn)(const char* fmt, ...); - -#if defined(_MSC_VER) -#define ARG_TRACE(x) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \ - if (ARG_ENABLE_TRACE) \ - dbg_printf x; \ - } \ - while (0) \ - __pragma(warning(pop)) - -#define ARG_LOG(x) \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \ - if (ARG_ENABLE_LOG) \ - dbg_printf x; \ - } \ - while (0) \ - __pragma(warning(pop)) -#else -#define ARG_TRACE(x) \ - do { \ - if (ARG_ENABLE_TRACE) \ - dbg_printf x; \ - } while (0) - -#define ARG_LOG(x) \ - do { \ - if (ARG_ENABLE_LOG) \ - dbg_printf x; \ - } while (0) -#endif - -extern void dbg_printf(const char* fmt, ...); -extern void arg_set_panic(arg_panicfn* proc); -extern void* xmalloc(size_t size); -extern void* xcalloc(size_t count, size_t size); -extern void* xrealloc(void* ptr, size_t size); -extern void xfree(void* ptr); - -struct arg_hashtable_entry { - void *k, *v; - unsigned int h; - struct arg_hashtable_entry* next; -}; - -typedef struct arg_hashtable { - unsigned int tablelength; - struct arg_hashtable_entry** table; - unsigned int entrycount; - unsigned int loadlimit; - unsigned int primeindex; - unsigned int (*hashfn)(const void* k); - int (*eqfn)(const void* k1, const void* k2); -} arg_hashtable_t; - -/** - * @brief Create a hash table. - * - * @param minsize minimum initial size of hash table - * @param hashfn function for hashing keys - * @param eqfn function for determining key equality - * @return newly created hash table or NULL on failure - */ -arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*)); - -/** - * @brief This function will cause the table to expand if the insertion would take - * the ratio of entries to table size over the maximum load factor. - * - * This function does not check for repeated insertions with a duplicate key. - * The value returned when using a duplicate key is undefined -- when - * the hash table changes size, the order of retrieval of duplicate key - * entries is reversed. - * If in doubt, remove before insert. - * - * @param h the hash table to insert into - * @param k the key - hash table claims ownership and will free on removal - * @param v the value - does not claim ownership - * @return non-zero for successful insertion - */ -void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v); - -#define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ - int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); } - -/** - * @brief Search the specified key in the hash table. - * - * @param h the hash table to search - * @param k the key to search for - does not claim ownership - * @return the value associated with the key, or NULL if none found - */ -void* arg_hashtable_search(arg_hashtable_t* h, const void* k); - -#define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ - valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); } - -/** - * @brief Remove the specified key from the hash table. - * - * @param h the hash table to remove the item from - * @param k the key to search for - does not claim ownership - */ -void arg_hashtable_remove(arg_hashtable_t* h, const void* k); - -#define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ - void fnname(arg_hashtable_t* h, keytype* k) { arg_hashtable_remove(h, k); } - -/** - * @brief Return the number of keys in the hash table. - * - * @param h the hash table - * @return the number of items stored in the hash table - */ -unsigned int arg_hashtable_count(arg_hashtable_t* h); - -/** - * @brief Change the value associated with the key. - * - * function to change the value associated with a key, where there already - * exists a value bound to the key in the hash table. - * Source due to Holger Schemel. - * - * @name hashtable_change - * @param h the hash table - * @param key - * @param value - */ -int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v); - -/** - * @brief Free the hash table and the memory allocated for each key-value pair. - * - * @param h the hash table - * @param free_values whether to call 'free' on the remaining values - */ -void arg_hashtable_destroy(arg_hashtable_t* h, int free_values); - -typedef struct arg_hashtable_itr { - arg_hashtable_t* h; - struct arg_hashtable_entry* e; - struct arg_hashtable_entry* parent; - unsigned int index; -} arg_hashtable_itr_t; - -arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h); - -void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr); - -/** - * @brief Return the value of the (key,value) pair at the current position. - */ -extern void* arg_hashtable_itr_key(arg_hashtable_itr_t* i); - -/** - * @brief Return the value of the (key,value) pair at the current position. - */ -extern void* arg_hashtable_itr_value(arg_hashtable_itr_t* i); - -/** - * @brief Advance the iterator to the next element. Returns zero if advanced to end of table. - */ -int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr); - -/** - * @brief Remove current element and advance the iterator to the next element. - */ -int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr); - -/** - * @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key. - * - * @return Zero if not found. - */ -int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k); - -#define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ - int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); } - -#ifdef __cplusplus -} -#endif - -#endif -/******************************************************************************* - * arg_utils: Implements memory, panic, and other utility functions - * - * This file is part of the argtable3 library. - * - * Copyright (C) 2013-2019 Tom G. Huang - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include -#include -#include - -static void panic(const char* fmt, ...); -static arg_panicfn* s_panic = panic; - -void dbg_printf(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); -} - -static void panic(const char* fmt, ...) { - va_list args; - char* s; - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - s = getenv("EF_DUMPCORE"); -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - - if (s != NULL && *s != '\0') { - abort(); - } else { - exit(EXIT_FAILURE); - } -} - -void arg_set_panic(arg_panicfn* proc) { - s_panic = proc; -} - -void* xmalloc(size_t size) { - void* ret = malloc(size); - if (!ret) { - s_panic("Out of memory!\n"); - } - return ret; -} - -void* xcalloc(size_t count, size_t size) { - size_t allocated_count = count && size ? count : 1; - size_t allocated_size = count && size ? size : 1; - void* ret = calloc(allocated_count, allocated_size); - if (!ret) { - s_panic("Out of memory!\n"); - } - return ret; -} - -void* xrealloc(void* ptr, size_t size) { - size_t allocated_size = size ? size : 1; - void* ret = realloc(ptr, allocated_size); - if (!ret) { - s_panic("Out of memory!\n"); - } - return ret; -} - -void xfree(void* ptr) { - free(ptr); -} - -static void merge(void* data, int esize, int i, int j, int k, arg_comparefn* comparefn) { - char* a = (char*)data; - char* m; - int ipos, jpos, mpos; - - /* Initialize the counters used in merging. */ - ipos = i; - jpos = j + 1; - mpos = 0; - - /* Allocate storage for the merged elements. */ - m = (char*)xmalloc(esize * ((k - i) + 1)); - - /* Continue while either division has elements to merge. */ - while (ipos <= j || jpos <= k) { - if (ipos > j) { - /* The left division has no more elements to merge. */ - while (jpos <= k) { - memcpy(&m[mpos * esize], &a[jpos * esize], esize); - jpos++; - mpos++; - } - - continue; - } else if (jpos > k) { - /* The right division has no more elements to merge. */ - while (ipos <= j) { - memcpy(&m[mpos * esize], &a[ipos * esize], esize); - ipos++; - mpos++; - } - - continue; - } - - /* Append the next ordered element to the merged elements. */ - if (comparefn(&a[ipos * esize], &a[jpos * esize]) < 0) { - memcpy(&m[mpos * esize], &a[ipos * esize], esize); - ipos++; - mpos++; - } else { - memcpy(&m[mpos * esize], &a[jpos * esize], esize); - jpos++; - mpos++; - } - } - - /* Prepare to pass back the merged data. */ - memcpy(&a[i * esize], m, esize * ((k - i) + 1)); - xfree(m); -} - -void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn) { - int j; - - /* Stop the recursion when no more divisions can be made. */ - if (i < k) { - /* Determine where to divide the elements. */ - j = (int)(((i + k - 1)) / 2); - - /* Recursively sort the two divisions. */ - arg_mgsort(data, size, esize, i, j, comparefn); - arg_mgsort(data, size, esize, j + 1, k, comparefn); - merge(data, esize, i, j, k, comparefn); - } -} -/******************************************************************************* - * arg_hashtable: Implements the hash table utilities - * - * This file is part of the argtable3 library. - * - * Copyright (C) 2013-2019 Tom G. Huang - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include -#include -#include - -/* - * This hash table module is adapted from the C hash table implementation by - * Christopher Clark. Here is the copyright notice from the library: - * - * Copyright (c) 2002, Christopher Clark - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Credit for primes table: Aaron Krowne - * http://br.endernet.org/~akrowne/ - * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html - */ -static const unsigned int primes[] = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, - 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, - 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741}; -const unsigned int prime_table_length = sizeof(primes) / sizeof(primes[0]); -const float max_load_factor = (float)0.65; - -static unsigned int enhanced_hash(arg_hashtable_t* h, const void* k) { - /* - * Aim to protect against poor hash functions by adding logic here. - * The logic is taken from Java 1.4 hash table source. - */ - unsigned int i = h->hashfn(k); - i += ~(i << 9); - i ^= ((i >> 14) | (i << 18)); /* >>> */ - i += (i << 4); - i ^= ((i >> 10) | (i << 22)); /* >>> */ - return i; -} - -static unsigned int index_for(unsigned int tablelength, unsigned int hashvalue) { - return (hashvalue % tablelength); -} - -arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*)) { - arg_hashtable_t* h; - unsigned int pindex; - unsigned int size = primes[0]; - - /* Check requested hash table isn't too large */ - if (minsize > (1u << 30)) - return NULL; - - /* - * Enforce size as prime. The reason is to avoid clustering of values - * into a small number of buckets (yes, distribution). A more even - * distributed hash table will perform more consistently. - */ - for (pindex = 0; pindex < prime_table_length; pindex++) { - if (primes[pindex] > minsize) { - size = primes[pindex]; - break; - } - } - - h = (arg_hashtable_t*)xmalloc(sizeof(arg_hashtable_t)); - h->table = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * size); - memset(h->table, 0, size * sizeof(struct arg_hashtable_entry*)); - h->tablelength = size; - h->primeindex = pindex; - h->entrycount = 0; - h->hashfn = hashfn; - h->eqfn = eqfn; - h->loadlimit = (unsigned int)ceil(size * max_load_factor); - return h; -} - -static int arg_hashtable_expand(arg_hashtable_t* h) { - /* Double the size of the table to accommodate more entries */ - struct arg_hashtable_entry** newtable; - struct arg_hashtable_entry* e; - unsigned int newsize; - unsigned int i; - unsigned int index; - - /* Check we're not hitting max capacity */ - if (h->primeindex == (prime_table_length - 1)) - return 0; - newsize = primes[++(h->primeindex)]; - - newtable = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * newsize); - memset(newtable, 0, newsize * sizeof(struct arg_hashtable_entry*)); - /* - * This algorithm is not 'stable': it reverses the list - * when it transfers entries between the tables - */ - for (i = 0; i < h->tablelength; i++) { - while (NULL != (e = h->table[i])) { - h->table[i] = e->next; - index = index_for(newsize, e->h); - e->next = newtable[index]; - newtable[index] = e; - } - } - - xfree(h->table); - h->table = newtable; - h->tablelength = newsize; - h->loadlimit = (unsigned int)ceil(newsize * max_load_factor); - return -1; -} - -unsigned int arg_hashtable_count(arg_hashtable_t* h) { - return h->entrycount; -} - -void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v) { - /* This method allows duplicate keys - but they shouldn't be used */ - unsigned int index; - struct arg_hashtable_entry* e; - if ((h->entrycount + 1) > h->loadlimit) { - /* - * Ignore the return value. If expand fails, we should - * still try cramming just this value into the existing table - * -- we may not have memory for a larger table, but one more - * element may be ok. Next time we insert, we'll try expanding again. - */ - arg_hashtable_expand(h); - } - e = (struct arg_hashtable_entry*)xmalloc(sizeof(struct arg_hashtable_entry)); - e->h = enhanced_hash(h, k); - index = index_for(h->tablelength, e->h); - e->k = k; - e->v = v; - e->next = h->table[index]; - h->table[index] = e; - h->entrycount++; -} - -void* arg_hashtable_search(arg_hashtable_t* h, const void* k) { - struct arg_hashtable_entry* e; - unsigned int hashvalue; - unsigned int index; - - hashvalue = enhanced_hash(h, k); - index = index_for(h->tablelength, hashvalue); - e = h->table[index]; - while (e != NULL) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (h->eqfn(k, e->k))) - return e->v; - e = e->next; - } - return NULL; -} - -void arg_hashtable_remove(arg_hashtable_t* h, const void* k) { - /* - * TODO: consider compacting the table when the load factor drops enough, - * or provide a 'compact' method. - */ - - struct arg_hashtable_entry* e; - struct arg_hashtable_entry** pE; - unsigned int hashvalue; - unsigned int index; - - hashvalue = enhanced_hash(h, k); - index = index_for(h->tablelength, hashvalue); - pE = &(h->table[index]); - e = *pE; - while (NULL != e) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { - *pE = e->next; - h->entrycount--; - xfree(e->k); - xfree(e->v); - xfree(e); - return; - } - pE = &(e->next); - e = e->next; - } -} - -void arg_hashtable_destroy(arg_hashtable_t* h, int free_values) { - unsigned int i; - struct arg_hashtable_entry *e, *f; - struct arg_hashtable_entry** table = h->table; - if (free_values) { - for (i = 0; i < h->tablelength; i++) { - e = table[i]; - while (NULL != e) { - f = e; - e = e->next; - xfree(f->k); - xfree(f->v); - xfree(f); - } - } - } else { - for (i = 0; i < h->tablelength; i++) { - e = table[i]; - while (NULL != e) { - f = e; - e = e->next; - xfree(f->k); - xfree(f); - } - } - } - xfree(h->table); - xfree(h); -} - -arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h) { - unsigned int i; - unsigned int tablelength; - - arg_hashtable_itr_t* itr = (arg_hashtable_itr_t*)xmalloc(sizeof(arg_hashtable_itr_t)); - itr->h = h; - itr->e = NULL; - itr->parent = NULL; - tablelength = h->tablelength; - itr->index = tablelength; - if (0 == h->entrycount) - return itr; - - for (i = 0; i < tablelength; i++) { - if (h->table[i] != NULL) { - itr->e = h->table[i]; - itr->index = i; - break; - } - } - return itr; -} - -void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr) { - xfree(itr); -} - -void* arg_hashtable_itr_key(arg_hashtable_itr_t* i) { - return i->e->k; -} - -void* arg_hashtable_itr_value(arg_hashtable_itr_t* i) { - return i->e->v; -} - -int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr) { - unsigned int j; - unsigned int tablelength; - struct arg_hashtable_entry** table; - struct arg_hashtable_entry* next; - - if (itr->e == NULL) - return 0; /* stupidity check */ - - next = itr->e->next; - if (NULL != next) { - itr->parent = itr->e; - itr->e = next; - return -1; - } - - tablelength = itr->h->tablelength; - itr->parent = NULL; - if (tablelength <= (j = ++(itr->index))) { - itr->e = NULL; - return 0; - } - - table = itr->h->table; - while (NULL == (next = table[j])) { - if (++j >= tablelength) { - itr->index = tablelength; - itr->e = NULL; - return 0; - } - } - - itr->index = j; - itr->e = next; - return -1; -} - -int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr) { - struct arg_hashtable_entry* remember_e; - struct arg_hashtable_entry* remember_parent; - int ret; - - /* Do the removal */ - if ((itr->parent) == NULL) { - /* element is head of a chain */ - itr->h->table[itr->index] = itr->e->next; - } else { - /* element is mid-chain */ - itr->parent->next = itr->e->next; - } - /* itr->e is now outside the hashtable */ - remember_e = itr->e; - itr->h->entrycount--; - xfree(remember_e->k); - xfree(remember_e->v); - - /* Advance the iterator, correcting the parent */ - remember_parent = itr->parent; - ret = arg_hashtable_itr_advance(itr); - if (itr->parent == remember_e) { - itr->parent = remember_parent; - } - xfree(remember_e); - return ret; -} - -int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k) { - struct arg_hashtable_entry* e; - struct arg_hashtable_entry* parent; - unsigned int hashvalue; - unsigned int index; - - hashvalue = enhanced_hash(h, k); - index = index_for(h->tablelength, hashvalue); - - e = h->table[index]; - parent = NULL; - while (e != NULL) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { - itr->index = index; - itr->e = e; - itr->parent = parent; - itr->h = h; - return -1; - } - parent = e; - e = e->next; - } - return 0; -} - -int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v) { - struct arg_hashtable_entry* e; - unsigned int hashvalue; - unsigned int index; - - hashvalue = enhanced_hash(h, k); - index = index_for(h->tablelength, hashvalue); - e = h->table[index]; - while (e != NULL) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { - xfree(e->v); - e->v = v; - return -1; - } - e = e->next; - } - return 0; -} -/******************************************************************************* - * arg_dstr: Implements the dynamic string utilities - * - * This file is part of the argtable3 library. - * - * Copyright (C) 2013-2019 Tom G. Huang - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include -#include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - -#define START_VSNBUFF 16 - -/* - * This dynamic string module is adapted from TclResult.c in the Tcl library. - * Here is the copyright notice from the library: - * - * This software is copyrighted by the Regents of the University of - * California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState - * Corporation and other parties. The following terms apply to all files - * associated with the software unless explicitly disclaimed in - * individual files. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - * - * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY - * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY - * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE - * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE - * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR - * MODIFICATIONS. - * - * GOVERNMENT USE: If you are acquiring this software on behalf of the - * U.S. government, the Government shall have only "Restricted Rights" - * in the software and related documentation as defined in the Federal - * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you - * are acquiring the software on behalf of the Department of Defense, the - * software shall be classified as "Commercial Computer Software" and the - * Government shall have only "Restricted Rights" as defined in Clause - * 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the - * authors grant the U.S. Government and others acting in its behalf - * permission to use and distribute the software in accordance with the - * terms specified in this license. - */ - -typedef struct _internal_arg_dstr { - char* data; - arg_dstr_freefn* free_proc; - char sbuf[ARG_DSTR_SIZE + 1]; - char* append_data; - int append_data_size; - int append_used; -} _internal_arg_dstr_t; - -static void setup_append_buf(arg_dstr_t res, int newSpace); - -arg_dstr_t arg_dstr_create(void) { - _internal_arg_dstr_t* h = (_internal_arg_dstr_t*)xmalloc(sizeof(_internal_arg_dstr_t)); - memset(h, 0, sizeof(_internal_arg_dstr_t)); - h->sbuf[0] = 0; - h->data = h->sbuf; - h->free_proc = ARG_DSTR_STATIC; - return h; -} - -void arg_dstr_destroy(arg_dstr_t ds) { - if (ds == NULL) - return; - - arg_dstr_reset(ds); - xfree(ds); - return; -} - -void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc) { - int length; - register arg_dstr_freefn* old_free_proc = ds->free_proc; - char* old_result = ds->data; - - if (str == NULL) { - ds->sbuf[0] = 0; - ds->data = ds->sbuf; - ds->free_proc = ARG_DSTR_STATIC; - } else if (free_proc == ARG_DSTR_VOLATILE) { - length = (int)strlen(str); - if (length > ARG_DSTR_SIZE) { - ds->data = (char*)xmalloc((unsigned)length + 1); - ds->free_proc = ARG_DSTR_DYNAMIC; - } else { - ds->data = ds->sbuf; - ds->free_proc = ARG_DSTR_STATIC; - } - strcpy(ds->data, str); - } else { - ds->data = str; - ds->free_proc = free_proc; - } - - /* - * If the old result was dynamically-allocated, free it up. Do it here, - * rather than at the beginning, in case the new result value was part of - * the old result value. - */ - - if ((old_free_proc != 0) && (old_result != ds->data)) { - if (old_free_proc == ARG_DSTR_DYNAMIC) { - xfree(old_result); - } else { - (*old_free_proc)(old_result); - } - } - - if ((ds->append_data != NULL) && (ds->append_data_size > 0)) { - xfree(ds->append_data); - ds->append_data = NULL; - ds->append_data_size = 0; - } -} - -char* arg_dstr_cstr(arg_dstr_t ds) /* Interpreter whose result to return. */ -{ - return ds->data; -} - -void arg_dstr_cat(arg_dstr_t ds, const char* str) { - setup_append_buf(ds, (int)strlen(str) + 1); - memcpy(ds->data + strlen(ds->data), str, strlen(str)); -} - -void arg_dstr_catc(arg_dstr_t ds, char c) { - setup_append_buf(ds, 2); - memcpy(ds->data + strlen(ds->data), &c, 1); -} - -/* - * The logic of the `arg_dstr_catf` function is adapted from the `bformat` - * function in The Better String Library by Paul Hsieh. Here is the copyright - * notice from the library: - * - * Copyright (c) 2014, Paul Hsieh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of bstrlib nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...) { - va_list arglist; - char* buff; - int n, r; - size_t slen; - - if (fmt == NULL) - return; - - /* Since the length is not determinable beforehand, a search is - performed using the truncating "vsnprintf" call (to avoid buffer - overflows) on increasing potential sizes for the output result. */ - - if ((n = (int)(2 * strlen(fmt))) < START_VSNBUFF) - n = START_VSNBUFF; - - buff = (char*)xmalloc(n + 2); - memset(buff, 0, n + 2); - - for (;;) { - va_start(arglist, fmt); - r = vsnprintf(buff, n + 1, fmt, arglist); - va_end(arglist); - - slen = strlen(buff); - if (slen < (size_t)n) - break; - - if (r > n) - n = r; - else - n += n; - - xfree(buff); - buff = (char*)xmalloc(n + 2); - memset(buff, 0, n + 2); - } - - arg_dstr_cat(ds, buff); - xfree(buff); -} - -static void setup_append_buf(arg_dstr_t ds, int new_space) { - int total_space; - - /* - * Make the append buffer larger, if that's necessary, then copy the - * data into the append buffer and make the append buffer the official - * data. - */ - if (ds->data != ds->append_data) { - /* - * If the buffer is too big, then free it up so we go back to a - * smaller buffer. This avoids tying up memory forever after a large - * operation. - */ - if (ds->append_data_size > 500) { - xfree(ds->append_data); - ds->append_data = NULL; - ds->append_data_size = 0; - } - ds->append_used = (int)strlen(ds->data); - } else if (ds->data[ds->append_used] != 0) { - /* - * Most likely someone has modified a result created by - * arg_dstr_cat et al. so that it has a different size. Just - * recompute the size. - */ - ds->append_used = (int)strlen(ds->data); - } - - total_space = new_space + ds->append_used; - if (total_space >= ds->append_data_size) { - char* newbuf; - - if (total_space < 100) { - total_space = 200; - } else { - total_space *= 2; - } - newbuf = (char*)xmalloc((unsigned)total_space); - memset(newbuf, 0, total_space); - strcpy(newbuf, ds->data); - if (ds->append_data != NULL) { - xfree(ds->append_data); - } - ds->append_data = newbuf; - ds->append_data_size = total_space; - } else if (ds->data != ds->append_data) { - strcpy(ds->append_data, ds->data); - } - - arg_dstr_free(ds); - ds->data = ds->append_data; -} - -void arg_dstr_free(arg_dstr_t ds) { - if (ds->free_proc != NULL) { - if (ds->free_proc == ARG_DSTR_DYNAMIC) { - xfree(ds->data); - } else { - (*ds->free_proc)(ds->data); - } - ds->free_proc = NULL; - } -} - -void arg_dstr_reset(arg_dstr_t ds) { - arg_dstr_free(ds); - if ((ds->append_data != NULL) && (ds->append_data_size > 0)) { - xfree(ds->append_data); - ds->append_data = NULL; - ds->append_data_size = 0; - } - - ds->data = ds->sbuf; - ds->sbuf[0] = 0; -} - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-2-Clause-NetBSD - * - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#if ARG_REPLACE_GETOPT == 1 - -#ifndef _GETOPT_H_ -#define _GETOPT_H_ - -/* - * GNU-like getopt_long()/getopt_long_only() with 4.4BSD optreset extension. - * getopt() is declared here too for GNU programs. - */ -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -struct option { - /* name of long option */ - const char *name; - /* - * one of no_argument, required_argument, and optional_argument: - * whether option takes an argument - */ - int has_arg; - /* if not NULL, set *flag to val when option found */ - int *flag; - /* if flag not NULL, value to set *flag to; else return value */ - int val; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -int getopt_long(int, char * const *, const char *, - const struct option *, int *); -int getopt_long_only(int, char * const *, const char *, - const struct option *, int *); -#ifndef _GETOPT_DECLARED -#define _GETOPT_DECLARED -int getopt(int, char * const [], const char *); - -extern char *optarg; /* getopt(3) external variables */ -extern int optind, opterr, optopt; -#endif -#ifndef _OPTRESET_DECLARED -#define _OPTRESET_DECLARED -extern int optreset; /* getopt(3) external variable */ -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !_GETOPT_H_ */ - -#endif /* ARG_REPLACE_GETOPT == 1 */ -/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */ -/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ - -/* - * Copyright (c) 2002 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Dieter Baron and Thomas Klausner. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "argtable3.h" - -#if ARG_REPLACE_GETOPT == 1 - -#ifndef ARG_AMALGAMATION -#include "arg_getopt.h" -#endif - -#include -#include -#include - -#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */ - -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ - -#define PRINT_ERROR ((opterr) && (*options != ':')) - -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ - -/* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 - -#define EMSG "" - -#ifdef GNU_COMPATIBLE -#define NO_PREFIX (-1) -#define D_PREFIX 0 -#define DD_PREFIX 1 -#define W_PREFIX 2 -#endif - -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int, int); -static int gcd(int, int); -static void permute_args(int, int, int, char * const *); - -static char *place = EMSG; /* option letter processing */ - -/* XXX: set optreset to 1 rather than these two */ -static int nonopt_start = -1; /* first non option argument (for permute) */ -static int nonopt_end = -1; /* first option after non options (for permute) */ - -/* Error messages */ -static const char recargchar[] = "option requires an argument -- %c"; -static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */ -#ifdef GNU_COMPATIBLE -static int dash_prefix = NO_PREFIX; -static const char gnuoptchar[] = "invalid option -- %c"; - -static const char recargstring[] = "option `%s%s' requires an argument"; -static const char ambig[] = "option `%s%.*s' is ambiguous"; -static const char noarg[] = "option `%s%.*s' doesn't allow an argument"; -static const char illoptstring[] = "unrecognized option `%s%s'"; -#else -static const char recargstring[] = "option requires an argument -- %s"; -static const char ambig[] = "ambiguous option -- %.*s"; -static const char noarg[] = "option doesn't take an argument -- %.*s"; -static const char illoptstring[] = "unknown option -- %s"; -#endif - -#ifdef _WIN32 - -/* - * Windows needs warnx(). We change the definition though: - * 1. (another) global is defined, opterrmsg, which holds the error message - * 2. errors are always printed out on stderr w/o the program name - * Note that opterrmsg always gets set no matter what opterr is set to. The - * error message will not be printed if opterr is 0 as usual. - */ - -#include -#include - -#define MAX_OPTERRMSG_SIZE 128 - -extern char opterrmsg[MAX_OPTERRMSG_SIZE]; -char opterrmsg[MAX_OPTERRMSG_SIZE]; /* buffer for the last error message */ - -static void warnx(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - - /* - * Make sure opterrmsg is always zero-terminated despite the _vsnprintf() - * implementation specifics and manually suppress the warning. - */ - memset(opterrmsg, 0, sizeof(opterrmsg)); - if (fmt != NULL) -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - _vsnprintf_s(opterrmsg, sizeof(opterrmsg), sizeof(opterrmsg) - 1, fmt, ap); -#else - _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap); -#endif - - va_end(ap); - -#ifdef _MSC_VER -#pragma warning(suppress : 6053) -#endif - fprintf(stderr, "%s\n", opterrmsg); -} - -#else -#include -#endif /*_WIN32*/ -/* - * Compute the greatest common divisor of a and b. - */ -static int -gcd(int a, int b) -{ - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return (b); -} - -/* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ -static void -permute_args(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end+i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } -} - -/* - * parse_long_options -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ -static int -parse_long_options(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too, int flags) -{ - char *current_argv, *has_equal; -#ifdef GNU_COMPATIBLE - char *current_dash; -#endif - size_t current_argv_len; - int i, match, exact_match, second_partial_match; - - current_argv = place; -#ifdef GNU_COMPATIBLE - switch (dash_prefix) { - case D_PREFIX: - current_dash = "-"; - break; - case DD_PREFIX: - current_dash = "--"; - break; - case W_PREFIX: - current_dash = "-W "; - break; - default: - current_dash = ""; - break; - } -#endif - match = -1; - exact_match = 0; - second_partial_match = 0; - - optind++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else - current_argv_len = strlen(current_argv); - - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - exact_match = 1; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* first partial match */ - match = i; - else if ((flags & FLAG_LONGONLY) || - long_options[i].has_arg != - long_options[match].has_arg || - long_options[i].flag != long_options[match].flag || - long_options[i].val != long_options[match].val) - second_partial_match = 1; - } - if (!exact_match && second_partial_match) { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, -#ifdef GNU_COMPATIBLE - current_dash, -#endif - (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, -#ifdef GNU_COMPATIBLE - current_dash, -#endif - (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; -#ifdef GNU_COMPATIBLE - return (BADCH); -#else - return (BADARG); -#endif - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, -#ifdef GNU_COMPATIBLE - current_dash, -#endif - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return (BADARG); - } - } else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, -#ifdef GNU_COMPATIBLE - current_dash, -#endif - current_argv); - optopt = 0; - return (BADCH); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); -} - -/* - * getopt_internal -- - * Parse argc/argv argument vector. Called by user level routines. - */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) -{ - char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - if (posixly_correct == -1 || optreset) { -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - size_t requiredSize; - getenv_s(&requiredSize, NULL, 0, "POSIXLY_CORRECT"); - posixly_correct = requiredSize != 0; -#else - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); -#endif - } - - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; -start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargv[optind]) != '-' || -#ifdef GNU_COMPATIBLE - place[1] == '\0') { -#else - (place[1] == '\0' && strchr(options, '-') == NULL)) { -#endif - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = EMSG; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() - */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; -#ifdef GNU_COMPATIBLE - dash_prefix = D_PREFIX; -#endif - if (*place == '-') { - place++; /* --foo long option */ - if (*place == '\0') - return (BADARG); /* malformed option */ -#ifdef GNU_COMPATIBLE - dash_prefix = DD_PREFIX; -#endif - } else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too, flags); - if (optchar != -1) { - place = EMSG; - return (optchar); - } - } - - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; -#ifdef GNU_COMPATIBLE - if (PRINT_ERROR) - warnx(posixly_correct ? illoptchar : gnuoptchar, - optchar); -#else - if (PRINT_ERROR) - warnx(illoptchar, optchar); -#endif - optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else /* white space */ - place = nargv[optind]; -#ifdef GNU_COMPATIBLE - dash_prefix = W_PREFIX; -#endif - optchar = parse_long_options(nargv, options, long_options, - idx, 0, flags); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; - } else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = place; - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } else - optarg = nargv[optind]; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return (optchar); -} - -/* - * getopt -- - * Parse argc/argv argument vector. - * - * [eventually this will replace the BSD getopt] - */ -int -getopt(int nargc, char * const *nargv, const char *options) -{ - - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); -} - -/* - * getopt_long -- - * Parse argc/argv argument vector. - */ -int -getopt_long(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); -} - -/* - * getopt_long_only -- - * Parse argc/argv argument vector. - */ -int -getopt_long_only(int nargc, char * const *nargv, const char *options, - const struct option *long_options, int *idx) -{ - - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE|FLAG_LONGONLY)); -} - -#endif /* ARG_REPLACE_GETOPT == 1 */ -/******************************************************************************* - * arg_date: Implements the date command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include - -char* arg_strptime(const char* buf, const char* fmt, struct tm* tm); - -static void arg_date_resetfn(struct arg_date* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -static int arg_date_scanfn(struct arg_date* parent, const char* argval) { - int errorcode = 0; - - if (parent->count == parent->hdr.maxcount) { - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* no argument value was given, leave parent->tmval[] unaltered but still count it */ - parent->count++; - } else { - const char* pend; - struct tm tm = parent->tmval[parent->count]; - - /* parse the given argument value, store result in parent->tmval[] */ - pend = arg_strptime(argval, parent->format, &tm); - if (pend && pend[0] == '\0') - parent->tmval[parent->count++] = tm; - else - errorcode = ARG_ERR_BADDATE; - } - - ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static int arg_date_checkfn(struct arg_date* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - - ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static void arg_date_errorfn(struct arg_date* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - case ARG_ERR_BADDATE: { - struct tm tm; - char buff[200]; - - arg_dstr_catf(ds, "illegal timestamp format \"%s\"\n", argval); - memset(&tm, 0, sizeof(tm)); - arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm); - strftime(buff, sizeof(buff), parent->format, &tm); - arg_dstr_catf(ds, "correct format is \"%s\"\n", buff); - break; - } - } -} - -struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) { - return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary); -} - -struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) { - return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary); -} - -struct arg_date* -arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary) { - size_t nbytes; - struct arg_date* result; - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - /* default time format is the national date format for the locale */ - if (!format) - format = "%x"; - - nbytes = sizeof(struct arg_date) /* storage for struct arg_date */ - + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */ - - /* allocate storage for the arg_date struct + tmval[] array. */ - /* we use calloc because we want the tmval[] array zero filled. */ - result = (struct arg_date*)xcalloc(1, nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = datatype ? datatype : format; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_date_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_date_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_date_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_date_errorfn; - - /* store the tmval[maxcount] array immediately after the arg_date struct */ - result->tmval = (struct tm*)(result + 1); - - /* init the remaining arg_date member variables */ - result->count = 0; - result->format = format; - - ARG_TRACE(("arg_daten() returns %p\n", result)); - return result; -} - -/*- - * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code was contributed to The NetBSD Foundation by Klaus Klein. - * Heavily optimised by David Laight - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -/* - * We do not implement alternate representations. However, we always - * check whether a given modifier is allowed for a certain conversion. - */ -#define ALT_E 0x01 -#define ALT_O 0x02 -#define LEGAL_ALT(x) \ - { \ - if (alt_format & ~(x)) \ - return (0); \ - } -#define TM_YEAR_BASE (1900) - -static int conv_num(const char**, int*, int, int); - -static const char* day[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; - -static const char* abday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - -static const char* mon[12] = {"January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"}; - -static const char* abmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -static const char* am_pm[2] = {"AM", "PM"}; - -static int arg_strcasecmp(const char* s1, const char* s2) { - const unsigned char* us1 = (const unsigned char*)s1; - const unsigned char* us2 = (const unsigned char*)s2; - while (tolower(*us1) == tolower(*us2++)) - if (*us1++ == '\0') - return 0; - - return tolower(*us1) - tolower(*--us2); -} - -static int arg_strncasecmp(const char* s1, const char* s2, size_t n) { - if (n != 0) { - const unsigned char* us1 = (const unsigned char*)s1; - const unsigned char* us2 = (const unsigned char*)s2; - do { - if (tolower(*us1) != tolower(*us2++)) - return tolower(*us1) - tolower(*--us2); - - if (*us1++ == '\0') - break; - } while (--n != 0); - } - - return 0; -} - -char* arg_strptime(const char* buf, const char* fmt, struct tm* tm) { - char c; - const char* bp; - size_t len = 0; - int alt_format, i, split_year = 0; - - bp = buf; - - while ((c = *fmt) != '\0') { - /* Clear `alternate' modifier prior to new conversion. */ - alt_format = 0; - - /* Eat up white-space. */ - if (isspace(c)) { - while (isspace(*bp)) - bp++; - - fmt++; - continue; - } - - if ((c = *fmt++) != '%') - goto literal; - - again: - switch (c = *fmt++) { - case '%': /* "%%" is converted to "%". */ - literal: - if (c != *bp++) - return (0); - break; - - /* - * "Alternative" modifiers. Just set the appropriate flag - * and start over again. - */ - case 'E': /* "%E?" alternative conversion modifier. */ - LEGAL_ALT(0); - alt_format |= ALT_E; - goto again; - - case 'O': /* "%O?" alternative conversion modifier. */ - LEGAL_ALT(0); - alt_format |= ALT_O; - goto again; - - /* - * "Complex" conversion rules, implemented through recursion. - */ - case 'c': /* Date and time, using the locale's format. */ - LEGAL_ALT(ALT_E); - bp = arg_strptime(bp, "%x %X", tm); - if (!bp) - return (0); - break; - - case 'D': /* The date as "%m/%d/%y". */ - LEGAL_ALT(0); - bp = arg_strptime(bp, "%m/%d/%y", tm); - if (!bp) - return (0); - break; - - case 'R': /* The time as "%H:%M". */ - LEGAL_ALT(0); - bp = arg_strptime(bp, "%H:%M", tm); - if (!bp) - return (0); - break; - - case 'r': /* The time in 12-hour clock representation. */ - LEGAL_ALT(0); - bp = arg_strptime(bp, "%I:%M:%S %p", tm); - if (!bp) - return (0); - break; - - case 'T': /* The time as "%H:%M:%S". */ - LEGAL_ALT(0); - bp = arg_strptime(bp, "%H:%M:%S", tm); - if (!bp) - return (0); - break; - - case 'X': /* The time, using the locale's format. */ - LEGAL_ALT(ALT_E); - bp = arg_strptime(bp, "%H:%M:%S", tm); - if (!bp) - return (0); - break; - - case 'x': /* The date, using the locale's format. */ - LEGAL_ALT(ALT_E); - bp = arg_strptime(bp, "%m/%d/%y", tm); - if (!bp) - return (0); - break; - - /* - * "Elementary" conversion rules. - */ - case 'A': /* The day of week, using the locale's form. */ - case 'a': - LEGAL_ALT(0); - for (i = 0; i < 7; i++) { - /* Full name. */ - len = strlen(day[i]); - if (arg_strncasecmp(day[i], bp, len) == 0) - break; - - /* Abbreviated name. */ - len = strlen(abday[i]); - if (arg_strncasecmp(abday[i], bp, len) == 0) - break; - } - - /* Nothing matched. */ - if (i == 7) - return (0); - - tm->tm_wday = i; - bp += len; - break; - - case 'B': /* The month, using the locale's form. */ - case 'b': - case 'h': - LEGAL_ALT(0); - for (i = 0; i < 12; i++) { - /* Full name. */ - len = strlen(mon[i]); - if (arg_strncasecmp(mon[i], bp, len) == 0) - break; - - /* Abbreviated name. */ - len = strlen(abmon[i]); - if (arg_strncasecmp(abmon[i], bp, len) == 0) - break; - } - - /* Nothing matched. */ - if (i == 12) - return (0); - - tm->tm_mon = i; - bp += len; - break; - - case 'C': /* The century number. */ - LEGAL_ALT(ALT_E); - if (!(conv_num(&bp, &i, 0, 99))) - return (0); - - if (split_year) { - tm->tm_year = (tm->tm_year % 100) + (i * 100); - } else { - tm->tm_year = i * 100; - split_year = 1; - } - break; - - case 'd': /* The day of month. */ - case 'e': - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_mday, 1, 31))) - return (0); - break; - - case 'k': /* The hour (24-hour clock representation). */ - LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'H': - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_hour, 0, 23))) - return (0); - break; - - case 'l': /* The hour (12-hour clock representation). */ - LEGAL_ALT(0); - /* FALLTHROUGH */ - case 'I': - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_hour, 1, 12))) - return (0); - if (tm->tm_hour == 12) - tm->tm_hour = 0; - break; - - case 'j': /* The day of year. */ - LEGAL_ALT(0); - if (!(conv_num(&bp, &i, 1, 366))) - return (0); - tm->tm_yday = i - 1; - break; - - case 'M': /* The minute. */ - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_min, 0, 59))) - return (0); - break; - - case 'm': /* The month. */ - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &i, 1, 12))) - return (0); - tm->tm_mon = i - 1; - break; - - case 'p': /* The locale's equivalent of AM/PM. */ - LEGAL_ALT(0); - /* AM? */ - if (arg_strcasecmp(am_pm[0], bp) == 0) { - if (tm->tm_hour > 11) - return (0); - - bp += strlen(am_pm[0]); - break; - } - /* PM? */ - else if (arg_strcasecmp(am_pm[1], bp) == 0) { - if (tm->tm_hour > 11) - return (0); - - tm->tm_hour += 12; - bp += strlen(am_pm[1]); - break; - } - - /* Nothing matched. */ - return (0); - - case 'S': /* The seconds. */ - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_sec, 0, 61))) - return (0); - break; - - case 'U': /* The week of year, beginning on sunday. */ - case 'W': /* The week of year, beginning on monday. */ - LEGAL_ALT(ALT_O); - /* - * XXX This is bogus, as we can not assume any valid - * information present in the tm structure at this - * point to calculate a real value, so just check the - * range for now. - */ - if (!(conv_num(&bp, &i, 0, 53))) - return (0); - break; - - case 'w': /* The day of week, beginning on sunday. */ - LEGAL_ALT(ALT_O); - if (!(conv_num(&bp, &tm->tm_wday, 0, 6))) - return (0); - break; - - case 'Y': /* The year. */ - LEGAL_ALT(ALT_E); - if (!(conv_num(&bp, &i, 0, 9999))) - return (0); - - tm->tm_year = i - TM_YEAR_BASE; - break; - - case 'y': /* The year within 100 years of the epoch. */ - LEGAL_ALT(ALT_E | ALT_O); - if (!(conv_num(&bp, &i, 0, 99))) - return (0); - - if (split_year) { - tm->tm_year = ((tm->tm_year / 100) * 100) + i; - break; - } - split_year = 1; - if (i <= 68) - tm->tm_year = i + 2000 - TM_YEAR_BASE; - else - tm->tm_year = i + 1900 - TM_YEAR_BASE; - break; - - /* - * Miscellaneous conversions. - */ - case 'n': /* Any kind of white-space. */ - case 't': - LEGAL_ALT(0); - while (isspace(*bp)) - bp++; - break; - - default: /* Unknown/unsupported conversion. */ - return (0); - } - } - - /* LINTED functional specification */ - return ((char*)bp); -} - -static int conv_num(const char** buf, int* dest, int llim, int ulim) { - int result = 0; - - /* The limit also determines the number of valid digits. */ - int rulim = ulim; - - if (**buf < '0' || **buf > '9') - return (0); - - do { - result *= 10; - result += *(*buf)++ - '0'; - rulim /= 10; - } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9'); - - if (result < llim || result > ulim) - return (0); - - *dest = result; - return (1); -} -/******************************************************************************* - * arg_dbl: Implements the double command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include - -static void arg_dbl_resetfn(struct arg_dbl* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -static int arg_dbl_scanfn(struct arg_dbl* parent, const char* argval) { - int errorcode = 0; - - if (parent->count == parent->hdr.maxcount) { - /* maximum number of arguments exceeded */ - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* a valid argument with no argument value was given. */ - /* This happens when an optional argument value was invoked. */ - /* leave parent argument value unaltered but still count the argument. */ - parent->count++; - } else { - double val; - char* end; - - /* extract double from argval into val */ - val = strtod(argval, &end); - - /* if success then store result in parent->dval[] array otherwise return error*/ - if (*end == 0) - parent->dval[parent->count++] = val; - else - errorcode = ARG_ERR_BADDOUBLE; - } - - ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static int arg_dbl_checkfn(struct arg_dbl* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - - ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static void arg_dbl_errorfn(struct arg_dbl* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - case ARG_ERR_BADDOUBLE: - arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - } -} - -struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary); -} - -struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary); -} - -struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) { - size_t nbytes; - struct arg_dbl* result; - size_t addr; - size_t rem; - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */ - + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */ - - result = (struct arg_dbl*)xmalloc(nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = datatype ? datatype : ""; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_dbl_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_dbl_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_dbl_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_dbl_errorfn; - - /* Store the dval[maxcount] array on the first double boundary that - * immediately follows the arg_dbl struct. We do the memory alignment - * purely for SPARC and Motorola systems. They require floats and - * doubles to be aligned on natural boundaries. - */ - addr = (size_t)(result + 1); - rem = addr % sizeof(double); - result->dval = (double*)(addr + sizeof(double) - rem); - ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem)); - - result->count = 0; - - ARG_TRACE(("arg_dbln() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_end: Implements the error handling utilities - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include - -static void arg_end_resetfn(struct arg_end* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -static void arg_end_errorfn(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname) { - /* suppress unreferenced formal parameter warning */ - (void)parent; - - progname = progname ? progname : ""; - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (error) { - case ARG_ELIMIT: - arg_dstr_cat(ds, "too many errors to display"); - break; - case ARG_EMALLOC: - arg_dstr_cat(ds, "insufficient memory"); - break; - case ARG_ENOMATCH: - arg_dstr_catf(ds, "unexpected argument \"%s\"", argval); - break; - case ARG_EMISSARG: - arg_dstr_catf(ds, "option \"%s\" requires an argument", argval); - break; - case ARG_ELONGOPT: - arg_dstr_catf(ds, "invalid option \"%s\"", argval); - break; - default: - arg_dstr_catf(ds, "invalid option \"-%c\"", error); - break; - } - - arg_dstr_cat(ds, "\n"); -} - -struct arg_end* arg_end(int maxcount) { - size_t nbytes; - struct arg_end* result; - - nbytes = sizeof(struct arg_end) + maxcount * sizeof(int) /* storage for int error[maxcount] array*/ - + maxcount * sizeof(void*) /* storage for void* parent[maxcount] array */ - + maxcount * sizeof(char*); /* storage for char* argval[maxcount] array */ - - result = (struct arg_end*)xmalloc(nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_TERMINATOR; - result->hdr.shortopts = NULL; - result->hdr.longopts = NULL; - result->hdr.datatype = NULL; - result->hdr.glossary = NULL; - result->hdr.mincount = 1; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_end_resetfn; - result->hdr.scanfn = NULL; - result->hdr.checkfn = NULL; - result->hdr.errorfn = (arg_errorfn*)arg_end_errorfn; - - /* store error[maxcount] array immediately after struct arg_end */ - result->error = (int*)(result + 1); - - /* store parent[maxcount] array immediately after error[] array */ - result->parent = (void**)(result->error + maxcount); - - /* store argval[maxcount] array immediately after parent[] array */ - result->argval = (const char**)(result->parent + maxcount); - - ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result)); - return result; -} - -void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname) { - int i; - ARG_TRACE(("arg_errors()\n")); - for (i = 0; i < end->count; i++) { - struct arg_hdr* errorparent = (struct arg_hdr*)(end->parent[i]); - if (errorparent->errorfn) - errorparent->errorfn(end->parent[i], ds, end->error[i], end->argval[i], progname); - } -} - -void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_errors_ds(ds, end, progname); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} -/******************************************************************************* - * arg_file: Implements the file command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include - -#ifdef WIN32 -#define FILESEPARATOR1 '\\' -#define FILESEPARATOR2 '/' -#else -#define FILESEPARATOR1 '/' -#define FILESEPARATOR2 '/' -#endif - -static void arg_file_resetfn(struct arg_file* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -/* Returns ptr to the base filename within *filename */ -static const char* arg_basename(const char* filename) { - const char *result = NULL, *result1, *result2; - - /* Find the last occurrence of eother file separator character. */ - /* Two alternative file separator chars are supported as legal */ - /* file separators but not both together in the same filename. */ - result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL); - result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL); - - if (result2) - result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */ - - if (result1) - result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */ - - if (!result) - result = filename; /* neither file separator was found so basename is the whole filename */ - - /* special cases of "." and ".." are not considered basenames */ - if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0)) - result = filename + strlen(filename); - - return result; -} - -/* Returns ptr to the file extension within *basename */ -static const char* arg_extension(const char* basename) { - /* find the last occurrence of '.' in basename */ - const char* result = (basename ? strrchr(basename, '.') : NULL); - - /* if no '.' was found then return pointer to end of basename */ - if (basename && !result) - result = basename + strlen(basename); - - /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */ - if (basename && result == basename) - result = basename + strlen(basename); - - /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */ - if (basename && result && strlen(result) == 1) - result = basename + strlen(basename); - - return result; -} - -static int arg_file_scanfn(struct arg_file* parent, const char* argval) { - int errorcode = 0; - - if (parent->count == parent->hdr.maxcount) { - /* maximum number of arguments exceeded */ - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* a valid argument with no argument value was given. */ - /* This happens when an optional argument value was invoked. */ - /* leave parent arguiment value unaltered but still count the argument. */ - parent->count++; - } else { - parent->filename[parent->count] = argval; - parent->basename[parent->count] = arg_basename(argval); - parent->extension[parent->count] = - arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/ - parent->count++; - } - - ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static int arg_file_checkfn(struct arg_file* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - - ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static void arg_file_errorfn(struct arg_file* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - default: - arg_dstr_catf(ds, "unknown error at \"%s\"\n", argval); - } -} - -struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_filen(shortopts, longopts, datatype, 0, 1, glossary); -} - -struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_filen(shortopts, longopts, datatype, 1, 1, glossary); -} - -struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) { - size_t nbytes; - struct arg_file* result; - int i; - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - nbytes = sizeof(struct arg_file) /* storage for struct arg_file */ - + sizeof(char*) * maxcount /* storage for filename[maxcount] array */ - + sizeof(char*) * maxcount /* storage for basename[maxcount] array */ - + sizeof(char*) * maxcount; /* storage for extension[maxcount] array */ - - result = (struct arg_file*)xmalloc(nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.glossary = glossary; - result->hdr.datatype = datatype ? datatype : ""; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_file_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_file_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_file_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_file_errorfn; - - /* store the filename,basename,extension arrays immediately after the arg_file struct */ - result->filename = (const char**)(result + 1); - result->basename = result->filename + maxcount; - result->extension = result->basename + maxcount; - result->count = 0; - - /* foolproof the string pointers by initialising them with empty strings */ - for (i = 0; i < maxcount; i++) { - result->filename[i] = ""; - result->basename[i] = ""; - result->extension[i] = ""; - } - - ARG_TRACE(("arg_filen() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_int: Implements the int command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include -#include - -static void arg_int_resetfn(struct arg_int* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -/* strtol0x() is like strtol() except that the numeric string is */ -/* expected to be prefixed by "0X" where X is a user supplied char. */ -/* The string may optionally be prefixed by white space and + or - */ -/* as in +0X123 or -0X123. */ -/* Once the prefix has been scanned, the remainder of the numeric */ -/* string is converted using strtol() with the given base. */ -/* eg: to parse hex str="-0X12324", specify X='X' and base=16. */ -/* eg: to parse oct str="+0o12324", specify X='O' and base=8. */ -/* eg: to parse bin str="-0B01010", specify X='B' and base=2. */ -/* Failure of conversion is indicated by result where *endptr==str. */ -static long int strtol0X(const char* str, const char** endptr, char X, int base) { - long int val; /* stores result */ - int s = 1; /* sign is +1 or -1 */ - const char* ptr = str; /* ptr to current position in str */ - - /* skip leading whitespace */ - while (isspace(*ptr)) - ptr++; - /* printf("1) %s\n",ptr); */ - - /* scan optional sign character */ - switch (*ptr) { - case '+': - ptr++; - s = 1; - break; - case '-': - ptr++; - s = -1; - break; - default: - s = 1; - break; - } - /* printf("2) %s\n",ptr); */ - - /* '0X' prefix */ - if ((*ptr++) != '0') { - /* printf("failed to detect '0'\n"); */ - *endptr = str; - return 0; - } - /* printf("3) %s\n",ptr); */ - if (toupper(*ptr++) != toupper(X)) { - /* printf("failed to detect '%c'\n",X); */ - *endptr = str; - return 0; - } - /* printf("4) %s\n",ptr); */ - - /* attempt conversion on remainder of string using strtol() */ - val = strtol(ptr, (char**)endptr, base); - if (*endptr == ptr) { - /* conversion failed */ - *endptr = str; - return 0; - } - - /* success */ - return s * val; -} - -/* Returns 1 if str matches suffix (case insensitive). */ -/* Str may contain trailing whitespace, but nothing else. */ -static int detectsuffix(const char* str, const char* suffix) { - /* scan pairwise through strings until mismatch detected */ - while (toupper(*str) == toupper(*suffix)) { - /* printf("'%c' '%c'\n", *str, *suffix); */ - - /* return 1 (success) if match persists until the string terminator */ - if (*str == '\0') - return 1; - - /* next chars */ - str++; - suffix++; - } - /* printf("'%c' '%c' mismatch\n", *str, *suffix); */ - - /* return 0 (fail) if the matching did not consume the entire suffix */ - if (*suffix != 0) - return 0; /* failed to consume entire suffix */ - - /* skip any remaining whitespace in str */ - while (isspace(*str)) - str++; - - /* return 1 (success) if we have reached end of str else return 0 (fail) */ - return (*str == '\0') ? 1 : 0; -} - -static int arg_int_scanfn(struct arg_int* parent, const char* argval) { - int errorcode = 0; - - if (parent->count == parent->hdr.maxcount) { - /* maximum number of arguments exceeded */ - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* a valid argument with no argument value was given. */ - /* This happens when an optional argument value was invoked. */ - /* leave parent arguiment value unaltered but still count the argument. */ - parent->count++; - } else { - long int val; - const char* end; - - /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */ - val = strtol0X(argval, &end, 'X', 16); - if (end == argval) { - /* hex failed, attempt octal conversion (eg +0o123) */ - val = strtol0X(argval, &end, 'O', 8); - if (end == argval) { - /* octal failed, attempt binary conversion (eg +0B101) */ - val = strtol0X(argval, &end, 'B', 2); - if (end == argval) { - /* binary failed, attempt decimal conversion with no prefix (eg 1234) */ - val = strtol(argval, (char**)&end, 10); - if (end == argval) { - /* all supported number formats failed */ - return ARG_ERR_BADINT; - } - } - } - } - - /* Safety check for integer overflow. WARNING: this check */ - /* achieves nothing on machines where size(int)==size(long). */ - if (val > INT_MAX || val < INT_MIN) - errorcode = ARG_ERR_OVERFLOW; - - /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */ - /* We need to be mindful of integer overflows when using such big numbers. */ - if (detectsuffix(end, "KB")) /* kilobytes */ - { - if (val > (INT_MAX / 1024) || val < (INT_MIN / 1024)) - errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */ - else - val *= 1024; /* 1KB = 1024 */ - } else if (detectsuffix(end, "MB")) /* megabytes */ - { - if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576)) - errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */ - else - val *= 1048576; /* 1MB = 1024*1024 */ - } else if (detectsuffix(end, "GB")) /* gigabytes */ - { - if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824)) - errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */ - else - val *= 1073741824; /* 1GB = 1024*1024*1024 */ - } else if (!detectsuffix(end, "")) - errorcode = ARG_ERR_BADINT; /* invalid suffix detected */ - - /* if success then store result in parent->ival[] array */ - if (errorcode == 0) - parent->ival[parent->count++] = (int)val; - } - - /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */ - return errorcode; -} - -static int arg_int_checkfn(struct arg_int* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ - return errorcode; -} - -static void arg_int_errorfn(struct arg_int* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - case ARG_ERR_BADINT: - arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_OVERFLOW: - arg_dstr_cat(ds, "integer overflow at option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, " "); - arg_dstr_catf(ds, "(%s is too large)\n", argval); - break; - } -} - -struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_intn(shortopts, longopts, datatype, 0, 1, glossary); -} - -struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_intn(shortopts, longopts, datatype, 1, 1, glossary); -} - -struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) { - size_t nbytes; - struct arg_int* result; - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - nbytes = sizeof(struct arg_int) /* storage for struct arg_int */ - + maxcount * sizeof(int); /* storage for ival[maxcount] array */ - - result = (struct arg_int*)xmalloc(nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = datatype ? datatype : ""; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_int_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_int_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_int_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_int_errorfn; - - /* store the ival[maxcount] array immediately after the arg_int struct */ - result->ival = (int*)(result + 1); - result->count = 0; - - ARG_TRACE(("arg_intn() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_lit: Implements the literature command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include - -static void arg_lit_resetfn(struct arg_lit* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -static int arg_lit_scanfn(struct arg_lit* parent, const char* argval) { - int errorcode = 0; - if (parent->count < parent->hdr.maxcount) - parent->count++; - else - errorcode = ARG_ERR_MAXCOUNT; - - ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval, errorcode)); - return errorcode; -} - -static int arg_lit_checkfn(struct arg_lit* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static void arg_lit_errorfn(struct arg_lit* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_catf(ds, "%s: missing option ", progname); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - arg_dstr_cat(ds, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_catf(ds, "%s: extraneous option ", progname); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - } - - ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, ds, errorcode, argval, progname)); -} - -struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary) { - return arg_litn(shortopts, longopts, 0, 1, glossary); -} - -struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary) { - return arg_litn(shortopts, longopts, 1, 1, glossary); -} - -struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary) { - struct arg_lit* result; - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - result = (struct arg_lit*)xmalloc(sizeof(struct arg_lit)); - - /* init the arg_hdr struct */ - result->hdr.flag = 0; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = NULL; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_lit_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_lit_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_lit_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_lit_errorfn; - - /* init local variables */ - result->count = 0; - - ARG_TRACE(("arg_litn() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_rem: Implements the rem command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include - -struct arg_rem* arg_rem(const char* datatype, const char* glossary) { - struct arg_rem* result = (struct arg_rem*)xmalloc(sizeof(struct arg_rem)); - - result->hdr.flag = 0; - result->hdr.shortopts = NULL; - result->hdr.longopts = NULL; - result->hdr.datatype = datatype; - result->hdr.glossary = glossary; - result->hdr.mincount = 1; - result->hdr.maxcount = 1; - result->hdr.parent = result; - result->hdr.resetfn = NULL; - result->hdr.scanfn = NULL; - result->hdr.checkfn = NULL; - result->hdr.errorfn = NULL; - - ARG_TRACE(("arg_rem() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_rex: Implements the regex command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include - -#ifndef _TREX_H_ -#define _TREX_H_ - -/* - * This module uses the T-Rex regular expression library to implement the regex - * logic. Here is the copyright notice of the library: - * - * Copyright (C) 2003-2006 Alberto Demichelis - * - * This software is provided 'as-is', without any express - * or implied warranty. In no event will the authors be held - * liable for any damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for - * any purpose, including commercial applications, and to alter - * it and redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; - * you must not claim that you wrote the original software. - * If you use this software in a product, an acknowledgment - * in the product documentation would be appreciated but - * is not required. - * - * 2. Altered source versions must be plainly marked as such, - * and must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any - * source distribution. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define TRexChar char -#define MAX_CHAR 0xFF -#define _TREXC(c) (c) -#define trex_strlen strlen -#define trex_printf printf - -#ifndef TREX_API -#define TREX_API extern -#endif - -#define TRex_True 1 -#define TRex_False 0 - -#define TREX_ICASE ARG_REX_ICASE - -typedef unsigned int TRexBool; -typedef struct TRex TRex; - -typedef struct { - const TRexChar* begin; - int len; -} TRexMatch; - -#ifdef __GNUC__ -TREX_API TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags) __attribute__((optimize(0))); -#else -TREX_API TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags); -#endif -TREX_API void trex_free(TRex* exp); -TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text); -TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end); -TREX_API TRexBool -trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end); -TREX_API int trex_getsubexpcount(TRex* exp); -TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp); - -#ifdef __cplusplus -} -#endif - -#endif - -struct privhdr { - const char* pattern; - int flags; -}; - -static void arg_rex_resetfn(struct arg_rex* parent) { - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - parent->count = 0; -} - -static int arg_rex_scanfn(struct arg_rex* parent, const char* argval) { - int errorcode = 0; - const TRexChar* error = NULL; - TRex* rex = NULL; - TRexBool is_match = TRex_False; - - if (parent->count == parent->hdr.maxcount) { - /* maximum number of arguments exceeded */ - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* a valid argument with no argument value was given. */ - /* This happens when an optional argument value was invoked. */ - /* leave parent argument value unaltered but still count the argument. */ - parent->count++; - } else { - struct privhdr* priv = (struct privhdr*)parent->hdr.priv; - - /* test the current argument value for a match with the regular expression */ - /* if a match is detected, record the argument value in the arg_rex struct */ - - rex = trex_compile(priv->pattern, &error, priv->flags); - is_match = trex_match(rex, argval); - if (!is_match) - errorcode = ARG_ERR_REGNOMATCH; - else - parent->sval[parent->count++] = argval; - - trex_free(rex); - } - - ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static int arg_rex_checkfn(struct arg_rex* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; -#if 0 - struct privhdr *priv = (struct privhdr*)parent->hdr.priv; - - /* free the regex "program" we constructed in resetfn */ - regfree(&(priv->regex)); - - /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ -#endif - return errorcode; -} - -static void arg_rex_errorfn(struct arg_rex* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - case ARG_ERR_REGNOMATCH: - arg_dstr_cat(ds, "illegal value "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - - default: { - #if 0 - char errbuff[256]; - regerror(errorcode, NULL, errbuff, sizeof(errbuff)); - printf("%s\n", errbuff); - #endif - } break; - } -} - -struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) { - return arg_rexn(shortopts, longopts, pattern, datatype, 0, 1, flags, glossary); -} - -struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) { - return arg_rexn(shortopts, longopts, pattern, datatype, 1, 1, flags, glossary); -} - -struct arg_rex* arg_rexn(const char* shortopts, - const char* longopts, - const char* pattern, - const char* datatype, - int mincount, - int maxcount, - int flags, - const char* glossary) { - size_t nbytes; - struct arg_rex* result; - struct privhdr* priv; - int i; - const TRexChar* error = NULL; - TRex* rex = NULL; - - if (!pattern) { - printf("argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n"); - printf("argtable: Bad argument table.\n"); - return NULL; - } - - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */ - + sizeof(struct privhdr) /* storage for private arg_rex data */ - + maxcount * sizeof(char*); /* storage for sval[maxcount] array */ - - /* init the arg_hdr struct */ - result = (struct arg_rex*)xmalloc(nbytes); - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = datatype ? datatype : pattern; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_rex_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_rex_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_rex_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_rex_errorfn; - - /* store the arg_rex_priv struct immediately after the arg_rex struct */ - result->hdr.priv = result + 1; - priv = (struct privhdr*)(result->hdr.priv); - priv->pattern = pattern; - priv->flags = flags; - - /* store the sval[maxcount] array immediately after the arg_rex_priv struct */ - result->sval = (const char**)(priv + 1); - result->count = 0; - - /* foolproof the string pointers by initializing them to reference empty strings */ - for (i = 0; i < maxcount; i++) - result->sval[i] = ""; - - /* here we construct and destroy a regex representation of the regular - * expression for no other reason than to force any regex errors to be - * trapped now rather than later. If we don't, then errors may go undetected - * until an argument is actually parsed. - */ - - rex = trex_compile(priv->pattern, &error, priv->flags); - if (rex == NULL) { - ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern)); - ARG_LOG(("argtable: Bad argument table.\n")); - } - - trex_free(rex); - - ARG_TRACE(("arg_rexn() returns %p\n", result)); - return result; -} - -/* see copyright notice in trex.h */ -#include -#include -#include -#include - -#ifdef _UINCODE -#define scisprint iswprint -#define scstrlen wcslen -#define scprintf wprintf -#define _SC(x) L(x) -#else -#define scisprint isprint -#define scstrlen strlen -#define scprintf printf -#define _SC(x) (x) -#endif - -#ifdef ARG_REX_DEBUG -#include - -static const TRexChar* g_nnames[] = {_SC("NONE"), _SC("OP_GREEDY"), _SC("OP_OR"), _SC("OP_EXPR"), _SC("OP_NOCAPEXPR"), - _SC("OP_DOT"), _SC("OP_CLASS"), _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"), - _SC("OP_CHAR"), _SC("OP_EOL"), _SC("OP_BOL"), _SC("OP_WB")}; - -#endif -#define OP_GREEDY (MAX_CHAR + 1) /* * + ? {n} */ -#define OP_OR (MAX_CHAR + 2) -#define OP_EXPR (MAX_CHAR + 3) /* parentesis () */ -#define OP_NOCAPEXPR (MAX_CHAR + 4) /* parentesis (?:) */ -#define OP_DOT (MAX_CHAR + 5) -#define OP_CLASS (MAX_CHAR + 6) -#define OP_CCLASS (MAX_CHAR + 7) -#define OP_NCLASS (MAX_CHAR + 8) /* negates class the [^ */ -#define OP_RANGE (MAX_CHAR + 9) -#define OP_CHAR (MAX_CHAR + 10) -#define OP_EOL (MAX_CHAR + 11) -#define OP_BOL (MAX_CHAR + 12) -#define OP_WB (MAX_CHAR + 13) - -#define TREX_SYMBOL_ANY_CHAR ('.') -#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') -#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') -#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') -#define TREX_SYMBOL_BRANCH ('|') -#define TREX_SYMBOL_END_OF_STRING ('$') -#define TREX_SYMBOL_BEGINNING_OF_STRING ('^') -#define TREX_SYMBOL_ESCAPE_CHAR ('\\') - -typedef int TRexNodeType; - -typedef struct tagTRexNode { - TRexNodeType type; - int left; - int right; - int next; -} TRexNode; - -struct TRex { - const TRexChar* _eol; - const TRexChar* _bol; - const TRexChar* _p; - int _first; - int _op; - TRexNode* _nodes; - int _nallocated; - int _nsize; - int _nsubexpr; - TRexMatch* _matches; - int _currsubexp; - void* _jmpbuf; - const TRexChar** _error; - int _flags; -}; - -static int trex_list(TRex* exp); - -static int trex_newnode(TRex* exp, TRexNodeType type) { - TRexNode n; - int newid; - n.type = type; - n.next = n.right = n.left = -1; - if (type == OP_EXPR) - n.right = exp->_nsubexpr++; - if (exp->_nallocated < (exp->_nsize + 1)) { - exp->_nallocated *= 2; - exp->_nodes = (TRexNode*)xrealloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode)); - } - exp->_nodes[exp->_nsize++] = n; - newid = exp->_nsize - 1; - return (int)newid; -} - -static void trex_error(TRex* exp, const TRexChar* error) { - if (exp->_error) - *exp->_error = error; - longjmp(*((jmp_buf*)exp->_jmpbuf), -1); -} - -static void trex_expect(TRex* exp, int n) { - if ((*exp->_p) != n) - trex_error(exp, _SC("expected paren")); - exp->_p++; -} - -static TRexChar trex_escapechar(TRex* exp) { - if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) { - exp->_p++; - switch (*exp->_p) { - case 'v': - exp->_p++; - return '\v'; - case 'n': - exp->_p++; - return '\n'; - case 't': - exp->_p++; - return '\t'; - case 'r': - exp->_p++; - return '\r'; - case 'f': - exp->_p++; - return '\f'; - default: - return (*exp->_p++); - } - } else if (!scisprint(*exp->_p)) - trex_error(exp, _SC("letter expected")); - return (*exp->_p++); -} - -static int trex_charclass(TRex* exp, int classid) { - int n = trex_newnode(exp, OP_CCLASS); - exp->_nodes[n].left = classid; - return n; -} - -static int trex_charnode(TRex* exp, TRexBool isclass) { - TRexChar t; - if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) { - exp->_p++; - switch (*exp->_p) { - case 'n': - exp->_p++; - return trex_newnode(exp, '\n'); - case 't': - exp->_p++; - return trex_newnode(exp, '\t'); - case 'r': - exp->_p++; - return trex_newnode(exp, '\r'); - case 'f': - exp->_p++; - return trex_newnode(exp, '\f'); - case 'v': - exp->_p++; - return trex_newnode(exp, '\v'); - case 'a': - case 'A': - case 'w': - case 'W': - case 's': - case 'S': - case 'd': - case 'D': - case 'x': - case 'X': - case 'c': - case 'C': - case 'p': - case 'P': - case 'l': - case 'u': { - t = *exp->_p; - exp->_p++; - return trex_charclass(exp, t); - } - case 'b': - case 'B': - if (!isclass) { - int node = trex_newnode(exp, OP_WB); - exp->_nodes[node].left = *exp->_p; - exp->_p++; - return node; - } - /* fall through */ - default: - t = *exp->_p; - exp->_p++; - return trex_newnode(exp, t); - } - } else if (!scisprint(*exp->_p)) { - trex_error(exp, _SC("letter expected")); - } - t = *exp->_p; - exp->_p++; - return trex_newnode(exp, t); -} -static int trex_class(TRex* exp) { - int ret = -1; - int first = -1, chain; - if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) { - ret = trex_newnode(exp, OP_NCLASS); - exp->_p++; - } else - ret = trex_newnode(exp, OP_CLASS); - - if (*exp->_p == ']') - trex_error(exp, _SC("empty class")); - chain = ret; - while (*exp->_p != ']' && exp->_p != exp->_eol) { - if (*exp->_p == '-' && first != -1) { - int r, t; - if (*exp->_p++ == ']') - trex_error(exp, _SC("unfinished range")); - r = trex_newnode(exp, OP_RANGE); - if (first > *exp->_p) - trex_error(exp, _SC("invalid range")); - if (exp->_nodes[first].type == OP_CCLASS) - trex_error(exp, _SC("cannot use character classes in ranges")); - exp->_nodes[r].left = exp->_nodes[first].type; - t = trex_escapechar(exp); - exp->_nodes[r].right = t; - exp->_nodes[chain].next = r; - chain = r; - first = -1; - } else { - if (first != -1) { - int c = first; - exp->_nodes[chain].next = c; - chain = c; - first = trex_charnode(exp, TRex_True); - } else { - first = trex_charnode(exp, TRex_True); - } - } - } - if (first != -1) { - int c = first; - exp->_nodes[chain].next = c; - chain = c; - first = -1; - } - /* hack? */ - exp->_nodes[ret].left = exp->_nodes[ret].next; - exp->_nodes[ret].next = -1; - return ret; -} - -static int trex_parsenumber(TRex* exp) { - int ret = *exp->_p - '0'; - int positions = 10; - exp->_p++; - while (isdigit(*exp->_p)) { - ret = ret * 10 + (*exp->_p++ - '0'); - if (positions == 1000000000) - trex_error(exp, _SC("overflow in numeric constant")); - positions *= 10; - }; - return ret; -} - -static int trex_element(TRex* exp) { - int ret = -1; - switch (*exp->_p) { - case '(': { - int expr, newn; - exp->_p++; - - if (*exp->_p == '?') { - exp->_p++; - trex_expect(exp, ':'); - expr = trex_newnode(exp, OP_NOCAPEXPR); - } else - expr = trex_newnode(exp, OP_EXPR); - newn = trex_list(exp); - exp->_nodes[expr].left = newn; - ret = expr; - trex_expect(exp, ')'); - } break; - case '[': - exp->_p++; - ret = trex_class(exp); - trex_expect(exp, ']'); - break; - case TREX_SYMBOL_END_OF_STRING: - exp->_p++; - ret = trex_newnode(exp, OP_EOL); - break; - case TREX_SYMBOL_ANY_CHAR: - exp->_p++; - ret = trex_newnode(exp, OP_DOT); - break; - default: - ret = trex_charnode(exp, TRex_False); - break; - } - - { - TRexBool isgreedy = TRex_False; - unsigned short p0 = 0, p1 = 0; - switch (*exp->_p) { - case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: - p0 = 0; - p1 = 0xFFFF; - exp->_p++; - isgreedy = TRex_True; - break; - case TREX_SYMBOL_GREEDY_ONE_OR_MORE: - p0 = 1; - p1 = 0xFFFF; - exp->_p++; - isgreedy = TRex_True; - break; - case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: - p0 = 0; - p1 = 1; - exp->_p++; - isgreedy = TRex_True; - break; - case '{': - exp->_p++; - if (!isdigit(*exp->_p)) - trex_error(exp, _SC("number expected")); - p0 = (unsigned short)trex_parsenumber(exp); - /*******************************/ - switch (*exp->_p) { - case '}': - p1 = p0; - exp->_p++; - break; - case ',': - exp->_p++; - p1 = 0xFFFF; - if (isdigit(*exp->_p)) { - p1 = (unsigned short)trex_parsenumber(exp); - } - trex_expect(exp, '}'); - break; - default: - trex_error(exp, _SC(", or } expected")); - } - /*******************************/ - isgreedy = TRex_True; - break; - } - if (isgreedy) { - int nnode = trex_newnode(exp, OP_GREEDY); - exp->_nodes[nnode].left = ret; - exp->_nodes[nnode].right = ((p0) << 16) | p1; - ret = nnode; - } - } - if ((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && - (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { - int nnode = trex_element(exp); - exp->_nodes[ret].next = nnode; - } - - return ret; -} - -static int trex_list(TRex* exp) { - int ret = -1, e; - if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) { - exp->_p++; - ret = trex_newnode(exp, OP_BOL); - } - e = trex_element(exp); - if (ret != -1) { - exp->_nodes[ret].next = e; - } else - ret = e; - - if (*exp->_p == TREX_SYMBOL_BRANCH) { - int temp, tright; - exp->_p++; - temp = trex_newnode(exp, OP_OR); - exp->_nodes[temp].left = ret; - tright = trex_list(exp); - exp->_nodes[temp].right = tright; - ret = temp; - } - return ret; -} - -static TRexBool trex_matchcclass(int cclass, TRexChar c) { - switch (cclass) { - case 'a': - return isalpha(c) ? TRex_True : TRex_False; - case 'A': - return !isalpha(c) ? TRex_True : TRex_False; - case 'w': - return (isalnum(c) || c == '_') ? TRex_True : TRex_False; - case 'W': - return (!isalnum(c) && c != '_') ? TRex_True : TRex_False; - case 's': - return isspace(c) ? TRex_True : TRex_False; - case 'S': - return !isspace(c) ? TRex_True : TRex_False; - case 'd': - return isdigit(c) ? TRex_True : TRex_False; - case 'D': - return !isdigit(c) ? TRex_True : TRex_False; - case 'x': - return isxdigit(c) ? TRex_True : TRex_False; - case 'X': - return !isxdigit(c) ? TRex_True : TRex_False; - case 'c': - return iscntrl(c) ? TRex_True : TRex_False; - case 'C': - return !iscntrl(c) ? TRex_True : TRex_False; - case 'p': - return ispunct(c) ? TRex_True : TRex_False; - case 'P': - return !ispunct(c) ? TRex_True : TRex_False; - case 'l': - return islower(c) ? TRex_True : TRex_False; - case 'u': - return isupper(c) ? TRex_True : TRex_False; - } - return TRex_False; /*cannot happen*/ -} - -static TRexBool trex_matchclass(TRex* exp, TRexNode* node, TRexChar c) { - do { - switch (node->type) { - case OP_RANGE: - if (exp->_flags & TREX_ICASE) { - if (c >= toupper(node->left) && c <= toupper(node->right)) - return TRex_True; - if (c >= tolower(node->left) && c <= tolower(node->right)) - return TRex_True; - } else { - if (c >= node->left && c <= node->right) - return TRex_True; - } - break; - case OP_CCLASS: - if (trex_matchcclass(node->left, c)) - return TRex_True; - break; - default: - if (exp->_flags & TREX_ICASE) { - if (c == tolower(node->type) || c == toupper(node->type)) - return TRex_True; - } else { - if (c == node->type) - return TRex_True; - } - } - } while ((node->next != -1) && ((node = &exp->_nodes[node->next]) != NULL)); - return TRex_False; -} - -static const TRexChar* trex_matchnode(TRex* exp, TRexNode* node, const TRexChar* str, TRexNode* next) { - TRexNodeType type = node->type; - switch (type) { - case OP_GREEDY: { - /* TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; */ - TRexNode* greedystop = NULL; - int p0 = (node->right >> 16) & 0x0000FFFF, p1 = node->right & 0x0000FFFF, nmaches = 0; - const TRexChar *s = str, *good = str; - - if (node->next != -1) { - greedystop = &exp->_nodes[node->next]; - } else { - greedystop = next; - } - - while ((nmaches == 0xFFFF || nmaches < p1)) { - const TRexChar* stop; - if ((s = trex_matchnode(exp, &exp->_nodes[node->left], s, greedystop)) == NULL) - break; - nmaches++; - good = s; - if (greedystop) { - /* checks that 0 matches satisfy the expression(if so skips) */ - /* if not would always stop(for instance if is a '?') */ - if (greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16) & 0x0000FFFF) != 0)) { - TRexNode* gnext = NULL; - if (greedystop->next != -1) { - gnext = &exp->_nodes[greedystop->next]; - } else if (next && next->next != -1) { - gnext = &exp->_nodes[next->next]; - } - stop = trex_matchnode(exp, greedystop, s, gnext); - if (stop) { - /* if satisfied stop it */ - if (p0 == p1 && p0 == nmaches) - break; - else if (nmaches >= p0 && p1 == 0xFFFF) - break; - else if (nmaches >= p0 && nmaches <= p1) - break; - } - } - } - - if (s >= exp->_eol) - break; - } - if (p0 == p1 && p0 == nmaches) - return good; - else if (nmaches >= p0 && p1 == 0xFFFF) - return good; - else if (nmaches >= p0 && nmaches <= p1) - return good; - return NULL; - } - case OP_OR: { - const TRexChar* asd = str; - TRexNode* temp = &exp->_nodes[node->left]; - while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) { - if (temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - asd = str; - temp = &exp->_nodes[node->right]; - while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) { - if (temp->next != -1) - temp = &exp->_nodes[temp->next]; - else - return asd; - } - return NULL; - break; - } - case OP_EXPR: - case OP_NOCAPEXPR: { - TRexNode* n = &exp->_nodes[node->left]; - const TRexChar* cur = str; - int capture = -1; - if (node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { - capture = exp->_currsubexp; - exp->_matches[capture].begin = cur; - exp->_currsubexp++; - } - - do { - TRexNode* subnext = NULL; - if (n->next != -1) { - subnext = &exp->_nodes[n->next]; - } else { - subnext = next; - } - if ((cur = trex_matchnode(exp, n, cur, subnext)) == NULL) { - if (capture != -1) { - exp->_matches[capture].begin = 0; - exp->_matches[capture].len = 0; - } - return NULL; - } - } while ((n->next != -1) && ((n = &exp->_nodes[n->next]) != NULL)); - - if (capture != -1) - exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin); - return cur; - } - case OP_WB: - if ((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str - 1))) || (!isspace(*str) && isspace(*(str + 1))) || - (isspace(*str) && !isspace(*(str + 1)))) { - return (node->left == 'b') ? str : NULL; - } - return (node->left == 'b') ? NULL : str; - case OP_BOL: - if (str == exp->_bol) - return str; - return NULL; - case OP_EOL: - if (str == exp->_eol) - return str; - return NULL; - case OP_DOT: { - str++; - } - return str; - case OP_NCLASS: - case OP_CLASS: - if (trex_matchclass(exp, &exp->_nodes[node->left], *str) ? (type == OP_CLASS ? TRex_True : TRex_False) - : (type == OP_NCLASS ? TRex_True : TRex_False)) { - str++; - return str; - } - return NULL; - case OP_CCLASS: - if (trex_matchcclass(node->left, *str)) { - str++; - return str; - } - return NULL; - default: /* char */ - if (exp->_flags & TREX_ICASE) { - if (*str != tolower(node->type) && *str != toupper(node->type)) - return NULL; - } else { - if (*str != node->type) - return NULL; - } - str++; - return str; - } -} - -/* public api */ -TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags) { - TRex* exp = (TRex*)xmalloc(sizeof(TRex)); - exp->_eol = exp->_bol = NULL; - exp->_p = pattern; - exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar); - exp->_nodes = (TRexNode*)xmalloc(exp->_nallocated * sizeof(TRexNode)); - exp->_nsize = 0; - exp->_matches = 0; - exp->_nsubexpr = 0; - exp->_first = trex_newnode(exp, OP_EXPR); - exp->_error = error; - exp->_jmpbuf = xmalloc(sizeof(jmp_buf)); - exp->_flags = flags; - if (setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) { - int res = trex_list(exp); - exp->_nodes[exp->_first].left = res; - if (*exp->_p != '\0') - trex_error(exp, _SC("unexpected character")); -#ifdef ARG_REX_DEBUG - { - int nsize, i; - nsize = exp->_nsize; - scprintf(_SC("\n")); - for (i = 0; i < nsize; i++) { - if (exp->_nodes[i].type > MAX_CHAR) - scprintf(_SC("[%02d] %10s "), i, g_nnames[exp->_nodes[i].type - MAX_CHAR]); - else - scprintf(_SC("[%02d] %10c "), i, exp->_nodes[i].type); - scprintf(_SC("left %02d right %02d next %02d\n"), exp->_nodes[i].left, exp->_nodes[i].right, exp->_nodes[i].next); - } - scprintf(_SC("\n")); - } -#endif - exp->_matches = (TRexMatch*)xmalloc(exp->_nsubexpr * sizeof(TRexMatch)); - memset(exp->_matches, 0, exp->_nsubexpr * sizeof(TRexMatch)); - } else { - trex_free(exp); - return NULL; - } - return exp; -} - -void trex_free(TRex* exp) { - if (exp) { - xfree(exp->_nodes); - xfree(exp->_jmpbuf); - xfree(exp->_matches); - xfree(exp); - } -} - -TRexBool trex_match(TRex* exp, const TRexChar* text) { - const TRexChar* res = NULL; - exp->_bol = text; - exp->_eol = text + scstrlen(text); - exp->_currsubexp = 0; - res = trex_matchnode(exp, exp->_nodes, text, NULL); - if (res == NULL || res != exp->_eol) - return TRex_False; - return TRex_True; -} - -TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end) { - const TRexChar* cur = NULL; - int node = exp->_first; - if (text_begin >= text_end) - return TRex_False; - exp->_bol = text_begin; - exp->_eol = text_end; - do { - cur = text_begin; - while (node != -1) { - exp->_currsubexp = 0; - cur = trex_matchnode(exp, &exp->_nodes[node], cur, NULL); - if (!cur) - break; - node = exp->_nodes[node].next; - } - text_begin++; - } while (cur == NULL && text_begin != text_end); - - if (cur == NULL) - return TRex_False; - - --text_begin; - - if (out_begin) - *out_begin = text_begin; - if (out_end) - *out_end = cur; - return TRex_True; -} - -TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) { - return trex_searchrange(exp, text, text + scstrlen(text), out_begin, out_end); -} - -int trex_getsubexpcount(TRex* exp) { - return exp->_nsubexpr; -} - -TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp) { - if (n < 0 || n >= exp->_nsubexpr) - return TRex_False; - *subexp = exp->_matches[n]; - return TRex_True; -} -/******************************************************************************* - * arg_str: Implements the str command-line option - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include - -static void arg_str_resetfn(struct arg_str* parent) { - int i; - - ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); - for (i = 0; i < parent->count; i++) { - parent->sval[i] = ""; - } - parent->count = 0; -} - -static int arg_str_scanfn(struct arg_str* parent, const char* argval) { - int errorcode = 0; - - if (parent->count == parent->hdr.maxcount) { - /* maximum number of arguments exceeded */ - errorcode = ARG_ERR_MAXCOUNT; - } else if (!argval) { - /* a valid argument with no argument value was given. */ - /* This happens when an optional argument value was invoked. */ - /* leave parent argument value unaltered but still count the argument. */ - parent->count++; - } else { - parent->sval[parent->count++] = argval; - } - - ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static int arg_str_checkfn(struct arg_str* parent) { - int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0; - - ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode)); - return errorcode; -} - -static void arg_str_errorfn(struct arg_str* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) { - const char* shortopts = parent->hdr.shortopts; - const char* longopts = parent->hdr.longopts; - const char* datatype = parent->hdr.datatype; - - /* make argval NULL safe */ - argval = argval ? argval : ""; - - arg_dstr_catf(ds, "%s: ", progname); - switch (errorcode) { - case ARG_ERR_MINCOUNT: - arg_dstr_cat(ds, "missing option "); - arg_print_option_ds(ds, shortopts, longopts, datatype, "\n"); - break; - - case ARG_ERR_MAXCOUNT: - arg_dstr_cat(ds, "excess option "); - arg_print_option_ds(ds, shortopts, longopts, argval, "\n"); - break; - } -} - -struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_strn(shortopts, longopts, datatype, 0, 1, glossary); -} - -struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) { - return arg_strn(shortopts, longopts, datatype, 1, 1, glossary); -} - -struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) { - size_t nbytes; - struct arg_str* result; - int i; - - /* should not allow this stupid error */ - /* we should return an error code warning this logic error */ - /* foolproof things by ensuring maxcount is not less than mincount */ - maxcount = (maxcount < mincount) ? mincount : maxcount; - - nbytes = sizeof(struct arg_str) /* storage for struct arg_str */ - + maxcount * sizeof(char*); /* storage for sval[maxcount] array */ - - result = (struct arg_str*)xmalloc(nbytes); - - /* init the arg_hdr struct */ - result->hdr.flag = ARG_HASVALUE; - result->hdr.shortopts = shortopts; - result->hdr.longopts = longopts; - result->hdr.datatype = datatype ? datatype : ""; - result->hdr.glossary = glossary; - result->hdr.mincount = mincount; - result->hdr.maxcount = maxcount; - result->hdr.parent = result; - result->hdr.resetfn = (arg_resetfn*)arg_str_resetfn; - result->hdr.scanfn = (arg_scanfn*)arg_str_scanfn; - result->hdr.checkfn = (arg_checkfn*)arg_str_checkfn; - result->hdr.errorfn = (arg_errorfn*)arg_str_errorfn; - - /* store the sval[maxcount] array immediately after the arg_str struct */ - result->sval = (const char**)(result + 1); - result->count = 0; - - /* foolproof the string pointers by initializing them to reference empty strings */ - for (i = 0; i < maxcount; i++) - result->sval[i] = ""; - - ARG_TRACE(("arg_strn() returns %p\n", result)); - return result; -} -/******************************************************************************* - * arg_cmd: Provides the sub-command mechanism - * - * This file is part of the argtable3 library. - * - * Copyright (C) 2013-2019 Tom G. Huang - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#endif - -#include -#include -#include - -#define MAX_MODULE_VERSION_SIZE 128 - -static arg_hashtable_t* s_hashtable = NULL; -static char* s_module_name = NULL; -static int s_mod_ver_major = 0; -static int s_mod_ver_minor = 0; -static int s_mod_ver_patch = 0; -static char* s_mod_ver_tag = NULL; -static char* s_mod_ver = NULL; - -void arg_set_module_name(const char* name) { - size_t slen; - - xfree(s_module_name); - slen = strlen(name); - s_module_name = (char*)xmalloc(slen + 1); - memset(s_module_name, 0, slen + 1); - -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncpy_s(s_module_name, slen + 1, name, slen); -#else - memcpy(s_module_name, name, slen); -#endif -} - -void arg_set_module_version(int major, int minor, int patch, const char* tag) { - size_t slen_tag, slen_ds; - arg_dstr_t ds; - - s_mod_ver_major = major; - s_mod_ver_minor = minor; - s_mod_ver_patch = patch; - - xfree(s_mod_ver_tag); - slen_tag = strlen(tag); - s_mod_ver_tag = (char*)xmalloc(slen_tag + 1); - memset(s_mod_ver_tag, 0, slen_tag + 1); - -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncpy_s(s_mod_ver_tag, slen_tag + 1, tag, slen_tag); -#else - memcpy(s_mod_ver_tag, tag, slen_tag); -#endif - - ds = arg_dstr_create(); - arg_dstr_catf(ds, "%d.", s_mod_ver_major); - arg_dstr_catf(ds, "%d.", s_mod_ver_minor); - arg_dstr_catf(ds, "%d.", s_mod_ver_patch); - arg_dstr_cat(ds, s_mod_ver_tag); - - xfree(s_mod_ver); - slen_ds = strlen(arg_dstr_cstr(ds)); - s_mod_ver = (char*)xmalloc(slen_ds + 1); - memset(s_mod_ver, 0, slen_ds + 1); - -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncpy_s(s_mod_ver, slen_ds + 1, arg_dstr_cstr(ds), slen_ds); -#else - memcpy(s_mod_ver, arg_dstr_cstr(ds), slen_ds); -#endif - - arg_dstr_destroy(ds); -} - -static unsigned int hash_key(const void* key) { - const char* str = (const char*)key; - int c; - unsigned int hash = 5381; - - while ((c = *str++) != 0) - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - - return hash; -} - -static int equal_keys(const void* key1, const void* key2) { - char* k1 = (char*)key1; - char* k2 = (char*)key2; - return (0 == strcmp(k1, k2)); -} - -void arg_cmd_init(void) { - s_hashtable = arg_hashtable_create(32, hash_key, equal_keys); -} - -void arg_cmd_uninit(void) { - arg_hashtable_destroy(s_hashtable, 1); -} - -void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description) { - arg_cmd_info_t* cmd_info; - size_t slen_name; - void* k; - - assert(strlen(name) < ARG_CMD_NAME_LEN); - assert(strlen(description) < ARG_CMD_DESCRIPTION_LEN); - - /* Check if the command already exists. */ - /* If the command exists, replace the existing command. */ - /* If the command doesn't exist, insert the command. */ - cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name); - if (cmd_info) { - arg_hashtable_remove(s_hashtable, name); - cmd_info = NULL; - } - - cmd_info = (arg_cmd_info_t*)xmalloc(sizeof(arg_cmd_info_t)); - memset(cmd_info, 0, sizeof(arg_cmd_info_t)); - -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncpy_s(cmd_info->name, ARG_CMD_NAME_LEN, name, strlen(name)); - strncpy_s(cmd_info->description, ARG_CMD_DESCRIPTION_LEN, description, strlen(description)); -#else - memcpy(cmd_info->name, name, strlen(name)); - memcpy(cmd_info->description, description, strlen(description)); -#endif - - cmd_info->proc = proc; - - slen_name = strlen(name); - k = xmalloc(slen_name + 1); - memset(k, 0, slen_name + 1); - -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncpy_s((char*)k, slen_name + 1, name, slen_name); -#else - memcpy((char*)k, name, slen_name); -#endif - - arg_hashtable_insert(s_hashtable, k, cmd_info); -} - -void arg_cmd_unregister(const char* name) { - arg_hashtable_remove(s_hashtable, name); -} - -int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res) { - arg_cmd_info_t* cmd_info = arg_cmd_info(name); - - assert(cmd_info != NULL); - assert(cmd_info->proc != NULL); - - return cmd_info->proc(argc, argv, res); -} - -arg_cmd_info_t* arg_cmd_info(const char* name) { - return (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name); -} - -unsigned int arg_cmd_count(void) { - return arg_hashtable_count(s_hashtable); -} - -arg_cmd_itr_t arg_cmd_itr_create(void) { - return (arg_cmd_itr_t)arg_hashtable_itr_create(s_hashtable); -} - -int arg_cmd_itr_advance(arg_cmd_itr_t itr) { - return arg_hashtable_itr_advance((arg_hashtable_itr_t*)itr); -} - -char* arg_cmd_itr_key(arg_cmd_itr_t itr) { - return (char*)arg_hashtable_itr_key((arg_hashtable_itr_t*)itr); -} - -arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr) { - return (arg_cmd_info_t*)arg_hashtable_itr_value((arg_hashtable_itr_t*)itr); -} - -void arg_cmd_itr_destroy(arg_cmd_itr_t itr) { - arg_hashtable_itr_destroy((arg_hashtable_itr_t*)itr); -} - -int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k) { - return arg_hashtable_itr_search((arg_hashtable_itr_t*)itr, s_hashtable, k); -} - -static const char* module_name(void) { - if (s_module_name == NULL || strlen(s_module_name) == 0) - return ""; - - return s_module_name; -} - -static const char* module_version(void) { - if (s_mod_ver == NULL || strlen(s_mod_ver) == 0) - return "0.0.0.0"; - - return s_mod_ver; -} - -void arg_make_get_help_msg(arg_dstr_t res) { - arg_dstr_catf(res, "%s v%s\n", module_name(), module_version()); - arg_dstr_catf(res, "Please type '%s help' to get more information.\n", module_name()); -} - -void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable) { - arg_cmd_info_t* cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, cmd_name); - if (cmd_info) { - arg_dstr_catf(ds, "%s: %s\n", cmd_name, cmd_info->description); - } - - arg_dstr_cat(ds, "Usage:\n"); - arg_dstr_catf(ds, " %s", module_name()); - - arg_print_syntaxv_ds(ds, argtable, "\n \nAvailable options:\n"); - arg_print_glossary_ds(ds, argtable, " %-23s %s\n"); - - arg_dstr_cat(ds, "\n"); -} - -void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end) { - arg_print_errors_ds(ds, end, module_name()); - arg_dstr_cat(ds, "Usage: \n"); - arg_dstr_catf(ds, " %s", module_name()); - arg_print_syntaxv_ds(ds, argtable, "\n"); - arg_dstr_cat(ds, "\n"); -} - -int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode) { - /* help handling - * note: '-h|--help' takes precedence over error reporting - */ - if (help > 0) { - arg_make_help_msg(ds, name, argtable); - *exitcode = EXIT_SUCCESS; - return 1; - } - - /* syntax error handling */ - if (nerrors > 0) { - arg_make_syntax_err_msg(ds, argtable, end); - *exitcode = EXIT_FAILURE; - return 1; - } - - return 0; -} -/******************************************************************************* - * argtable3: Implements the main interfaces of the library - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#include "argtable3.h" - -#ifndef ARG_AMALGAMATION -#include "argtable3_private.h" -#if ARG_REPLACE_GETOPT == 1 -#include "arg_getopt.h" -#else -#include -#endif -#else -#if ARG_REPLACE_GETOPT == 0 -#include -#endif -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN -#endif - -#include -#include -#include -#include -#include - -static void arg_register_error(struct arg_end* end, void* parent, int error, const char* argval) { - /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */ - if (end->count < end->hdr.maxcount) { - end->error[end->count] = error; - end->parent[end->count] = parent; - end->argval[end->count] = argval; - end->count++; - } else { - end->error[end->hdr.maxcount - 1] = ARG_ELIMIT; - end->parent[end->hdr.maxcount - 1] = end; - end->argval[end->hdr.maxcount - 1] = NULL; - } -} - -/* - * Return index of first table entry with a matching short option - * or -1 if no match was found. - */ -static int find_shortoption(struct arg_hdr** table, char shortopt) { - int tabindex; - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - if (table[tabindex]->shortopts && strchr(table[tabindex]->shortopts, shortopt)) - return tabindex; - } - return -1; -} - -struct longoptions { - int getoptval; - int noptions; - struct option* options; -}; - -#if 0 -static -void dump_longoptions(struct longoptions * longoptions) -{ - int i; - printf("getoptval = %d\n", longoptions->getoptval); - printf("noptions = %d\n", longoptions->noptions); - for (i = 0; i < longoptions->noptions; i++) - { - printf("options[%d].name = \"%s\"\n", - i, - longoptions->options[i].name); - printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg); - printf("options[%d].flag = %p\n", i, longoptions->options[i].flag); - printf("options[%d].val = %d\n", i, longoptions->options[i].val); - } -} -#endif - -static struct longoptions* alloc_longoptions(struct arg_hdr** table) { - struct longoptions* result; - size_t nbytes; - int noptions = 1; - size_t longoptlen = 0; - int tabindex; - int option_index = 0; - char* store; - - /* - * Determine the total number of option structs required - * by counting the number of comma separated long options - * in all table entries and return the count in noptions. - * note: noptions starts at 1 not 0 because we getoptlong - * requires a NULL option entry to terminate the option array. - * While we are at it, count the number of chars required - * to store private copies of all the longoption strings - * and return that count in logoptlen. - */ - tabindex = 0; - do { - const char* longopts = table[tabindex]->longopts; - longoptlen += (longopts ? strlen(longopts) : 0) + 1; - while (longopts) { - noptions++; - longopts = strchr(longopts + 1, ','); - } - } while (!(table[tabindex++]->flag & ARG_TERMINATOR)); - /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/ - - /* allocate storage for return data structure as: */ - /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */ - nbytes = sizeof(struct longoptions) + sizeof(struct option) * noptions + longoptlen; - result = (struct longoptions*)xmalloc(nbytes); - - result->getoptval = 0; - result->noptions = noptions; - result->options = (struct option*)(result + 1); - store = (char*)(result->options + noptions); - - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - const char* longopts = table[tabindex]->longopts; - - while (longopts && *longopts) { - char* storestart = store; - - /* copy progressive longopt strings into the store */ - while (*longopts != 0 && *longopts != ',') - *store++ = *longopts++; - *store++ = 0; - if (*longopts == ',') - longopts++; - /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/ - - result->options[option_index].name = storestart; - result->options[option_index].flag = &(result->getoptval); - result->options[option_index].val = tabindex; - if (table[tabindex]->flag & ARG_HASOPTVALUE) - result->options[option_index].has_arg = 2; - else if (table[tabindex]->flag & ARG_HASVALUE) - result->options[option_index].has_arg = 1; - else - result->options[option_index].has_arg = 0; - - option_index++; - } - } - /* terminate the options array with a zero-filled entry */ - result->options[option_index].name = 0; - result->options[option_index].has_arg = 0; - result->options[option_index].flag = 0; - result->options[option_index].val = 0; - - /*dump_longoptions(result);*/ - return result; -} - -static char* alloc_shortoptions(struct arg_hdr** table) { - char* result; - size_t len = 2; - int tabindex; - char* res; - - /* determine the total number of option chars required */ - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - struct arg_hdr* hdr = table[tabindex]; - len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0); - } - - result = xmalloc(len); - - res = result; - - /* add a leading ':' so getopt return codes distinguish */ - /* unrecognised option and options missing argument values */ - *res++ = ':'; - - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - struct arg_hdr* hdr = table[tabindex]; - const char* shortopts = hdr->shortopts; - while (shortopts && *shortopts) { - *res++ = *shortopts++; - if (hdr->flag & ARG_HASVALUE) - *res++ = ':'; - if (hdr->flag & ARG_HASOPTVALUE) - *res++ = ':'; - } - } - /* null terminate the string */ - *res = 0; - - /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/ - return result; -} - -/* return index of the table terminator entry */ -static int arg_endindex(struct arg_hdr** table) { - int tabindex = 0; - while (!(table[tabindex]->flag & ARG_TERMINATOR)) - tabindex++; - return tabindex; -} - -static void arg_parse_tagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) { - struct longoptions* longoptions; - char* shortoptions; - int copt; - - /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ - - /* allocate short and long option arrays for the given opttable[]. */ - /* if the allocs fail then put an error msg in the last table entry. */ - longoptions = alloc_longoptions(table); - shortoptions = alloc_shortoptions(table); - - /*dump_longoptions(longoptions);*/ - - /* reset getopts internal option-index to zero, and disable error reporting */ - optind = 0; - opterr = 0; - - /* fetch and process args using getopt_long */ -#ifdef ARG_LONG_ONLY - while ((copt = getopt_long_only(argc, argv, shortoptions, longoptions->options, NULL)) != -1) { -#else - while ((copt = getopt_long(argc, argv, shortoptions, longoptions->options, NULL)) != -1) { -#endif - /* - printf("optarg='%s'\n",optarg); - printf("optind=%d\n",optind); - printf("copt=%c\n",(char)copt); - printf("optopt=%c (%d)\n",optopt, (int)(optopt)); - */ - switch (copt) { - case 0: { - int tabindex = longoptions->getoptval; - void* parent = table[tabindex]->parent; - /*printf("long option detected from argtable[%d]\n", tabindex);*/ - if (optarg && optarg[0] == 0 && (table[tabindex]->flag & ARG_HASVALUE)) { - /* printf(": long option %s requires an argument\n",argv[optind-1]); */ - arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]); - /* continue to scan the (empty) argument value to enforce argument count checking */ - } - if (table[tabindex]->scanfn) { - int errorcode = table[tabindex]->scanfn(parent, optarg); - if (errorcode != 0) - arg_register_error(endtable, parent, errorcode, optarg); - } - } break; - - case '?': - /* - * getopt_long() found an unrecognised short option. - * if it was a short option its value is in optopt - * if it was a long option then optopt=0 - */ - switch (optopt) { - case 0: - /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/ - arg_register_error(endtable, endtable, ARG_ELONGOPT, argv[optind - 1]); - break; - default: - /*printf("?* unrecognised short option '%c'\n",optopt);*/ - arg_register_error(endtable, endtable, optopt, NULL); - break; - } - break; - - case ':': - /* - * getopt_long() found an option with its argument missing. - */ - /*printf(": option %s requires an argument\n",argv[optind-1]); */ - arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]); - break; - - default: { - /* getopt_long() found a valid short option */ - int tabindex = find_shortoption(table, (char)copt); - /*printf("short option detected from argtable[%d]\n", tabindex);*/ - if (tabindex == -1) { - /* should never get here - but handle it just in case */ - /*printf("unrecognised short option %d\n",copt);*/ - arg_register_error(endtable, endtable, copt, NULL); - } else { - if (table[tabindex]->scanfn) { - void* parent = table[tabindex]->parent; - int errorcode = table[tabindex]->scanfn(parent, optarg); - if (errorcode != 0) - arg_register_error(endtable, parent, errorcode, optarg); - } - } - break; - } - } - } - - xfree(shortoptions); - xfree(longoptions); -} - -static void arg_parse_untagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) { - int tabindex = 0; - int errorlast = 0; - const char* optarglast = NULL; - void* parentlast = NULL; - - /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/ - while (!(table[tabindex]->flag & ARG_TERMINATOR)) { - void* parent; - int errorcode; - - /* if we have exhausted our argv[optind] entries then we have finished */ - if (optind >= argc) { - /*printf("arg_parse_untagged(): argv[] exhausted\n");*/ - return; - } - - /* skip table entries with non-null long or short options (they are not untagged entries) */ - if (table[tabindex]->longopts || table[tabindex]->shortopts) { - /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/ - tabindex++; - continue; - } - - /* skip table entries with NULL scanfn */ - if (!(table[tabindex]->scanfn)) { - /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/ - tabindex++; - continue; - } - - /* attempt to scan the current argv[optind] with the current */ - /* table[tabindex] entry. If it succeeds then keep it, otherwise */ - /* try again with the next table[] entry. */ - parent = table[tabindex]->parent; - errorcode = table[tabindex]->scanfn(parent, argv[optind]); - if (errorcode == 0) { - /* success, move onto next argv[optind] but stay with same table[tabindex] */ - /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/ - optind++; - - /* clear the last tentative error */ - errorlast = 0; - } else { - /* failure, try same argv[optind] with next table[tabindex] entry */ - /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/ - tabindex++; - - /* remember this as a tentative error we may wish to reinstate later */ - errorlast = errorcode; - optarglast = argv[optind]; - parentlast = parent; - } - } - - /* if a tenative error still remains at this point then register it as a proper error */ - if (errorlast) { - arg_register_error(endtable, parentlast, errorlast, optarglast); - optind++; - } - - /* only get here when not all argv[] entries were consumed */ - /* register an error for each unused argv[] entry */ - while (optind < argc) { - /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ - arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]); - } - - return; -} - -static void arg_parse_check(struct arg_hdr** table, struct arg_end* endtable) { - int tabindex = 0; - /* printf("arg_parse_check()\n"); */ - do { - if (table[tabindex]->checkfn) { - void* parent = table[tabindex]->parent; - int errorcode = table[tabindex]->checkfn(parent); - if (errorcode != 0) - arg_register_error(endtable, parent, errorcode, NULL); - } - } while (!(table[tabindex++]->flag & ARG_TERMINATOR)); -} - -static void arg_reset(void** argtable) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int tabindex = 0; - /*printf("arg_reset(%p)\n",argtable);*/ - do { - if (table[tabindex]->resetfn) - table[tabindex]->resetfn(table[tabindex]->parent); - } while (!(table[tabindex++]->flag & ARG_TERMINATOR)); -} - -int arg_parse(int argc, char** argv, void** argtable) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - struct arg_end* endtable; - int endindex; - char** argvcopy = NULL; - int i; - - /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/ - - /* reset any argtable data from previous invocations */ - arg_reset(argtable); - - /* locate the first end-of-table marker within the array */ - endindex = arg_endindex(table); - endtable = (struct arg_end*)table[endindex]; - - /* Special case of argc==0. This can occur on Texas Instruments DSP. */ - /* Failure to trap this case results in an unwanted NULL result from */ - /* the malloc for argvcopy (next code block). */ - if (argc == 0) { - /* We must still perform post-parse checks despite the absence of command line arguments */ - arg_parse_check(table, endtable); - - /* Now we are finished */ - return endtable->count; - } - - argvcopy = (char**)xmalloc(sizeof(char*) * (argc + 1)); - - /* - Fill in the local copy of argv[]. We need a local copy - because getopt rearranges argv[] which adversely affects - susbsequent parsing attempts. - */ - for (i = 0; i < argc; i++) - argvcopy[i] = argv[i]; - - argvcopy[argc] = NULL; - - /* parse the command line (local copy) for tagged options */ - arg_parse_tagged(argc, argvcopy, table, endtable); - - /* parse the command line (local copy) for untagged options */ - arg_parse_untagged(argc, argvcopy, table, endtable); - - /* if no errors so far then perform post-parse checks otherwise dont bother */ - if (endtable->count == 0) - arg_parse_check(table, endtable); - - /* release the local copt of argv[] */ - xfree(argvcopy); - - return endtable->count; -} - -/* - * Concatenate contents of src[] string onto *pdest[] string. - * The *pdest pointer is altered to point to the end of the - * target string and *pndest is decremented by the same number - * of chars. - * Does not append more than *pndest chars into *pdest[] - * so as to prevent buffer overruns. - * Its something like strncat() but more efficient for repeated - * calls on the same destination string. - * Example of use: - * char dest[30] = "good" - * size_t ndest = sizeof(dest); - * char *pdest = dest; - * arg_char(&pdest,"bye ",&ndest); - * arg_char(&pdest,"cruel ",&ndest); - * arg_char(&pdest,"world!",&ndest); - * Results in: - * dest[] == "goodbye cruel world!" - * ndest == 10 - */ -static void arg_cat(char** pdest, const char* src, size_t* pndest) { - char* dest = *pdest; - char* end = dest + *pndest; - - /*locate null terminator of dest string */ - while (dest < end && *dest != 0) - dest++; - - /* concat src string to dest string */ - while (dest < end && *src != 0) - *dest++ = *src++; - - /* null terminate dest string */ - *dest = 0; - - /* update *pdest and *pndest */ - *pndest = end - dest; - *pdest = dest; -} - -static void arg_cat_option(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue) { - if (shortopts) { - char option[3]; - - /* note: option array[] is initialiazed dynamically here to satisfy */ - /* a deficiency in the watcom compiler wrt static array initializers. */ - option[0] = '-'; - option[1] = shortopts[0]; - option[2] = 0; - - arg_cat(&dest, option, &ndest); - if (datatype) { - arg_cat(&dest, " ", &ndest); - if (optvalue) { - arg_cat(&dest, "[", &ndest); - arg_cat(&dest, datatype, &ndest); - arg_cat(&dest, "]", &ndest); - } else - arg_cat(&dest, datatype, &ndest); - } - } else if (longopts) { - size_t ncspn; - - /* add "--" tag prefix */ - arg_cat(&dest, "--", &ndest); - - /* add comma separated option tag */ - ncspn = strcspn(longopts, ","); -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest); -#else - strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest); -#endif - - if (datatype) { - arg_cat(&dest, "=", &ndest); - if (optvalue) { - arg_cat(&dest, "[", &ndest); - arg_cat(&dest, datatype, &ndest); - arg_cat(&dest, "]", &ndest); - } else - arg_cat(&dest, datatype, &ndest); - } - } else if (datatype) { - if (optvalue) { - arg_cat(&dest, "[", &ndest); - arg_cat(&dest, datatype, &ndest); - arg_cat(&dest, "]", &ndest); - } else - arg_cat(&dest, datatype, &ndest); - } -} - -static void arg_cat_optionv(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue, const char* separator) { - separator = separator ? separator : ""; - - if (shortopts) { - const char* c = shortopts; - while (*c) { - /* "-a|-b|-c" */ - char shortopt[3]; - - /* note: shortopt array[] is initialiazed dynamically here to satisfy */ - /* a deficiency in the watcom compiler wrt static array initializers. */ - shortopt[0] = '-'; - shortopt[1] = *c; - shortopt[2] = 0; - - arg_cat(&dest, shortopt, &ndest); - if (*++c) - arg_cat(&dest, separator, &ndest); - } - } - - /* put separator between long opts and short opts */ - if (shortopts && longopts) - arg_cat(&dest, separator, &ndest); - - if (longopts) { - const char* c = longopts; - while (*c) { - size_t ncspn; - - /* add "--" tag prefix */ - arg_cat(&dest, "--", &ndest); - - /* add comma separated option tag */ - ncspn = strcspn(c, ","); -#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__)) - strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest); -#else - strncat(dest, c, (ncspn < ndest) ? ncspn : ndest); -#endif - c += ncspn; - - /* add given separator in place of comma */ - if (*c == ',') { - arg_cat(&dest, separator, &ndest); - c++; - } - } - } - - if (datatype) { - if (longopts) - arg_cat(&dest, "=", &ndest); - else if (shortopts) - arg_cat(&dest, " ", &ndest); - - if (optvalue) { - arg_cat(&dest, "[", &ndest); - arg_cat(&dest, datatype, &ndest); - arg_cat(&dest, "]", &ndest); - } else - arg_cat(&dest, datatype, &ndest); - } -} - -void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) { - char syntax[200] = ""; - suffix = suffix ? suffix : ""; - - /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */ - arg_cat_optionv(syntax, sizeof(syntax) - 1, shortopts, longopts, datatype, 0, "|"); - - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, (char*)suffix); -} - -/* this function should be deprecated because it doesn't consider optional argument values (ARG_HASOPTVALUE) */ -void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_option_ds(ds, shortopts, longopts, datatype, suffix); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} - -/* - * Print a GNU style [OPTION] string in which all short options that - * do not take argument values are presented in abbreviated form, as - * in: -xvfsd, or -xvf[sd], or [-xvsfd] - */ -static void arg_print_gnuswitch_ds(arg_dstr_t ds, struct arg_hdr** table) { - int tabindex; - char* format1 = " -%c"; - char* format2 = " [-%c"; - char* suffix = ""; - - /* print all mandatory switches that are without argument values */ - for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - /* skip optional options */ - if (table[tabindex]->mincount < 1) - continue; - - /* skip non-short options */ - if (table[tabindex]->shortopts == NULL) - continue; - - /* skip options that take argument values */ - if (table[tabindex]->flag & ARG_HASVALUE) - continue; - - /* print the short option (only the first short option char, ignore multiple choices)*/ - arg_dstr_catf(ds, format1, table[tabindex]->shortopts[0]); - format1 = "%c"; - format2 = "[%c"; - } - - /* print all optional switches that are without argument values */ - for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - /* skip mandatory args */ - if (table[tabindex]->mincount > 0) - continue; - - /* skip args without short options */ - if (table[tabindex]->shortopts == NULL) - continue; - - /* skip args with values */ - if (table[tabindex]->flag & ARG_HASVALUE) - continue; - - /* print first short option */ - arg_dstr_catf(ds, format2, table[tabindex]->shortopts[0]); - format2 = "%c"; - suffix = "]"; - } - - arg_dstr_catf(ds, "%s", suffix); -} - -void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int i, tabindex; - - /* print GNU style [OPTION] string */ - arg_print_gnuswitch_ds(ds, table); - - /* print remaining options in abbreviated style */ - for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - char syntax[200] = ""; - const char *shortopts, *longopts, *datatype; - - /* skip short options without arg values (they were printed by arg_print_gnu_switch) */ - if (table[tabindex]->shortopts && !(table[tabindex]->flag & ARG_HASVALUE)) - continue; - - shortopts = table[tabindex]->shortopts; - longopts = table[tabindex]->longopts; - datatype = table[tabindex]->datatype; - arg_cat_option(syntax, sizeof(syntax) - 1, shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE); - - if (strlen(syntax) > 0) { - /* print mandatory instances of this option */ - for (i = 0; i < table[tabindex]->mincount; i++) { - arg_dstr_cat(ds, " "); - arg_dstr_cat(ds, syntax); - } - - /* print optional instances enclosed in "[..]" */ - switch (table[tabindex]->maxcount - table[tabindex]->mincount) { - case 0: - break; - case 1: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - break; - case 2: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - break; - default: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]..."); - break; - } - } - } - - if (suffix) { - arg_dstr_cat(ds, (char*)suffix); - } -} - -void arg_print_syntax(FILE* fp, void** argtable, const char* suffix) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_syntax_ds(ds, argtable, suffix); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} - -void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int i, tabindex; - - /* print remaining options in abbreviated style */ - for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - char syntax[200] = ""; - const char *shortopts, *longopts, *datatype; - - shortopts = table[tabindex]->shortopts; - longopts = table[tabindex]->longopts; - datatype = table[tabindex]->datatype; - arg_cat_optionv(syntax, sizeof(syntax) - 1, shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, "|"); - - /* print mandatory options */ - for (i = 0; i < table[tabindex]->mincount; i++) { - arg_dstr_cat(ds, " "); - arg_dstr_cat(ds, syntax); - } - - /* print optional args enclosed in "[..]" */ - switch (table[tabindex]->maxcount - table[tabindex]->mincount) { - case 0: - break; - case 1: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - break; - case 2: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]"); - break; - default: - arg_dstr_cat(ds, " ["); - arg_dstr_cat(ds, syntax); - arg_dstr_cat(ds, "]..."); - break; - } - } - - if (suffix) { - arg_dstr_cat(ds, (char*)suffix); - } -} - -void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_syntaxv_ds(ds, argtable, suffix); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} - -void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int tabindex; - - format = format ? format : " %-20s %s\n"; - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - if (table[tabindex]->glossary) { - char syntax[200] = ""; - const char* shortopts = table[tabindex]->shortopts; - const char* longopts = table[tabindex]->longopts; - const char* datatype = table[tabindex]->datatype; - const char* glossary = table[tabindex]->glossary; - arg_cat_optionv(syntax, sizeof(syntax) - 1, shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", "); - arg_dstr_catf(ds, format, syntax, glossary); - } - } -} - -void arg_print_glossary(FILE* fp, void** argtable, const char* format) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_glossary_ds(ds, argtable, format); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} - -/** - * Print a piece of text formatted, which means in a column with a - * left and a right margin. The lines are wrapped at whitspaces next - * to right margin. The function does not indent the first line, but - * only the following ones. - * - * Example: - * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." ) - * will result in the following output: - * - * Some - * text - * that - * doesn' - * t fit. - * - * Too long lines will be wrapped in the middle of a word. - * - * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." ) - * will result in the following output: - * - * Some - * text - * that - * doesn' - * t fit. - * - * As you see, the first line is not indented. This enables output of - * lines, which start in a line where output already happened. - * - * Author: Uli Fouquet - */ -static void arg_print_formatted_ds(arg_dstr_t ds, const unsigned lmargin, const unsigned rmargin, const char* text) { - const unsigned int textlen = (unsigned int)strlen(text); - unsigned int line_start = 0; - unsigned int line_end = textlen; - const unsigned int colwidth = (rmargin - lmargin) + 1; - - assert(strlen(text) < UINT_MAX); - - /* Someone doesn't like us... */ - if (line_end < line_start) { - arg_dstr_catf(ds, "%s\n", text); - } - - while (line_end > line_start) { - /* Eat leading white spaces. This is essential because while - wrapping lines, there will often be a whitespace at beginning - of line */ - while (isspace(*(text + line_start))) { - line_start++; - } - - /* Find last whitespace, that fits into line */ - if (line_end - line_start > colwidth) { - line_end = line_start + colwidth; - - while ((line_end > line_start) && !isspace(*(text + line_end))) { - line_end--; - } - - /* Consume trailing spaces */ - while ((line_end > line_start) && isspace(*(text + line_end))) { - line_end--; - } - - /* Restore the last non-space character */ - line_end++; - } - - /* Output line of text */ - while (line_start < line_end) { - char c = *(text + line_start); - arg_dstr_catc(ds, c); - line_start++; - } - arg_dstr_cat(ds, "\n"); - - /* Initialize another line */ - if (line_end < textlen) { - unsigned i; - - for (i = 0; i < lmargin; i++) { - arg_dstr_cat(ds, " "); - } - - line_end = textlen; - } - } /* lines of text */ -} - -/** - * Prints the glossary in strict GNU format. - * Differences to arg_print_glossary() are: - * - wraps lines after 80 chars - * - indents lines without shortops - * - does not accept formatstrings - * - * Contributed by Uli Fouquet - */ -void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int tabindex; - - for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { - if (table[tabindex]->glossary) { - char syntax[200] = ""; - const char* shortopts = table[tabindex]->shortopts; - const char* longopts = table[tabindex]->longopts; - const char* datatype = table[tabindex]->datatype; - const char* glossary = table[tabindex]->glossary; - - if (!shortopts && longopts) { - /* Indent trailing line by 4 spaces... */ - memset(syntax, ' ', 4); - *(syntax + 4) = '\0'; - } - - arg_cat_optionv(syntax, sizeof(syntax) - 1, shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", "); - - /* If syntax fits not into column, print glossary in new line... */ - if (strlen(syntax) > 25) { - arg_dstr_catf(ds, " %-25s %s\n", syntax, ""); - *syntax = '\0'; - } - - arg_dstr_catf(ds, " %-25s ", syntax); - arg_print_formatted_ds(ds, 28, 79, glossary); - } - } /* for each table entry */ - - arg_dstr_cat(ds, "\n"); -} - -void arg_print_glossary_gnu(FILE* fp, void** argtable) { - arg_dstr_t ds = arg_dstr_create(); - arg_print_glossary_gnu_ds(ds, argtable); - fputs(arg_dstr_cstr(ds), fp); - arg_dstr_destroy(ds); -} - -/** - * Checks the argtable[] array for NULL entries and returns 1 - * if any are found, zero otherwise. - */ -int arg_nullcheck(void** argtable) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int tabindex; - /*printf("arg_nullcheck(%p)\n",argtable);*/ - - if (!table) - return 1; - - tabindex = 0; - do { - /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/ - if (!table[tabindex]) - return 1; - } while (!(table[tabindex++]->flag & ARG_TERMINATOR)); - - return 0; -} - -/* - * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design. - * The flaw results in memory leak in the (very rare) case that an intermediate - * entry in the argtable array failed its memory allocation while others following - * that entry were still allocated ok. Those subsequent allocations will not be - * deallocated by arg_free(). - * Despite the unlikeliness of the problem occurring, and the even unlikelier event - * that it has any deliterious effect, it is fixed regardless by replacing arg_free() - * with the newer arg_freetable() function. - * We still keep arg_free() for backwards compatibility. - */ -void arg_free(void** argtable) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - int tabindex = 0; - int flag; - /*printf("arg_free(%p)\n",argtable);*/ - do { - /* - if we encounter a NULL entry then somewhat incorrectly we presume - we have come to the end of the array. It isnt strictly true because - an intermediate entry could be NULL with other non-NULL entries to follow. - The subsequent argtable entries would then not be freed as they should. - */ - if (table[tabindex] == NULL) - break; - - flag = table[tabindex]->flag; - xfree(table[tabindex]); - table[tabindex++] = NULL; - - } while (!(flag & ARG_TERMINATOR)); -} - -/* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */ -void arg_freetable(void** argtable, size_t n) { - struct arg_hdr** table = (struct arg_hdr**)argtable; - size_t tabindex = 0; - /*printf("arg_freetable(%p)\n",argtable);*/ - for (tabindex = 0; tabindex < n; tabindex++) { - if (table[tabindex] == NULL) - continue; - - xfree(table[tabindex]); - table[tabindex] = NULL; - }; -} - -#ifdef _WIN32 -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - return TRUE; - UNREFERENCED_PARAMETER(hinstDLL); - UNREFERENCED_PARAMETER(fdwReason); - UNREFERENCED_PARAMETER(lpvReserved); -} -#endif diff --git a/client/cliparser/argtable3.h b/client/cliparser/argtable3.h deleted file mode 100644 index 487c22d3..00000000 --- a/client/cliparser/argtable3.h +++ /dev/null @@ -1,273 +0,0 @@ -/******************************************************************************* - * argtable3: Declares the main interfaces of the library - * - * This file is part of the argtable3 library. - * - * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of STEWART HEITMANN nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -#ifndef ARGTABLE3 -#define ARGTABLE3 - -#include /* FILE */ -#include /* struct tm */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define ARG_REX_ICASE 1 -#define ARG_DSTR_SIZE 200 -#define ARG_CMD_NAME_LEN 100 -#define ARG_CMD_DESCRIPTION_LEN 256 - -#ifndef ARG_REPLACE_GETOPT -#define ARG_REPLACE_GETOPT 1 /* use the embedded getopt as the system getopt(3) */ -#endif /* ARG_REPLACE_GETOPT */ - -/* bit masks for arg_hdr.flag */ -enum { ARG_TERMINATOR = 0x1, ARG_HASVALUE = 0x2, ARG_HASOPTVALUE = 0x4 }; - -#if defined(_WIN32) - #if defined(argtable3_EXPORTS) - #define ARG_EXTERN __declspec(dllexport) - #elif defined(argtable3_IMPORTS) - #define ARG_EXTERN __declspec(dllimport) - #else - #define ARG_EXTERN - #endif -#else - #define ARG_EXTERN -#endif - -typedef struct _internal_arg_dstr* arg_dstr_t; -typedef void* arg_cmd_itr_t; - -typedef void(arg_resetfn)(void* parent); -typedef int(arg_scanfn)(void* parent, const char* argval); -typedef int(arg_checkfn)(void* parent); -typedef void(arg_errorfn)(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname); -typedef void(arg_dstr_freefn)(char* buf); -typedef int(arg_cmdfn)(int argc, char* argv[], arg_dstr_t res); -typedef int(arg_comparefn)(const void* k1, const void* k2); - -/* - * The arg_hdr struct defines properties that are common to all arg_xxx structs. - * The argtable library requires each arg_xxx struct to have an arg_hdr - * struct as its first data member. - * The argtable library functions then use this data to identify the - * properties of the command line option, such as its option tags, - * datatype string, and glossary strings, and so on. - * Moreover, the arg_hdr struct contains pointers to custom functions that - * are provided by each arg_xxx struct which perform the tasks of parsing - * that particular arg_xxx arguments, performing post-parse checks, and - * reporting errors. - * These functions are private to the individual arg_xxx source code - * and are the pointer to them are initiliased by that arg_xxx struct's - * constructor function. The user could alter them after construction - * if desired, but the original intention is for them to be set by the - * constructor and left unaltered. - */ -typedef struct arg_hdr { - char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */ - const char* shortopts; /* String defining the short options */ - const char* longopts; /* String defiing the long options */ - const char* datatype; /* Description of the argument data type */ - const char* glossary; /* Description of the option as shown by arg_print_glossary function */ - int mincount; /* Minimum number of occurences of this option accepted */ - int maxcount; /* Maximum number of occurences if this option accepted */ - void* parent; /* Pointer to parent arg_xxx struct */ - arg_resetfn* resetfn; /* Pointer to parent arg_xxx reset function */ - arg_scanfn* scanfn; /* Pointer to parent arg_xxx scan function */ - arg_checkfn* checkfn; /* Pointer to parent arg_xxx check function */ - arg_errorfn* errorfn; /* Pointer to parent arg_xxx error function */ - void* priv; /* Pointer to private header data for use by arg_xxx functions */ -} arg_hdr_t; - -typedef struct arg_rem { - struct arg_hdr hdr; /* The mandatory argtable header struct */ -} arg_rem_t; - -typedef struct arg_lit { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args */ -} arg_lit_t; - -typedef struct arg_int { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args */ - int* ival; /* Array of parsed argument values */ -} arg_int_t; - -typedef struct arg_dbl { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args */ - double* dval; /* Array of parsed argument values */ -} arg_dbl_t; - -typedef struct arg_str { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args */ - const char** sval; /* Array of parsed argument values */ -} arg_str_t; - -typedef struct arg_rex { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args */ - const char** sval; /* Array of parsed argument values */ -} arg_rex_t; - -typedef struct arg_file { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of matching command line args*/ - const char** filename; /* Array of parsed filenames (eg: /home/foo.bar) */ - const char** basename; /* Array of parsed basenames (eg: foo.bar) */ - const char** extension; /* Array of parsed extensions (eg: .bar) */ -} arg_file_t; - -typedef struct arg_date { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - const char* format; /* strptime format string used to parse the date */ - int count; /* Number of matching command line args */ - struct tm* tmval; /* Array of parsed time values */ -} arg_date_t; - -enum { ARG_ELIMIT = 1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG }; -typedef struct arg_end { - struct arg_hdr hdr; /* The mandatory argtable header struct */ - int count; /* Number of errors encountered */ - int* error; /* Array of error codes */ - void** parent; /* Array of pointers to offending arg_xxx struct */ - const char** argval; /* Array of pointers to offending argv[] string */ -} arg_end_t; - -typedef struct arg_cmd_info { - char name[ARG_CMD_NAME_LEN]; - char description[ARG_CMD_DESCRIPTION_LEN]; - arg_cmdfn* proc; -} arg_cmd_info_t; - -/**** arg_xxx constructor functions *********************************/ - -ARG_EXTERN struct arg_rem* arg_rem(const char* datatype, const char* glossary); - -ARG_EXTERN struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary); -ARG_EXTERN struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary); -ARG_EXTERN struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary); -ARG_EXTERN struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary); -ARG_EXTERN struct arg_rex* arg_rexn(const char* shortopts, - const char* longopts, - const char* pattern, - const char* datatype, - int mincount, - int maxcount, - int flags, - const char* glossary); - -ARG_EXTERN struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary); -ARG_EXTERN struct arg_date* arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary); - -ARG_EXTERN struct arg_end* arg_end(int maxerrors); - -#define ARG_DSTR_STATIC ((arg_dstr_freefn*)0) -#define ARG_DSTR_VOLATILE ((arg_dstr_freefn*)1) -#define ARG_DSTR_DYNAMIC ((arg_dstr_freefn*)3) - -/**** other functions *******************************************/ -ARG_EXTERN int arg_nullcheck(void** argtable); -ARG_EXTERN int arg_parse(int argc, char** argv, void** argtable); -ARG_EXTERN void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix); -ARG_EXTERN void arg_print_syntax(FILE* fp, void** argtable, const char* suffix); -ARG_EXTERN void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix); -ARG_EXTERN void arg_print_glossary(FILE* fp, void** argtable, const char* format); -ARG_EXTERN void arg_print_glossary_gnu(FILE* fp, void** argtable); -ARG_EXTERN void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname); -ARG_EXTERN void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix); -ARG_EXTERN void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix); -ARG_EXTERN void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix); -ARG_EXTERN void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format); -ARG_EXTERN void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable); -ARG_EXTERN void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname); -ARG_EXTERN void arg_freetable(void** argtable, size_t n); - -ARG_EXTERN arg_dstr_t arg_dstr_create(void); -ARG_EXTERN void arg_dstr_destroy(arg_dstr_t ds); -ARG_EXTERN void arg_dstr_reset(arg_dstr_t ds); -ARG_EXTERN void arg_dstr_free(arg_dstr_t ds); -ARG_EXTERN void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc); -ARG_EXTERN void arg_dstr_cat(arg_dstr_t ds, const char* str); -ARG_EXTERN void arg_dstr_catc(arg_dstr_t ds, char c); -ARG_EXTERN void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...); -ARG_EXTERN char* arg_dstr_cstr(arg_dstr_t ds); - -ARG_EXTERN void arg_cmd_init(void); -ARG_EXTERN void arg_cmd_uninit(void); -ARG_EXTERN void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description); -ARG_EXTERN void arg_cmd_unregister(const char* name); -ARG_EXTERN int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res); -ARG_EXTERN unsigned int arg_cmd_count(void); -ARG_EXTERN arg_cmd_info_t* arg_cmd_info(const char* name); -ARG_EXTERN arg_cmd_itr_t arg_cmd_itr_create(void); -ARG_EXTERN void arg_cmd_itr_destroy(arg_cmd_itr_t itr); -ARG_EXTERN int arg_cmd_itr_advance(arg_cmd_itr_t itr); -ARG_EXTERN char* arg_cmd_itr_key(arg_cmd_itr_t itr); -ARG_EXTERN arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr); -ARG_EXTERN int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k); -ARG_EXTERN void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn); -ARG_EXTERN void arg_make_get_help_msg(arg_dstr_t res); -ARG_EXTERN void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable); -ARG_EXTERN void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end); -ARG_EXTERN int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode); -ARG_EXTERN void arg_set_module_name(const char* name); -ARG_EXTERN void arg_set_module_version(int major, int minor, int patch, const char* tag); - -/**** deprecated functions, for back-compatibility only ********/ -ARG_EXTERN void arg_free(void** argtable); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/client/cliparser/cliparser.c b/client/cliparser/cliparser.c deleted file mode 100644 index 95422039..00000000 --- a/client/cliparser/cliparser.c +++ /dev/null @@ -1,205 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2017 Merlok -// -// 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. -//----------------------------------------------------------------------------- -// Command line parser core commands -//----------------------------------------------------------------------------- - -#include "cliparser.h" -#include -#include - -void **argtable = NULL; -size_t argtableLen = 0; -char *programName = NULL; -char *programHint = NULL; -char *programHelp = NULL; -char buf[500] = {0}; - -int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp) { - argtable = NULL; - argtableLen = 0; - programName = vprogramName; - programHint = vprogramHint; - programHelp = vprogramHelp; - memset(buf, 0x00, 500); - - return 0; -} - -int CLIParserParseArg(int argc, char **argv, void* vargtable[], size_t vargtableLen, bool allowEmptyExec) { - int nerrors; - - argtable = vargtable; - argtableLen = vargtableLen; - - /* verify the argtable[] entries were allocated sucessfully */ - if (arg_nullcheck(argtable) != 0) { - /* NULL entries were detected, some allocations must have failed */ - printf("ERROR: Insufficient memory\n"); - return 2; - } - /* Parse the command line as defined by argtable[] */ - nerrors = arg_parse(argc, argv, argtable); - - /* special case: '--help' takes precedence over error reporting */ - if ((argc < 2 && !allowEmptyExec) ||((struct arg_lit *)argtable[0])->count > 0) { // help must be the first record - printf("Usage: %s", programName); - arg_print_syntaxv(stdout, argtable, "\n"); - if (programHint) - printf("%s\n\n", programHint); - arg_print_glossary(stdout, argtable, " %-20s %s\n"); - printf("\n"); - if (programHelp) - printf("%s \n", programHelp); - - return 1; - } - - /* If the parser returned any errors then display them and exit */ - if (nerrors > 0) { - /* Display the error details contained in the arg_end struct.*/ - arg_print_errors(stdout, ((struct arg_end *)argtable[vargtableLen - 1]), programName); - printf("Try '%s --help' for more information.\n", programName); - - return 3; - } - - return 0; -} - -enum ParserState { - PS_FIRST, - PS_ARGUMENT, - PS_OPTION, -}; - -#define isSpace(c)(c == ' ' || c == '\t') - -int CLIParserParseString(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec) { - return CLIParserParseStringEx(str, vargtable, vargtableLen, allowEmptyExec, false); -} - -int CLIParserParseStringEx(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData) { - int argc = 0; - char *argv[200] = {NULL}; - - int len = strlen(str); - char *bufptr = buf; - char *spaceptr = NULL; - enum ParserState state = PS_FIRST; - - argv[argc++] = bufptr; - // param0 = program name - memcpy(buf, programName, strlen(programName) + 1); // with 0x00 - bufptr += strlen(programName) + 1; - if (len) - argv[argc++] = bufptr; - - // parse params - for (int i = 0; i < len; i++) { - switch(state){ - case PS_FIRST: // first char - if (!clueData || str[i] == '-'){ // first char before space is '-' - next element - option OR not "clueData" for not-option fields - state = PS_OPTION; - - if (spaceptr) { - bufptr = spaceptr; - *bufptr = 0x00; - bufptr++; - argv[argc++] = bufptr; - } - } - spaceptr = NULL; - case PS_ARGUMENT: - if (state == PS_FIRST) - state = PS_ARGUMENT; - if (isSpace(str[i])) { - spaceptr = bufptr; - state = PS_FIRST; - } - *bufptr = str[i]; - bufptr++; - break; - case PS_OPTION: - if (isSpace(str[i])){ - state = PS_FIRST; - - *bufptr = 0x00; - bufptr++; - argv[argc++] = bufptr; - break; - } - - *bufptr = str[i]; - bufptr++; - break; - } - } - - return CLIParserParseArg(argc, argv, vargtable, vargtableLen, allowEmptyExec); -} - -void CLIParserFree() { - arg_freetable(argtable, argtableLen); - argtable = NULL; - - return; -} - -// convertors -int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { - *datalen = 0; - - int ibuf = 0; - uint8_t buf[256] = {0}; - int res = CLIParamStrToBuf(argstr, buf, maxdatalen * 2, &ibuf); // *2 because here HEX - if (res || !ibuf) - return res; - - switch(param_gethex_to_eol((char *)buf, 0, data, maxdatalen, datalen)) { - case 1: - printf("Parameter error: Invalid HEX value.\n"); - return 1; - case 2: - printf("Parameter error: parameter too large.\n"); - return 2; - case 3: - printf("Parameter error: Hex string must have even number of digits.\n"); - return 3; - } - - return 0; -} - -int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { - *datalen = 0; - if (!argstr->count) - return 0; - - uint8_t buf[256] = {0}; - int ibuf = 0; - - for (int i = 0; i < argstr->count; i++) { - int len = strlen(argstr->sval[i]); - memcpy(&buf[ibuf], argstr->sval[i], len); - ibuf += len; - } - buf[ibuf] = 0; - - if (!ibuf) - return 0; - - if (ibuf > maxdatalen) - return 2; - - memcpy(data, buf, ibuf); - *datalen = ibuf; - - return 0; -} - - diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h deleted file mode 100644 index 05910ea4..00000000 --- a/client/cliparser/cliparser.h +++ /dev/null @@ -1,41 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2017 Merlok -// -// 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. -//----------------------------------------------------------------------------- -// Command line parser core commands -//----------------------------------------------------------------------------- - -#include "argtable3.h" -#include "util.h" -#include - -#define arg_param_begin arg_lit0("hH", "help", "print this help and exit") -#define arg_param_end arg_end(20) - -#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) -#define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count) -#define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count) -#define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0]) -#define arg_get_int_def(n,def)(arg_get_int_count(n)?(arg_get_int(n)):(def)) -#define arg_get_str(n)((struct arg_str*)argtable[n]) -#define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0])) - -#define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary))) -#define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary))) - -#define CLIExecWithReturn(cmd, atbl, ifempty) if (CLIParserParseString(cmd, atbl, arg_getsize(atbl), ifempty)){CLIParserFree();return 0;} -#define CLIGetHexBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;} -#define CLIGetHexWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;} -#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;} - -extern int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp); -extern int CLIParserParseString(const char* str, void* argtable[], size_t vargtableLen, bool allowEmptyExec); -extern int CLIParserParseStringEx(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData); -extern int CLIParserParseArg(int argc, char **argv, void* argtable[], size_t vargtableLen, bool allowEmptyExec); -extern void CLIParserFree(); - -extern int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); -extern int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); diff --git a/client/cmddata.c b/client/cmddata.c index f5416fee..a7b80480 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -8,1864 +8,883 @@ // Data and Graph commands //----------------------------------------------------------------------------- -#include "cmddata.h" - -#include // also included in util.h -#include // also included in util.h -#include -#include // for CmdNorm INT_MIN && INT_MAX -#include "util.h" +#include +#include +#include +#include +#include "proxmark3.h" +#include "data.h" +#include "ui.h" +#include "graph.h" +#include "cmdparser.h" #include "cmdmain.h" -#include "comms.h" -#include "ui.h" // for show graph controls -#include "graph.h" // for graph data -#include "cmdparser.h"// already included in cmdmain.h -#include "usb_cmd.h" // already included in cmdmain.h and proxmark3.h -#include "lfdemod.h" // for demod code -#include "loclass/cipherutils.h" // for decimating samples in getsamples -#include "cmdlfem4x.h"// for em410x demod - -uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; -uint8_t g_debugMode=0; -size_t DemodBufferLen=0; -int g_DemodStartIdx=0; -int g_DemodClock=0; +#include "cmddata.h" static int CmdHelp(const char *Cmd); -//set the demod buffer with given array of binary (one bit per byte) -//by marshmellow -void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx) +int CmdAmp(const char *Cmd) { - if (buff == NULL) - return; + int i, rising, falling; + int max = INT_MIN, min = INT_MAX; - if ( size > MAX_DEMOD_BUF_LEN - startIdx) - size = MAX_DEMOD_BUF_LEN - startIdx; + for (i = 10; i < GraphTraceLen; ++i) { + if (GraphBuffer[i] > max) + max = GraphBuffer[i]; + if (GraphBuffer[i] < min) + min = GraphBuffer[i]; + } - size_t i = 0; - for (; i < size; i++){ - DemodBuffer[i]=buff[startIdx++]; - } - DemodBufferLen=size; - return; + if (max != min) { + rising = falling= 0; + for (i = 0; i < GraphTraceLen; ++i) { + if (GraphBuffer[i + 1] < GraphBuffer[i]) { + if (rising) { + GraphBuffer[i] = max; + rising = 0; + } + falling = 1; + } + if (GraphBuffer[i + 1] > GraphBuffer[i]) { + if (falling) { + GraphBuffer[i] = min; + falling = 0; + } + rising= 1; + } + } + } + RepaintGraphWindow(); + return 0; } -bool getDemodBuf(uint8_t *buff, size_t *size) { - if (buff == NULL) return false; - if (size == NULL) return false; - if (*size == 0) return false; - - *size = (*size > DemodBufferLen) ? DemodBufferLen : *size; - - memcpy(buff, DemodBuffer, *size); - return true; -} - -// option '1' to save DemodBuffer any other to restore -void save_restoreDB(uint8_t saveOpt) -{ - static uint8_t SavedDB[MAX_DEMOD_BUF_LEN]; - static size_t SavedDBlen; - static bool DB_Saved = false; - static int savedDemodStartIdx = 0; - static int savedDemodClock = 0; - - if (saveOpt == GRAPH_SAVE) { //save - - memcpy(SavedDB, DemodBuffer, sizeof(DemodBuffer)); - SavedDBlen = DemodBufferLen; - DB_Saved=true; - savedDemodStartIdx = g_DemodStartIdx; - savedDemodClock = g_DemodClock; - } else if (DB_Saved) { //restore - memcpy(DemodBuffer, SavedDB, sizeof(DemodBuffer)); - DemodBufferLen = SavedDBlen; - g_DemodClock = savedDemodClock; - g_DemodStartIdx = savedDemodStartIdx; - } - return; -} - -int CmdSetDebugMode(const char *Cmd) -{ - int demod=0; - sscanf(Cmd, "%i", &demod); - g_debugMode=(uint8_t)demod; - return 1; -} - -int usage_data_printdemodbuf(){ - PrintAndLog("Usage: data printdemodbuffer x o l "); - PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" x output in hex (omit for binary output)"); - PrintAndLog(" o enter offset in # of bits"); - PrintAndLog(" l enter length to print in # of bits or hex characters respectively"); - return 0; -} - -//by marshmellow -void printDemodBuff(void) -{ - int bitLen = DemodBufferLen; - if (bitLen<1) { - PrintAndLog("no bits found in demod buffer"); - return; - } - if (bitLen>512) bitLen=512; //max output to 512 bits if we have more - should be plenty - - char *bin = sprint_bin_break(DemodBuffer,bitLen,16); - PrintAndLog("%s",bin); - - return; -} - -int CmdPrintDemodBuff(const char *Cmd) -{ - char hex[512]={0x00}; - bool hexMode = false; - bool errors = false; - uint32_t offset = 0; //could be size_t but no param_get16... - uint32_t length = 512; - char cmdp = 0; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { - case 'h': - case 'H': - return usage_data_printdemodbuf(); - case 'x': - case 'X': - hexMode = true; - cmdp++; - break; - case 'o': - case 'O': - offset = param_get32ex(Cmd, cmdp+1, 0, 10); - if (!offset) errors = true; - cmdp += 2; - break; - case 'l': - case 'L': - length = param_get32ex(Cmd, cmdp+1, 512, 10); - if (!length) errors = true; - cmdp += 2; - break; - default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - if(errors) break; - } - //Validations - if(errors) return usage_data_printdemodbuf(); - length = (length > (DemodBufferLen-offset)) ? DemodBufferLen-offset : length; - int numBits = (length) & 0x00FFC; //make sure we don't exceed our string - - if (hexMode){ - char *buf = (char *) (DemodBuffer + offset); - numBits = (numBits > sizeof(hex)) ? sizeof(hex) : numBits; - numBits = binarraytohex(hex, buf, numBits); - if (numBits==0) return 0; - PrintAndLog("DemodBuffer: %s",hex); - } else { - PrintAndLog("DemodBuffer:\n%s", sprint_bin_break(DemodBuffer+offset,numBits,16)); - } - return 1; -} - -//by marshmellow -//this function strictly converts >1 to 1 and <1 to 0 for each sample in the graphbuffer -int CmdGetBitStream(const char *Cmd) -{ - int i; - CmdHpf(Cmd); - for (i = 0; i < GraphTraceLen; i++) { - if (GraphBuffer[i] >= 1) { - GraphBuffer[i] = 1; - } else { - GraphBuffer[i] = 0; - } - } - RepaintGraphWindow(); - return 0; -} - -//by marshmellow -//Cmd Args: Clock, invert, maxErr, maxLen as integers and amplify as char == 'a' -// (amp may not be needed anymore) -//verbose will print results and demoding messages -//emSearch will auto search for EM410x format in bitstream -//askType switches decode: ask/raw = 0, ask/manchester = 1 -int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, bool *stCheck) { - int invert=0; - int clk=0; - int maxErr=100; - int maxLen=0; - uint8_t askamp = 0; - char amp = param_getchar(Cmd, 0); - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - sscanf(Cmd, "%i %i %i %i %c", &clk, &invert, &maxErr, &maxLen, &); - if (!maxLen) maxLen = BIGBUF_SIZE; - if (invert != 0 && invert != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - if (clk==1){ - invert=1; - clk=0; - } - size_t BitLen = getFromGraphBuf(BitStream); - if (g_debugMode) PrintAndLog("DEBUG: Bitlen from grphbuff: %d",BitLen); - if (BitLen < 255) return 0; - if (maxLen < BitLen && maxLen != 0) BitLen = maxLen; - int foundclk = 0; - //amp before ST check - if (amp == 'a' || amp == 'A') { - askAmp(BitStream, BitLen); - } - bool st = false; - size_t ststart = 0, stend = 0; - if (*stCheck) st = DetectST(BitStream, &BitLen, &foundclk, &ststart, &stend); - *stCheck = st; - if (st) { - clk = (clk == 0) ? foundclk : clk; - CursorCPos = ststart; - CursorDPos = stend; - if (verbose || g_debugMode) PrintAndLog("\nFound Sequence Terminator - First one is shown by orange and blue graph markers"); - //Graph ST trim (for testing) - //for (int i = 0; i < BitLen; i++) { - // GraphBuffer[i] = BitStream[i]-128; - //} - //RepaintGraphWindow(); - } - int startIdx = 0; - int errCnt = askdemod_ext(BitStream, &BitLen, &clk, &invert, maxErr, askamp, askType, &startIdx); - if (errCnt<0 || BitLen<16){ //if fatal error (or -1) - if (g_debugMode) PrintAndLog("DEBUG: no data found %d, errors:%d, bitlen:%d, clock:%d",errCnt,invert,BitLen,clk); - return 0; - } - if (errCnt > maxErr){ - if (g_debugMode) PrintAndLog("DEBUG: Too many errors found, errors:%d, bits:%d, clock:%d",errCnt, BitLen, clk); - return 0; - } - if (verbose || g_debugMode) PrintAndLog("\nUsing Clock:%d, Invert:%d, Bits Found:%d",clk,invert,BitLen); - //output - setDemodBuf(BitStream,BitLen,0); - setClockGrid(clk, startIdx); - - if (verbose || g_debugMode){ - if (errCnt>0) PrintAndLog("# Errors during Demoding (shown as 7 in bit stream): %d",errCnt); - if (askType) PrintAndLog("ASK/Manchester - Clock: %d - Decoded bitstream:",clk); - else PrintAndLog("ASK/Raw - Clock: %d - Decoded bitstream:",clk); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - - } - uint64_t lo = 0; - uint32_t hi = 0; - if (emSearch){ - AskEm410xDecode(true, &hi, &lo); - } - return 1; -} -int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType) { - bool st = false; - return ASKDemod_ext(Cmd, verbose, emSearch, askType, &st); -} - -//by marshmellow -//takes 5 arguments - clock, invert, maxErr, maxLen as integers and amplify as char == 'a' -//attempts to demodulate ask while decoding manchester -//prints binary found and saves in graphbuffer for further commands -int Cmdaskmandemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 45 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod am [clock] [maxError] [maxLen] [amplify]"); - PrintAndLog(" ['s'] optional, check for Sequence Terminator"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); - PrintAndLog(" , 1 to invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100"); - PrintAndLog(" [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); - PrintAndLog(" , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod am = demod an ask/manchester tag from GraphBuffer"); - PrintAndLog(" : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); - PrintAndLog(" : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLog(" : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); - PrintAndLog(" : data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - return 0; - } - bool st = true; - if (Cmd[0]=='s') - return ASKDemod_ext(Cmd++, true, false, 1, &st); - else if (Cmd[1] == 's') - return ASKDemod_ext(Cmd+=2, true, false, 1, &st); - else - return ASKDemod(Cmd, true, false, 1); -} - -//by marshmellow -//manchester decode -//stricktly take 10 and 01 and convert to 0 and 1 -int Cmdmandecoderaw(const char *Cmd) -{ - int i =0; - int errCnt=0; - size_t size=0; - int invert=0; - int maxErr = 20; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data manrawdecode [invert] [maxErr]"); - PrintAndLog(" Takes 10 and 01 and converts to 0 and 1 respectively"); - PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)"); - PrintAndLog(" [invert] invert output"); - PrintAndLog(" [maxErr] set number of errors allowed (default = 20)"); - PrintAndLog(""); - PrintAndLog(" sample: data manrawdecode = decode manchester bitstream from the demodbuffer"); - return 0; - } - if (DemodBufferLen==0) return 0; - uint8_t BitStream[MAX_DEMOD_BUF_LEN]={0}; - int high=0,low=0; - for (;ihigh) high=DemodBuffer[i]; - else if(DemodBuffer[i]7 || low <0 ){ - PrintAndLog("Error: please raw demod the wave first then manchester raw decode"); - return 0; - } - - sscanf(Cmd, "%i %i", &invert, &maxErr); - size=i; - uint8_t alignPos = 0; - errCnt=manrawdecode(BitStream, &size, invert, &alignPos); - if (errCnt>=maxErr){ - PrintAndLog("Too many errors: %d",errCnt); - return 0; - } - PrintAndLog("Manchester Decoded - # errors:%d - data:",errCnt); - PrintAndLog("%s", sprint_bin_break(BitStream, size, 16)); - if (errCnt==0){ - uint64_t id = 0; - uint32_t hi = 0; - size_t idx=0; - if (Em410xDecode(BitStream, &size, &idx, &hi, &id)){ - //need to adjust to set bitstream back to manchester encoded data - //setDemodBuf(BitStream, size, idx); - - printEM410x(hi, id); - } - } - return 1; -} - -/** - * @author marshmellow - * biphase decode - * decdoes 01 or 10 to 0 and 11 or 00 to 1 - * param offset adjust start position - * param invert invert output - * param maxErr maximum tolerated errors +/* + * Generic command to demodulate ASK. + * + * Argument is convention: positive or negative (High mod means zero + * or high mod means one) + * + * Updates the Graph trace with 0/1 values + * + * Arguments: + * c : 0 or 1 */ -int CmdBiphaseDecodeRaw(const char *Cmd) +int Cmdaskdemod(const char *Cmd) { - size_t size=0; - int offset=0, invert=0, maxErr=20, errCnt=0; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 7 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data biphaserawdecode [offset] [invert] [maxErr]"); - PrintAndLog(" Converts 10 or 01 to 1 and 11 or 00 to 0"); - PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)"); - PrintAndLog(" --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); - PrintAndLog(""); - PrintAndLog(" [offset <0|1>], set to 0 not to adjust start position or to 1 to adjust decode start position"); - PrintAndLog(" [invert <0|1>], set to 1 to invert output"); - PrintAndLog(" [maxErr int], set max errors tolerated - default=20"); - PrintAndLog(""); - PrintAndLog(" sample: data biphaserawdecode = decode biphase bitstream from the demodbuffer"); - PrintAndLog(" sample: data biphaserawdecode 1 1 = decode biphase bitstream from the demodbuffer, set offset, and invert output"); - return 0; - } - sscanf(Cmd, "%i %i %i", &offset, &invert, &maxErr); - if (DemodBufferLen==0) { - PrintAndLog("DemodBuffer Empty - run 'data rawdemod ar' first"); - return 0; - } - uint8_t BitStream[MAX_DEMOD_BUF_LEN]={0}; - size = sizeof(BitStream); - if ( !getDemodBuf(BitStream, &size) ) return 0; - errCnt=BiphaseRawDecode(BitStream, &size, &offset, invert); - if (errCnt<0){ - PrintAndLog("Error during decode:%d", errCnt); - return 0; - } - if (errCnt>maxErr){ - PrintAndLog("Too many errors attempting to decode: %d",errCnt); - return 0; - } + int i; + int c, high = 0, low = 0; - if (errCnt>0){ - PrintAndLog("# Errors found during Demod (shown as 7 in bit stream): %d",errCnt); - } + // TODO: complain if we do not give 2 arguments here ! + // (AL - this doesn't make sense! we're only using one argument!!!) + sscanf(Cmd, "%i", &c); - PrintAndLog("Biphase Decoded using offset: %d - # invert:%d - data:",offset,invert); - PrintAndLog("%s", sprint_bin_break(BitStream, size, 16)); + /* Detect high and lows and clock */ + // (AL - clock???) + for (i = 0; i < GraphTraceLen; ++i) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + if (c != 0 && c != 1) { + PrintAndLog("Invalid argument: %s", Cmd); + return 0; + } - if (offset) setDemodBuf(DemodBuffer,DemodBufferLen-offset, offset); //remove first bit from raw demod - setClockGrid(g_DemodClock, g_DemodStartIdx + g_DemodClock*offset/2); - return 1; -} - -//by marshmellow -// - ASK Demod then Biphase decode GraphBuffer samples -int ASKbiphaseDemod(const char *Cmd, bool verbose) -{ - //ask raw demod GraphBuffer first - int offset=0, clk=0, invert=0, maxErr=100; - sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); - - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; - size_t size = getFromGraphBuf(BitStream); - int startIdx = 0; - //invert here inverts the ask raw demoded bits which has no effect on the demod, but we need the pointer - int errCnt = askdemod_ext(BitStream, &size, &clk, &invert, maxErr, 0, 0, &startIdx); - if ( errCnt < 0 || errCnt > maxErr ) { - if (g_debugMode) PrintAndLog("DEBUG: no data or error found %d, clock: %d", errCnt, clk); - return 0; - } - - //attempt to Biphase decode BitStream - errCnt = BiphaseRawDecode(BitStream, &size, &offset, invert); - if (errCnt < 0){ - if (g_debugMode || verbose) PrintAndLog("Error BiphaseRawDecode: %d", errCnt); - return 0; - } - if (errCnt > maxErr) { - if (g_debugMode || verbose) PrintAndLog("Error BiphaseRawDecode too many errors: %d", errCnt); - return 0; - } - //success set DemodBuffer and return - setDemodBuf(BitStream, size, 0); - setClockGrid(clk, startIdx + clk*offset/2); - if (g_debugMode || verbose){ - PrintAndLog("Biphase Decoded using offset: %d - clock: %d - # errors:%d - data:",offset,clk,errCnt); - printDemodBuff(); - } - return 1; -} -//by marshmellow - see ASKbiphaseDemod -int Cmdaskbiphdemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 25 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod ab [offset] [clock] [maxError] [maxLen] "); - PrintAndLog(" [offset], offset to begin biphase, default=0"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); - PrintAndLog(" , 1 to invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100"); - PrintAndLog(" [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); - PrintAndLog(" , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLog(" NOTE: can be entered as second or third argument"); - PrintAndLog(" NOTE: can be entered as first, second or last argument"); - PrintAndLog(" NOTE: any other arg must have previous args set to work"); - PrintAndLog(""); - PrintAndLog(" NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod ab = demod an ask/biph tag from GraphBuffer"); - PrintAndLog(" : data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); - PrintAndLog(" : data rawdemod ab 1 32 = demod an ask/biph tag from GraphBuffer using an offset of 1 and a clock of RF/32"); - PrintAndLog(" : data rawdemod ab 0 32 1 = demod an ask/biph tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLog(" : data rawdemod ab 0 1 = demod an ask/biph tag from GraphBuffer while inverting data"); - PrintAndLog(" : data rawdemod ab 0 64 1 0 = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - PrintAndLog(" : data rawdemod ab 0 64 1 0 0 a = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); - return 0; - } - return ASKbiphaseDemod(Cmd, true); -} - -//by marshmellow - see ASKDemod -int Cmdaskrawdemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 35 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod ar [clock] [maxError] [maxLen] [amplify]"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect"); - PrintAndLog(" , 1 to invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100"); - PrintAndLog(" [set maximum Samples to read], default = 32768 (1024 bits at rf/64)"); - PrintAndLog(" , 'a' to attempt demod with ask amplification, default = no amp"); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod ar = demod an ask tag from GraphBuffer"); - PrintAndLog(" : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); - PrintAndLog(" : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); - PrintAndLog(" : data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLog(" : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); - PrintAndLog(" : data rawdemod ar 64 1 0 = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - PrintAndLog(" : data rawdemod ar 64 1 0 0 a = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); - return 0; - } - return ASKDemod(Cmd, true, false, 0); -} - -int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph, bool verbose) -{ - static int CorrelBuffer[MAX_GRAPH_TRACE_LEN]; - size_t Correlation = 0; - int maxSum = 0; - int lastMax = 0; - if (verbose) PrintAndLog("performing %d correlations", GraphTraceLen - window); - for (int i = 0; i < len - window; ++i) { - int sum = 0; - for (int j = 0; j < window; ++j) { - sum += (in[j]*in[i + j]) / 256; - } - CorrelBuffer[i] = sum; - if (sum >= maxSum-100 && sum <= maxSum+100) { - //another max - Correlation = i-lastMax; - lastMax = i; - if (sum > maxSum) maxSum = sum; - } else if (sum > maxSum) { - maxSum=sum; - lastMax = i; - } - } - if (Correlation==0) { - //try again with wider margin - for (int i = 0; i < len - window; i++) { - if (CorrelBuffer[i] >= maxSum-(maxSum*0.05) && CorrelBuffer[i] <= maxSum+(maxSum*0.05)) { - //another max - Correlation = i-lastMax; - lastMax = i; - } - } - } - if (verbose && Correlation > 0) PrintAndLog("Possible Correlation: %d samples",Correlation); - - if (SaveGrph) { - //GraphTraceLen = GraphTraceLen - window; - memcpy(out, CorrelBuffer, len * sizeof(int)); - RepaintGraphWindow(); - } - return Correlation; -} - -int usage_data_autocorr(void) -{ - //print help - PrintAndLog("Usage: data autocorr [window] [g]"); - PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" [window] window length for correlation - default = 4000"); - PrintAndLog(" g save back to GraphBuffer (overwrite)"); - return 0; + if (GraphBuffer[0] > 0) { + GraphBuffer[0] = 1-c; + } else { + GraphBuffer[0] = c; + } + for (i = 1; i < GraphTraceLen; ++i) { + /* Transitions are detected at each peak + * Transitions are either: + * - we're low: transition if we hit a high + * - we're high: transition if we hit a low + * (we need to do it this way because some tags keep high or + * low for long periods, others just reach the peak and go + * down) + */ + if ((GraphBuffer[i] == high) && (GraphBuffer[i - 1] == c)) { + GraphBuffer[i] = 1 - c; + } else if ((GraphBuffer[i] == low) && (GraphBuffer[i - 1] == (1 - c))){ + GraphBuffer[i] = c; + } else { + /* No transition */ + GraphBuffer[i] = GraphBuffer[i - 1]; + } + } + RepaintGraphWindow(); + return 0; } int CmdAutoCorr(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (cmdp == 'h' || cmdp == 'H') - return usage_data_autocorr(); - int window = 4000; //set default - char grph=0; - bool updateGrph = false; - sscanf(Cmd, "%i %c", &window, &grph); + static int CorrelBuffer[MAX_GRAPH_TRACE_LEN]; - if (window >= GraphTraceLen) { - PrintAndLog("window must be smaller than trace (%d samples)", - GraphTraceLen); - return 0; - } - if (grph == 'g') updateGrph=true; - return AutoCorrelate(GraphBuffer, GraphBuffer, GraphTraceLen, window, updateGrph, true); + int window = atoi(Cmd); + + if (window == 0) { + PrintAndLog("needs a window"); + return 0; + } + if (window >= GraphTraceLen) { + PrintAndLog("window must be smaller than trace (%d samples)", + GraphTraceLen); + return 0; + } + + PrintAndLog("performing %d correlations", GraphTraceLen - window); + + for (int i = 0; i < GraphTraceLen - window; ++i) { + int sum = 0; + for (int j = 0; j < window; ++j) { + sum += (GraphBuffer[j]*GraphBuffer[i + j]) / 256; + } + CorrelBuffer[i] = sum; + } + GraphTraceLen = GraphTraceLen - window; + memcpy(GraphBuffer, CorrelBuffer, GraphTraceLen * sizeof (int)); + + RepaintGraphWindow(); + return 0; } int CmdBitsamples(const char *Cmd) { - int cnt = 0; - uint8_t got[12288]; + int cnt = 0; + uint8_t got[12288]; + + GetFromBigBuf(got,sizeof(got),0); + WaitForResponse(CMD_ACK,NULL); - GetFromBigBuf(got, sizeof(got), 0 , NULL, -1, false); + for (int j = 0; j < sizeof(got); j++) { + for (int k = 0; k < 8; k++) { + if(got[j] & (1 << (7 - k))) { + GraphBuffer[cnt++] = 1; + } else { + GraphBuffer[cnt++] = 0; + } + } + } + GraphTraceLen = cnt; + RepaintGraphWindow(); + return 0; +} - for (int j = 0; j < sizeof(got); j++) { - for (int k = 0; k < 8; k++) { - if(got[j] & (1 << (7 - k))) { - GraphBuffer[cnt++] = 1; - } else { - GraphBuffer[cnt++] = 0; - } - } - } - GraphTraceLen = cnt; - RepaintGraphWindow(); - return 0; +/* + * Convert to a bitstream + */ +int CmdBitstream(const char *Cmd) +{ + int i, j; + int bit; + int gtl; + int clock; + int low = 0; + int high = 0; + int hithigh, hitlow, first; + + /* Detect high and lows and clock */ + for (i = 0; i < GraphTraceLen; ++i) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* Get our clock */ + clock = GetClock(Cmd, high, 1); + gtl = ClearGraph(0); + + bit = 0; + for (i = 0; i < (int)(gtl / clock); ++i) + { + hithigh = 0; + hitlow = 0; + first = 1; + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; ++j) + { + if (GraphBuffer[(i * clock) + j] == high) + hithigh = 1; + else if (GraphBuffer[(i * clock) + j] == low) + hitlow = 1; + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + if (hithigh && hitlow) + break; + } + + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) + bit ^= 1; + + AppendGraph(0, clock, bit); +// for (j = 0; j < (int)(clock/2); j++) +// GraphBuffer[(i * clock) + j] = bit ^ 1; +// for (j = (int)(clock/2); j < clock; j++) +// GraphBuffer[(i * clock) + j] = bit; + } + + RepaintGraphWindow(); + return 0; } int CmdBuffClear(const char *Cmd) { - UsbCommand c = {CMD_BUFF_CLEAR}; - SendCommand(&c); - ClearGraph(true); - return 0; + UsbCommand c = {CMD_BUFF_CLEAR}; + SendCommand(&c); + ClearGraph(true); + return 0; } int CmdDec(const char *Cmd) { - for (int i = 0; i < (GraphTraceLen / 2); ++i) - GraphBuffer[i] = GraphBuffer[i * 2]; - GraphTraceLen /= 2; - PrintAndLog("decimated by 2"); - RepaintGraphWindow(); - return 0; -} -/** - * Undecimate - I'd call it 'interpolate', but we'll save that - * name until someone does an actual interpolation command, not just - * blindly repeating samples - * @param Cmd - * @return - */ -int CmdUndec(const char *Cmd) -{ - if(param_getchar(Cmd, 0) == 'h') - { - PrintAndLog("Usage: data undec [factor]"); - PrintAndLog("This function performs un-decimation, by repeating each sample N times"); - PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" factor The number of times to repeat each sample.[default:2]"); - PrintAndLog("Example: 'data undec 3'"); - return 0; - } - - uint8_t factor = param_get8ex(Cmd, 0,2, 10); - //We have memory, don't we? - int swap[MAX_GRAPH_TRACE_LEN] = { 0 }; - uint32_t g_index = 0, s_index = 0; - while(g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) - { - int count = 0; - for(count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) - swap[s_index+count] = GraphBuffer[g_index]; - - s_index += count; - g_index++; - } - - memcpy(GraphBuffer, swap, s_index * sizeof(int)); - GraphTraceLen = s_index; - RepaintGraphWindow(); - return 0; -} - -//by marshmellow -//shift graph zero up or down based on input + or - -int CmdGraphShiftZero(const char *Cmd) -{ - - int shift=0; - //set options from parameters entered with the command - sscanf(Cmd, "%i", &shift); - int shiftedVal=0; - for(int i = 0; i127) - shiftedVal=127; - else if (shiftedVal<-127) - shiftedVal=-127; - GraphBuffer[i]= shiftedVal; - } - CmdNorm(""); - return 0; -} - -int AskEdgeDetect(const int *in, int *out, int len, int threshold) { - int Last = 0; - for(int i = 1; i= threshold) //large jump up - Last = 127; - else if(in[i]-in[i-1] <= -1 * threshold) //large jump down - Last = -127; - out[i-1] = Last; - } - return 0; -} - -//by marshmellow -//use large jumps in read samples to identify edges of waves and then amplify that wave to max -//similar to dirtheshold, threshold commands -//takes a threshold length which is the measured length between two samples then determines an edge -int CmdAskEdgeDetect(const char *Cmd) -{ - int thresLen = 25; - int ans = 0; - sscanf(Cmd, "%i", &thresLen); - - ans = AskEdgeDetect(GraphBuffer, GraphBuffer, GraphTraceLen, thresLen); - RepaintGraphWindow(); - return ans; + for (int i = 0; i < (GraphTraceLen / 2); ++i) + GraphBuffer[i] = GraphBuffer[i * 2]; + GraphTraceLen /= 2; + PrintAndLog("decimated by 2"); + RepaintGraphWindow(); + return 0; } /* Print our clock rate */ -// uses data from graphbuffer -// adjusted to take char parameter for type of modulation to find the clock - by marshmellow. int CmdDetectClockRate(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 6 || strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data detectclock [modulation] "); - PrintAndLog(" [modulation as char], specify the modulation type you want to detect the clock of"); - PrintAndLog(" , specify the clock (optional - to get best start position only)"); - PrintAndLog(" 'a' = ask, 'f' = fsk, 'n' = nrz/direct, 'p' = psk"); - PrintAndLog(""); - PrintAndLog(" sample: data detectclock a = detect the clock of an ask modulated wave in the GraphBuffer"); - PrintAndLog(" data detectclock f = detect the clock of an fsk modulated wave in the GraphBuffer"); - PrintAndLog(" data detectclock p = detect the clock of an psk modulated wave in the GraphBuffer"); - PrintAndLog(" data detectclock n = detect the clock of an nrz/direct modulated wave in the GraphBuffer"); - } - int ans=0; - if (cmdp == 'a'){ - ans = GetAskClock(Cmd+1, true, false); - } else if (cmdp == 'f'){ - ans = GetFskClock("", true, false); - } else if (cmdp == 'n'){ - ans = GetNrzClock("", true, false); - } else if (cmdp == 'p'){ - ans = GetPskClock("", true, false); - } else { - PrintAndLog ("Please specify a valid modulation to detect the clock of - see option h for help"); - } - return ans; + int clock = DetectClock(0); + PrintAndLog("Auto-detected clock rate: %d", clock); + return 0; } -char *GetFSKType(uint8_t fchigh, uint8_t fclow, uint8_t invert) +int CmdFSKdemod(const char *Cmd) { - static char fType[8]; - memset(fType, 0x00, 8); - char *fskType = fType; - if (fchigh==10 && fclow==8){ - if (invert) //fsk2a - memcpy(fskType, "FSK2a", 5); - else //fsk2 - memcpy(fskType, "FSK2", 4); - } else if (fchigh == 8 && fclow == 5) { - if (invert) - memcpy(fskType, "FSK1", 4); - else - memcpy(fskType, "FSK1a", 5); - } else { - memcpy(fskType, "FSK??", 5); - } - return fskType; -} + static const int LowTone[] = { + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 + }; + static const int HighTone[] = { + 1, 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, + 1, 1, 1, 1, -1, -1, -1, -1, -1, + }; -//by marshmellow -//fsk raw demod and print binary -//takes 4 arguments - Clock, invert, fchigh, fclow -//defaults: clock = 50, invert=1, fchigh=10, fclow=8 (RF/10 RF/8 (fsk2a)) -int FSKrawDemod(const char *Cmd, bool verbose) -{ - //raw fsk demod no manchester decoding no start bit finding just get binary from wave - uint8_t rfLen, invert, fchigh, fclow; - //set defaults - //set options from parameters entered with the command - rfLen = param_get8(Cmd, 0); - invert = param_get8(Cmd, 1); - fchigh = param_get8(Cmd, 2); - fclow = param_get8(Cmd, 3); + int lowLen = sizeof (LowTone) / sizeof (int); + int highLen = sizeof (HighTone) / sizeof (int); + int convLen = (highLen > lowLen) ? highLen : lowLen; + uint32_t hi = 0, lo = 0; - if (strlen(Cmd)>0 && strlen(Cmd)<=2) { - if (rfLen==1) { - invert = 1; //if invert option only is used - rfLen = 0; - } - } - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - size_t BitLen = getFromGraphBuf(BitStream); - if (BitLen==0) return 0; - //get field clock lengths - uint16_t fcs=0; - if (!fchigh || !fclow) { - fcs = countFC(BitStream, BitLen, 1); - if (!fcs) { - fchigh = 10; - fclow = 8; - } else { - fchigh = (fcs >> 8) & 0x00FF; - fclow = fcs & 0x00FF; - } - } - //get bit clock length - if (!rfLen) { - int firstClockEdge = 0; //todo - align grid on graph with this... - rfLen = detectFSKClk(BitStream, BitLen, fchigh, fclow, &firstClockEdge); - if (!rfLen) rfLen = 50; - } - int startIdx = 0; - int size = fskdemod(BitStream, BitLen, rfLen, invert, fchigh, fclow, &startIdx); - if (size > 0) { - setDemodBuf(BitStream,size,0); - setClockGrid(rfLen, startIdx); + int i, j; + int minMark = 0, maxMark = 0; - // Now output the bitstream to the scrollback by line of 16 bits - if (verbose || g_debugMode) { - PrintAndLog("\nUsing Clock:%u, invert:%u, fchigh:%u, fclow:%u", (unsigned int)rfLen, (unsigned int)invert, (unsigned int)fchigh, (unsigned int)fclow); - PrintAndLog("%s decoded bitstream:",GetFSKType(fchigh,fclow,invert)); - printDemodBuff(); - } + for (i = 0; i < GraphTraceLen - convLen; ++i) { + int lowSum = 0, highSum = 0; - return 1; - } else { - if (g_debugMode) PrintAndLog("no FSK data found"); - } - return 0; -} + for (j = 0; j < lowLen; ++j) { + lowSum += LowTone[j]*GraphBuffer[i+j]; + } + for (j = 0; j < highLen; ++j) { + highSum += HighTone[j] * GraphBuffer[i + j]; + } + lowSum = abs(100 * lowSum / lowLen); + highSum = abs(100 * highSum / highLen); + GraphBuffer[i] = (highSum << 16) | lowSum; + } -//by marshmellow -//fsk raw demod and print binary -//takes 4 arguments - Clock, invert, fchigh, fclow -//defaults: clock = 50, invert=1, fchigh=10, fclow=8 (RF/10 RF/8 (fsk2a)) -int CmdFSKrawdemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 20 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod fs [clock] [fchigh] [fclow]"); - PrintAndLog(" [set clock as integer] optional, omit for autodetect."); - PrintAndLog(" , 1 for invert output, can be used even if the clock is omitted"); - PrintAndLog(" [fchigh], larger field clock length, omit for autodetect"); - PrintAndLog(" [fclow], small field clock length, omit for autodetect"); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); - PrintAndLog(" : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc"); - PrintAndLog(" : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); - PrintAndLog(" : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); - PrintAndLog(" : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); - PrintAndLog(" : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); - PrintAndLog(" : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer"); - return 0; - } - return FSKrawDemod(Cmd, true); -} + for(i = 0; i < GraphTraceLen - convLen - 16; ++i) { + int lowTot = 0, highTot = 0; + // 10 and 8 are f_s divided by f_l and f_h, rounded + for (j = 0; j < 10; ++j) { + lowTot += (GraphBuffer[i+j] & 0xffff); + } + for (j = 0; j < 8; j++) { + highTot += (GraphBuffer[i + j] >> 16); + } + GraphBuffer[i] = lowTot - highTot; + if (GraphBuffer[i] > maxMark) maxMark = GraphBuffer[i]; + if (GraphBuffer[i] < minMark) minMark = GraphBuffer[i]; + } -//by marshmellow -//attempt to psk1 demod graph buffer -int PSKDemod(const char *Cmd, bool verbose) -{ - int invert=0; - int clk=0; - int maxErr=100; - sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); - if (clk==1){ - invert=1; - clk=0; - } - if (invert != 0 && invert != 1) { - if (g_debugMode || verbose) PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - size_t BitLen = getFromGraphBuf(BitStream); - if (BitLen==0) return 0; - int errCnt=0; - int startIdx = 0; - errCnt = pskRawDemod_ext(BitStream, &BitLen, &clk, &invert, &startIdx); - if (errCnt > maxErr){ - if (g_debugMode || verbose) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); - return 0; - } - if (errCnt<0|| BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first) - if (g_debugMode || verbose) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); - return 0; - } - if (verbose || g_debugMode){ - PrintAndLog("\nUsing Clock:%d, invert:%d, Bits Found:%d",clk,invert,BitLen); - if (errCnt>0){ - PrintAndLog("# Errors during Demoding (shown as 7 in bit stream): %d",errCnt); - } - } - //prime demod buffer for output - setDemodBuf(BitStream,BitLen,0); - setClockGrid(clk, startIdx); + GraphTraceLen -= (convLen + 16); + RepaintGraphWindow(); - return 1; -} + // Find bit-sync (3 lo followed by 3 high) + int max = 0, maxPos = 0; + for (i = 0; i < 6000; ++i) { + int dec = 0; + for (j = 0; j < 3 * lowLen; ++j) { + dec -= GraphBuffer[i + j]; + } + for (; j < 3 * (lowLen + highLen ); ++j) { + dec += GraphBuffer[i + j]; + } + if (dec > max) { + max = dec; + maxPos = i; + } + } -// by marshmellow -// takes 3 arguments - clock, invert, maxErr as integers -// attempts to demodulate nrz only -// prints binary found and saves in demodbuffer for further commands -int NRZrawDemod(const char *Cmd, bool verbose) -{ - int invert=0; - int clk=0; - int maxErr=100; - sscanf(Cmd, "%i %i %i", &clk, &invert, &maxErr); - if (clk==1){ - invert=1; - clk=0; - } - if (invert != 0 && invert != 1) { - PrintAndLog("Invalid argument: %s", Cmd); - return 0; - } - uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; - size_t BitLen = getFromGraphBuf(BitStream); - if (BitLen==0) return 0; - int errCnt=0; - int clkStartIdx = 0; - errCnt = nrzRawDemod(BitStream, &BitLen, &clk, &invert, &clkStartIdx); - if (errCnt > maxErr){ - if (g_debugMode) PrintAndLog("Too many errors found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); - return 0; - } - if (errCnt<0 || BitLen<16){ //throw away static - allow 1 and -1 (in case of threshold command first) - if (g_debugMode) PrintAndLog("no data found, clk: %d, invert: %d, numbits: %d, errCnt: %d",clk,invert,BitLen,errCnt); - return 0; - } - if (verbose || g_debugMode) PrintAndLog("Tried NRZ Demod using Clock: %d - invert: %d - Bits Found: %d",clk,invert,BitLen); - //prime demod buffer for output - setDemodBuf(BitStream,BitLen,0); - setClockGrid(clk, clkStartIdx); + // place start of bit sync marker in graph + GraphBuffer[maxPos] = maxMark; + GraphBuffer[maxPos + 1] = minMark; + maxPos += j; - if (errCnt>0 && (verbose || g_debugMode)) PrintAndLog("# Errors during Demoding (shown as 7 in bit stream): %d",errCnt); - if (verbose || g_debugMode) { - PrintAndLog("NRZ demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - } - return 1; -} + // place end of bit sync marker in graph + GraphBuffer[maxPos] = maxMark; + GraphBuffer[maxPos+1] = minMark; -int CmdNRZrawDemod(const char *Cmd) -{ - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod nr [clock] <0|1> [maxError]"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); - PrintAndLog(" , 1 for invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100."); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); - PrintAndLog(" : data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); - PrintAndLog(" : data rawdemod nr 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLog(" : data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); - PrintAndLog(" : data rawdemod nr 64 1 0 = demod a nrz/direct tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - return 0; - } - return NRZrawDemod(Cmd, true); -} + PrintAndLog("actual data bits start at sample %d", maxPos); + PrintAndLog("length %d/%d", highLen, lowLen); -// by marshmellow -// takes 3 arguments - clock, invert, maxErr as integers -// attempts to demodulate psk only -// prints binary found and saves in demodbuffer for further commands -int CmdPSK1rawDemod(const char *Cmd) -{ - int ans; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod p1 [clock] <0|1> [maxError]"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); - PrintAndLog(" , 1 for invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100."); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod p1 = demod a psk1 tag from GraphBuffer"); - PrintAndLog(" : data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); - PrintAndLog(" : data rawdemod p1 32 1 = demod a psk1 tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLog(" : data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); - PrintAndLog(" : data rawdemod p1 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - return 0; - } - ans = PSKDemod(Cmd, true); - //output - if (!ans){ - if (g_debugMode) PrintAndLog("Error demoding: %d",ans); - return 0; - } + uint8_t bits[46]; + bits[sizeof(bits)-1] = '\0'; - PrintAndLog("PSK1 demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - return 1; -} + // find bit pairs and manchester decode them + for (i = 0; i < arraylen(bits) - 1; ++i) { + int dec = 0; + for (j = 0; j < lowLen; ++j) { + dec -= GraphBuffer[maxPos + j]; + } + for (; j < lowLen + highLen; ++j) { + dec += GraphBuffer[maxPos + j]; + } + maxPos += j; + // place inter bit marker in graph + GraphBuffer[maxPos] = maxMark; + GraphBuffer[maxPos + 1] = minMark; -// by marshmellow -// takes same args as cmdpsk1rawdemod -int CmdPSK2rawDemod(const char *Cmd) -{ - int ans=0; - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 16 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: data rawdemod p2 [clock] <0|1> [maxError]"); - PrintAndLog(" [set clock as integer] optional, if not set, autodetect."); - PrintAndLog(" , 1 for invert output"); - PrintAndLog(" [set maximum allowed errors], default = 100."); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); - PrintAndLog(" : data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); - PrintAndLog(" : data rawdemod p2 32 1 = demod a psk2 tag from GraphBuffer using a clock of RF/32 and inverting output"); - PrintAndLog(" : data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); - PrintAndLog(" : data rawdemod p2 64 1 0 = demod a psk2 tag from GraphBuffer using a clock of RF/64, inverting output and allowing 0 demod errors"); - return 0; - } - ans=PSKDemod(Cmd, true); - if (!ans){ - if (g_debugMode) PrintAndLog("Error demoding: %d",ans); - return 0; - } - psk1TOpsk2(DemodBuffer, DemodBufferLen); - PrintAndLog("PSK2 demoded bitstream:"); - // Now output the bitstream to the scrollback by line of 16 bits - printDemodBuff(); - return 1; -} - -// by marshmellow - combines all raw demod functions into one menu command -int CmdRawDemod(const char *Cmd) -{ - char cmdp = Cmd[0]; //param_getchar(Cmd, 0); - - if (strlen(Cmd) > 35 || cmdp == 'h' || cmdp == 'H' || strlen(Cmd)<2) { - PrintAndLog("Usage: data rawdemod [modulation] |"); - PrintAndLog(" [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); - PrintAndLog(" 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); - PrintAndLog(" as 'h', prints the help for the specific modulation"); - PrintAndLog(" see specific modulation help for optional parameters"); - PrintAndLog(""); - PrintAndLog(" sample: data rawdemod fs h = print help specific to fsk demod"); - PrintAndLog(" : data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); - PrintAndLog(" : data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); - PrintAndLog(" : data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); - PrintAndLog(" : data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); - PrintAndLog(" : data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); - PrintAndLog(" : data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); - PrintAndLog(" : data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); - return 0; - } - char cmdp2 = Cmd[1]; - int ans = 0; - if (cmdp == 'f' && cmdp2 == 's'){ - ans = CmdFSKrawdemod(Cmd+2); - } else if(cmdp == 'a' && cmdp2 == 'b'){ - ans = Cmdaskbiphdemod(Cmd+2); - } else if(cmdp == 'a' && cmdp2 == 'm'){ - ans = Cmdaskmandemod(Cmd+2); - } else if(cmdp == 'a' && cmdp2 == 'r'){ - ans = Cmdaskrawdemod(Cmd+2); - } else if(cmdp == 'n' && cmdp2 == 'r'){ - ans = CmdNRZrawDemod(Cmd+2); - } else if(cmdp == 'p' && cmdp2 == '1'){ - ans = CmdPSK1rawDemod(Cmd+2); - } else if(cmdp == 'p' && cmdp2 == '2'){ - ans = CmdPSK2rawDemod(Cmd+2); - } else { - PrintAndLog("unknown modulation entered - see help ('h') for parameter structure"); - } - return ans; -} - -void setClockGrid(int clk, int offset) { - g_DemodStartIdx = offset; - g_DemodClock = clk; - if (g_debugMode) PrintAndLog("demodoffset %d, clk %d",offset,clk); - - if (offset > clk) offset %= clk; - if (offset < 0) offset += clk; - - if (offset > GraphTraceLen || offset < 0) return; - if (clk < 8 || clk > GraphTraceLen) { - GridLocked = false; - GridOffset = 0; - PlotGridX = 0; - PlotGridXdefault = 0; - RepaintGraphWindow(); - } else { - GridLocked = true; - GridOffset = offset; - PlotGridX = clk; - PlotGridXdefault = clk; - RepaintGraphWindow(); - } + // hi and lo form a 64 bit pair + hi = (hi << 1) | (lo >> 31); + lo = (lo << 1); + // store decoded bit as binary (in hi/lo) and text (in bits[]) + if(dec < 0) { + bits[i] = '1'; + lo |= 1; + } else { + bits[i] = '0'; + } + } + PrintAndLog("bits: '%s'", bits); + PrintAndLog("hex: %08x %08x", hi, lo); + return 0; } int CmdGrid(const char *Cmd) { - sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); - PlotGridXdefault= PlotGridX; - PlotGridYdefault= PlotGridY; - RepaintGraphWindow(); - return 0; -} - -int CmdSetGraphMarkers(const char *Cmd) { - sscanf(Cmd, "%i %i", &CursorCPos, &CursorDPos); - RepaintGraphWindow(); - return 0; + sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); + PlotGridXdefault= PlotGridX; + PlotGridYdefault= PlotGridY; + RepaintGraphWindow(); + return 0; } int CmdHexsamples(const char *Cmd) { - int i, j; - int requested = 0; - int offset = 0; - char string_buf[25]; - char* string_ptr = string_buf; - uint8_t got[BIGBUF_SIZE]; + int i, j; + int requested = 0; + int offset = 0; + char string_buf[25]; + char* string_ptr = string_buf; + uint8_t got[40000]; + + sscanf(Cmd, "%i %i", &requested, &offset); - sscanf(Cmd, "%i %i", &requested, &offset); + /* if no args send something */ + if (requested == 0) { + requested = 8; + } + if (offset + requested > sizeof(got)) { + PrintAndLog("Tried to read past end of buffer, + > 40000"); + return 0; + } - /* if no args send something */ - if (requested == 0) { - requested = 8; - } - if (offset + requested > sizeof(got)) { - PrintAndLog("Tried to read past end of buffer, + > %d", BIGBUF_SIZE); - return 0; - } + GetFromBigBuf(got,requested,offset); + WaitForResponse(CMD_ACK,NULL); - GetFromBigBuf(got, requested, offset, NULL, -1, false); - - i = 0; - for (j = 0; j < requested; j++) { - i++; - string_ptr += sprintf(string_ptr, "%02x ", got[j]); - if (i == 8) { - *(string_ptr - 1) = '\0'; // remove the trailing space - PrintAndLog("%s", string_buf); - string_buf[0] = '\0'; - string_ptr = string_buf; - i = 0; - } - if (j == requested - 1 && string_buf[0] != '\0') { // print any remaining bytes - *(string_ptr - 1) = '\0'; - PrintAndLog("%s", string_buf); - string_buf[0] = '\0'; - } - } - return 0; + i = 0; + for (j = 0; j < requested; j++) { + i++; + string_ptr += sprintf(string_ptr, "%02x ", got[j]); + if (i == 8) { + *(string_ptr - 1) = '\0'; // remove the trailing space + PrintAndLog("%s", string_buf); + string_buf[0] = '\0'; + string_ptr = string_buf; + i = 0; + } + if (j == requested - 1 && string_buf[0] != '\0') { // print any remaining bytes + *(string_ptr - 1) = '\0'; + PrintAndLog("%s", string_buf); + string_buf[0] = '\0'; + } + } + return 0; } int CmdHide(const char *Cmd) { - HideGraphWindow(); - return 0; + HideGraphWindow(); + return 0; } -//zero mean GraphBuffer int CmdHpf(const char *Cmd) { - int i; - int accum = 0; + int i; + int accum = 0; - for (i = 10; i < GraphTraceLen; ++i) - accum += GraphBuffer[i]; - accum /= (GraphTraceLen - 10); - for (i = 0; i < GraphTraceLen; ++i) - GraphBuffer[i] -= accum; + for (i = 10; i < GraphTraceLen; ++i) + accum += GraphBuffer[i]; + accum /= (GraphTraceLen - 10); + for (i = 0; i < GraphTraceLen; ++i) + GraphBuffer[i] -= accum; - RepaintGraphWindow(); - return 0; -} - -uint8_t getByte(uint8_t bits_per_sample, BitstreamIn* b) -{ - int i; - uint8_t val = 0; - for(i =0 ; i < bits_per_sample; i++) - { - val |= (headBit(b) << (7-i)); - } - return val; -} - -int getSamples(int n, bool silent) -{ - //If we get all but the last byte in bigbuf, - // we don't have to worry about remaining trash - // in the last byte in case the bits-per-sample - // does not line up on byte boundaries - - uint8_t got[BIGBUF_SIZE-1] = { 0 }; - - if (n == 0 || n > sizeof(got)) - n = sizeof(got); - - if (!silent) PrintAndLog("Reading %d bytes from device memory\n", n); - UsbCommand response; - GetFromBigBuf(got, n, 0, &response, -1, false); - if (!silent) PrintAndLog("Data fetched"); - uint8_t bits_per_sample = 8; - - //Old devices without this feature would send 0 at arg[0] - if(response.arg[0] > 0) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Waddress-of-packed-member" - sample_config *sc = (sample_config *) response.d.asBytes; - #pragma GCC diagnostic pop - if (!silent) PrintAndLog("Samples @ %d bits/smpl, decimation 1:%d ", sc->bits_per_sample - , sc->decimation); - bits_per_sample = sc->bits_per_sample; - } - - if(bits_per_sample < 8) - { - if (!silent) PrintAndLog("Unpacking..."); - BitstreamIn bout = { got, bits_per_sample * n, 0}; - int j =0; - for (j = 0; j * bits_per_sample < n * 8 && j < n; j++) { - uint8_t sample = getByte(bits_per_sample, &bout); - GraphBuffer[j] = ((int) sample )- 128; - } - GraphTraceLen = j; - PrintAndLog("Unpacked %d samples" , j ); - }else - { - for (int j = 0; j < n; j++) { - GraphBuffer[j] = ((int)got[j]) - 128; - } - GraphTraceLen = n; - } - - setClockGrid(0,0); - DemodBufferLen = 0; - RepaintGraphWindow(); - return 0; + RepaintGraphWindow(); + return 0; } int CmdSamples(const char *Cmd) { - int n = strtol(Cmd, NULL, 0); - return getSamples(n, false); + int cnt = 0; + int n; + uint8_t got[40000]; + + n = strtol(Cmd, NULL, 0); + if (n == 0) n = 512; + if (n > sizeof(got)) n = sizeof(got); + + PrintAndLog("Reading %d samples\n", n); + GetFromBigBuf(got,n,0); + WaitForResponse(CMD_ACK,NULL); + for (int j = 0; j < n; j++) { + GraphBuffer[cnt++] = ((int)got[j]) - 128; + } + + PrintAndLog("Done!\n"); + GraphTraceLen = n; + RepaintGraphWindow(); + return 0; } -int CmdTuneSamples(const char *Cmd) -{ - int timeout = 0, arg = FLAG_TUNE_ALL; - - if(*Cmd == 'l') { - arg = FLAG_TUNE_LF; - } else if (*Cmd == 'h') { - arg = FLAG_TUNE_HF; - } else if (*Cmd != '\0') { - PrintAndLog("use 'tune' or 'tune l' or 'tune h'"); - return 0; - } - - printf("\nMeasuring antenna characteristics, please wait..."); - - UsbCommand c = {CMD_MEASURE_ANTENNA_TUNING, {arg, 0, 0}}; - SendCommand(&c); - - UsbCommand resp; - while(!WaitForResponseTimeout(CMD_MEASURED_ANTENNA_TUNING,&resp,1000)) { - timeout++; - printf("."); - if (timeout > 7) { - PrintAndLog("\nNo response from Proxmark. Aborting..."); - return 1; - } - } - - int peakv, peakf; - int vLf125, vLf134, vHf; - vLf125 = resp.arg[0] & 0xffff; - vLf134 = resp.arg[0] >> 16; - vHf = resp.arg[1] & 0xffff;; - peakf = resp.arg[2] & 0xffff; - peakv = resp.arg[2] >> 16; - PrintAndLog(""); - if (arg & FLAG_TUNE_LF) - { - PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/500.0); - PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/500.0); - PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/500.0, 12000.0/(peakf+1)); - } - if (arg & FLAG_TUNE_HF) - PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0); - - #define LF_UNUSABLE_V 3000 - #define LF_MARGINAL_V 15000 - #define HF_UNUSABLE_V 3200 - #define HF_MARGINAL_V 8000 - - if (arg & FLAG_TUNE_LF) - { - if (peakv<<1 < LF_UNUSABLE_V) - PrintAndLog("# Your LF antenna is unusable."); - else if (peakv<<1 < LF_MARGINAL_V) - PrintAndLog("# Your LF antenna is marginal."); - } - if (arg & FLAG_TUNE_HF) - { - if (vHf < HF_UNUSABLE_V) - PrintAndLog("# Your HF antenna is unusable."); - else if (vHf < HF_MARGINAL_V) - PrintAndLog("# Your HF antenna is marginal."); - } - - if (peakv<<1 >= LF_UNUSABLE_V) { - for (int i = 0; i < 256; i++) { - GraphBuffer[i] = resp.d.asBytes[i] - 128; - } - PrintAndLog("Displaying LF tuning graph. Divisor 89 is 134khz, 95 is 125khz.\n"); - PrintAndLog("\n"); - GraphTraceLen = 256; - ShowGraphWindow(); - RepaintGraphWindow(); - } - - return 0; -} - - int CmdLoad(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; + FILE *f = fopen(Cmd, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return 0; + } - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - FILE *f = fopen(filename, "r"); - if (!f) { - PrintAndLog("couldn't open '%s'", filename); - return 0; - } - - GraphTraceLen = 0; - char line[80]; - while (fgets(line, sizeof (line), f)) { - GraphBuffer[GraphTraceLen] = atoi(line); - GraphTraceLen++; - } - fclose(f); - PrintAndLog("loaded %d samples", GraphTraceLen); - setClockGrid(0,0); - DemodBufferLen = 0; - RepaintGraphWindow(); - return 0; + GraphTraceLen = 0; + char line[80]; + while (fgets(line, sizeof (line), f)) { + GraphBuffer[GraphTraceLen] = atoi(line); + GraphTraceLen++; + } + fclose(f); + PrintAndLog("loaded %d samples", GraphTraceLen); + RepaintGraphWindow(); + return 0; } int CmdLtrim(const char *Cmd) { - int ds = atoi(Cmd); - if (GraphTraceLen<=0) return 0; - for (int i = ds; i < GraphTraceLen; ++i) - GraphBuffer[i-ds] = GraphBuffer[i]; - GraphTraceLen -= ds; + int ds = atoi(Cmd); - RepaintGraphWindow(); - return 0; + for (int i = ds; i < GraphTraceLen; ++i) + GraphBuffer[i-ds] = GraphBuffer[i]; + GraphTraceLen -= ds; + + RepaintGraphWindow(); + return 0; } -// trim graph to input argument length -int CmdRtrim(const char *Cmd) +/* + * Manchester demodulate a bitstream. The bitstream needs to be already in + * the GraphBuffer as 0 and 1 values + * + * Give the clock rate as argument in order to help the sync - the algorithm + * resyncs at each pulse anyway. + * + * Not optimized by any means, this is the 1st time I'm writing this type of + * routine, feel free to improve... + * + * 1st argument: clock rate (as number of samples per clock rate) + * Typical values can be 64, 32, 128... + */ +int CmdManchesterDemod(const char *Cmd) { - int ds = atoi(Cmd); + int i, j, invert= 0; + int bit; + int clock; + int lastval = 0; + int low = 0; + int high = 0; + int hithigh, hitlow, first; + int lc = 0; + int bitidx = 0; + int bit2idx = 0; + int warnings = 0; - GraphTraceLen = ds; + /* check if we're inverting output */ + if (*Cmd == 'i') + { + PrintAndLog("Inverting output"); + invert = 1; + ++Cmd; + do + ++Cmd; + while(*Cmd == ' '); // in case a 2nd argument was given + } - RepaintGraphWindow(); - return 0; + /* Holds the decoded bitstream: each clock period contains 2 bits */ + /* later simplified to 1 bit after manchester decoding. */ + /* Add 10 bits to allow for noisy / uncertain traces without aborting */ + /* int BitStream[GraphTraceLen*2/clock+10]; */ + + /* But it does not work if compiling on WIndows: therefore we just allocate a */ + /* large array */ + uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; + + /* Detect high and lows */ + for (i = 0; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] > high) + high = GraphBuffer[i]; + else if (GraphBuffer[i] < low) + low = GraphBuffer[i]; + } + + /* Get our clock */ + clock = GetClock(Cmd, high, 1); + + int tolerance = clock/4; + + /* Detect first transition */ + /* Lo-Hi (arbitrary) */ + /* skip to the first high */ + for (i= 0; i < GraphTraceLen; i++) + if (GraphBuffer[i] == high) + break; + /* now look for the first low */ + for (; i < GraphTraceLen; i++) + { + if (GraphBuffer[i] == low) + { + lastval = i; + break; + } + } + + /* If we're not working with 1/0s, demod based off clock */ + if (high != 1) + { + bit = 0; /* We assume the 1st bit is zero, it may not be + * the case: this routine (I think) has an init problem. + * Ed. + */ + for (; i < (int)(GraphTraceLen / clock); i++) + { + hithigh = 0; + hitlow = 0; + first = 1; + + /* Find out if we hit both high and low peaks */ + for (j = 0; j < clock; j++) + { + if (GraphBuffer[(i * clock) + j] == high) + hithigh = 1; + else if (GraphBuffer[(i * clock) + j] == low) + hitlow = 1; + + /* it doesn't count if it's the first part of our read + because it's really just trailing from the last sequence */ + if (first && (hithigh || hitlow)) + hithigh = hitlow = 0; + else + first = 0; + + if (hithigh && hitlow) + break; + } + + /* If we didn't hit both high and low peaks, we had a bit transition */ + if (!hithigh || !hitlow) + bit ^= 1; + + BitStream[bit2idx++] = bit ^ invert; + } + } + + /* standard 1/0 bitstream */ + else + { + + /* Then detect duration between 2 successive transitions */ + for (bitidx = 1; i < GraphTraceLen; i++) + { + if (GraphBuffer[i-1] != GraphBuffer[i]) + { + lc = i-lastval; + lastval = i; + + // Error check: if bitidx becomes too large, we do not + // have a Manchester encoded bitstream or the clock is really + // wrong! + if (bitidx > (GraphTraceLen*2/clock+8) ) { + PrintAndLog("Error: the clock you gave is probably wrong, aborting."); + return 0; + } + // Then switch depending on lc length: + // Tolerance is 1/4 of clock rate (arbitrary) + if (abs(lc-clock/2) < tolerance) { + // Short pulse : either "1" or "0" + BitStream[bitidx++]=GraphBuffer[i-1]; + } else if (abs(lc-clock) < tolerance) { + // Long pulse: either "11" or "00" + BitStream[bitidx++]=GraphBuffer[i-1]; + BitStream[bitidx++]=GraphBuffer[i-1]; + } else { + // Error + warnings++; + PrintAndLog("Warning: Manchester decode error for pulse width detection."); + PrintAndLog("(too many of those messages mean either the stream is not Manchester encoded, or clock is wrong)"); + + if (warnings > 10) + { + PrintAndLog("Error: too many detection errors, aborting."); + return 0; + } + } + } + } + + // At this stage, we now have a bitstream of "01" ("1") or "10" ("0"), parse it into final decoded bitstream + // Actually, we overwrite BitStream with the new decoded bitstream, we just need to be careful + // to stop output at the final bitidx2 value, not bitidx + for (i = 0; i < bitidx; i += 2) { + if ((BitStream[i] == 0) && (BitStream[i+1] == 1)) { + BitStream[bit2idx++] = 1 ^ invert; + } else if ((BitStream[i] == 1) && (BitStream[i+1] == 0)) { + BitStream[bit2idx++] = 0 ^ invert; + } else { + // We cannot end up in this state, this means we are unsynchronized, + // move up 1 bit: + i++; + warnings++; + PrintAndLog("Unsynchronized, resync..."); + PrintAndLog("(too many of those messages mean the stream is not Manchester encoded)"); + + if (warnings > 10) + { + PrintAndLog("Error: too many decode errors, aborting."); + return 0; + } + } + } + } + + PrintAndLog("Manchester decoded bitstream"); + // Now output the bitstream to the scrollback by line of 16 bits + for (i = 0; i < (bit2idx-16); i+=16) { + PrintAndLog("%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i", + BitStream[i], + BitStream[i+1], + BitStream[i+2], + BitStream[i+3], + BitStream[i+4], + BitStream[i+5], + BitStream[i+6], + BitStream[i+7], + BitStream[i+8], + BitStream[i+9], + BitStream[i+10], + BitStream[i+11], + BitStream[i+12], + BitStream[i+13], + BitStream[i+14], + BitStream[i+15]); + } + return 0; } -// trim graph (middle) piece -int CmdMtrim(const char *Cmd) { - int start = 0, stop = 0; - sscanf(Cmd, "%i %i", &start, &stop); +/* Modulate our data into manchester */ +int CmdManchesterMod(const char *Cmd) +{ + int i, j; + int clock; + int bit, lastbit, wave; - if (start > GraphTraceLen || stop > GraphTraceLen || start > stop) return 0; - start++; //leave start position sample + /* Get our clock */ + clock = GetClock(Cmd, 0, 1); - GraphTraceLen = stop - start; - for (int i = 0; i < GraphTraceLen; i++) { - GraphBuffer[i] = GraphBuffer[start+i]; - } - return 0; + wave = 0; + lastbit = 1; + for (i = 0; i < (int)(GraphTraceLen / clock); i++) + { + bit = GraphBuffer[i * clock] ^ 1; + + for (j = 0; j < (int)(clock/2); j++) + GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave; + for (j = (int)(clock/2); j < clock; j++) + GraphBuffer[(i * clock) + j] = bit ^ lastbit ^ wave ^ 1; + + /* Keep track of how we start our wave and if we changed or not this time */ + wave ^= bit ^ lastbit; + lastbit = bit; + } + + RepaintGraphWindow(); + return 0; } - int CmdNorm(const char *Cmd) { - int i; - int max = INT_MIN, min = INT_MAX; + int i; + int max = INT_MIN, min = INT_MAX; - for (i = 10; i < GraphTraceLen; ++i) { - if (GraphBuffer[i] > max) - max = GraphBuffer[i]; - if (GraphBuffer[i] < min) - min = GraphBuffer[i]; - } + for (i = 10; i < GraphTraceLen; ++i) { + if (GraphBuffer[i] > max) + max = GraphBuffer[i]; + if (GraphBuffer[i] < min) + min = GraphBuffer[i]; + } - if (max != min) { - for (i = 0; i < GraphTraceLen; ++i) { - GraphBuffer[i] = ((long)(GraphBuffer[i] - ((max + min) / 2)) * 256) / (max - min); - //marshmelow: adjusted *1000 to *256 to make +/- 128 so demod commands still work - } - } - RepaintGraphWindow(); - return 0; + if (max != min) { + for (i = 0; i < GraphTraceLen; ++i) { + GraphBuffer[i] = (GraphBuffer[i] - ((max + min) / 2)) * 1000 / + (max - min); + } + } + RepaintGraphWindow(); + return 0; } int CmdPlot(const char *Cmd) { - ShowGraphWindow(); - return 0; + ShowGraphWindow(); + return 0; } int CmdSave(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - - FILE *f = fopen(filename, "w"); - if(!f) { - PrintAndLog("couldn't open '%s'", filename); - return 0; - } - int i; - for (i = 0; i < GraphTraceLen; i++) { - fprintf(f, "%d\n", GraphBuffer[i]); - } - fclose(f); - PrintAndLog("saved to '%s'", Cmd); - return 0; + FILE *f = fopen(Cmd, "w"); + if(!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return 0; + } + int i; + for (i = 0; i < GraphTraceLen; i++) { + fprintf(f, "%d\n", GraphBuffer[i]); + } + fclose(f); + PrintAndLog("saved to '%s'", Cmd); + return 0; } int CmdScale(const char *Cmd) { - CursorScaleFactor = atoi(Cmd); - if (CursorScaleFactor == 0) { - PrintAndLog("bad, can't have zero scale"); - CursorScaleFactor = 1; - } - RepaintGraphWindow(); - return 0; + CursorScaleFactor = atoi(Cmd); + if (CursorScaleFactor == 0) { + PrintAndLog("bad, can't have zero scale"); + CursorScaleFactor = 1; + } + RepaintGraphWindow(); + return 0; } -int directionalThreshold(const int* in, int *out, size_t len, int8_t up, int8_t down) +int CmdThreshold(const char *Cmd) { - int lastValue = in[0]; - out[0] = 0; // Will be changed at the end, but init 0 as we adjust to last samples value if no threshold kicks in. + int threshold = atoi(Cmd); - for (int i = 1; i < len; ++i) { - // Apply first threshold to samples heading up - if (in[i] >= up && in[i] > lastValue) - { - lastValue = out[i]; // Buffer last value as we overwrite it. - out[i] = 1; - } - // Apply second threshold to samples heading down - else if (in[i] <= down && in[i] < lastValue) - { - lastValue = out[i]; // Buffer last value as we overwrite it. - out[i] = -1; - } - else - { - lastValue = out[i]; // Buffer last value as we overwrite it. - out[i] = out[i-1]; - } - } - out[0] = out[1]; // Align with first edited sample. - return 0; -} - -int CmdDirectionalThreshold(const char *Cmd) -{ - int8_t upThres = param_get8(Cmd, 0); - int8_t downThres = param_get8(Cmd, 1); - - printf("Applying Up Threshold: %d, Down Threshold: %d\n", upThres, downThres); - - directionalThreshold(GraphBuffer, GraphBuffer,GraphTraceLen, upThres, downThres); - RepaintGraphWindow(); - return 0; + for (int i = 0; i < GraphTraceLen; ++i) { + if (GraphBuffer[i] >= threshold) + GraphBuffer[i] = 1; + else + GraphBuffer[i] = -1; + } + RepaintGraphWindow(); + return 0; } int CmdZerocrossings(const char *Cmd) { - // Zero-crossings aren't meaningful unless the signal is zero-mean. - CmdHpf(""); + // Zero-crossings aren't meaningful unless the signal is zero-mean. + CmdHpf(""); - int sign = 1; - int zc = 0; - int lastZc = 0; + int sign = 1; + int zc = 0; + int lastZc = 0; - for (int i = 0; i < GraphTraceLen; ++i) { - if (GraphBuffer[i] * sign >= 0) { - // No change in sign, reproduce the previous sample count. - zc++; - GraphBuffer[i] = lastZc; - } else { - // Change in sign, reset the sample count. - sign = -sign; - GraphBuffer[i] = lastZc; - if (sign > 0) { - lastZc = zc; - zc = 0; - } - } - } + for (int i = 0; i < GraphTraceLen; ++i) { + if (GraphBuffer[i] * sign >= 0) { + // No change in sign, reproduce the previous sample count. + zc++; + GraphBuffer[i] = lastZc; + } else { + // Change in sign, reset the sample count. + sign = -sign; + GraphBuffer[i] = lastZc; + if (sign > 0) { + lastZc = zc; + zc = 0; + } + } + } - RepaintGraphWindow(); - return 0; + RepaintGraphWindow(); + return 0; } -int usage_data_bin2hex(){ - PrintAndLog("Usage: data bin2hex "); - PrintAndLog(" This function will ignore all characters not 1 or 0 (but stop reading on whitespace)"); - return 0; -} - -/** - * @brief Utility for conversion via cmdline. - * @param Cmd - * @return - */ -int Cmdbin2hex(const char *Cmd) +static command_t CommandTable[] = { - int bg =0, en =0; - if(param_getptr(Cmd, &bg, &en, 0)) - { - return usage_data_bin2hex(); - } - //Number of digits supplied as argument - size_t length = en - bg +1; - size_t bytelen = (length+7) / 8; - uint8_t* arr = (uint8_t *) malloc(bytelen); - memset(arr, 0, bytelen); - BitstreamOut bout = { arr, 0, 0 }; - - for(; bg <= en ;bg++) - { - char c = Cmd[bg]; - if( c == '1') pushBit(&bout, 1); - else if( c == '0') pushBit(&bout, 0); - else PrintAndLog("Ignoring '%c'", c); - } - - if(bout.numbits % 8 != 0) - { - printf("[padded with %d zeroes]\n", 8-(bout.numbits % 8)); - } - - //Uses printf instead of PrintAndLog since the latter - // adds linebreaks to each printout - this way was more convenient since we don't have to - // allocate a string and write to that first... - for(size_t x = 0; x < bytelen ; x++) - { - printf("%02X", arr[x]); - } - printf("\n"); - free(arr); - return 0; -} - -int usage_data_hex2bin() { - PrintAndLog("Usage: data hex2bin "); - PrintAndLog(" This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); - return 0; - -} - -int Cmdhex2bin(const char *Cmd) -{ - int bg =0, en =0; - if(param_getptr(Cmd, &bg, &en, 0)) - { - return usage_data_hex2bin(); - } - - - while(bg <= en ) - { - char x = Cmd[bg++]; - // capitalize - if (x >= 'a' && x <= 'f') - x -= 32; - // convert to numeric value - if (x >= '0' && x <= '9') - x -= '0'; - else if (x >= 'A' && x <= 'F') - x -= 'A' - 10; - else - continue; - - //Uses printf instead of PrintAndLog since the latter - // adds linebreaks to each printout - this way was more convenient since we don't have to - // allocate a string and write to that first... - - for(int i= 0 ; i < 4 ; ++i) - printf("%d",(x >> (3 - i)) & 1); - } - printf("\n"); - - return 0; -} - - /* // example of FSK2 RF/50 Tones - static const int LowTone[] = { - 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 - }; - static const int HighTone[] = { - 1, 1, 1, 1, 1, -1, -1, -1, -1, // note one extra 1 to padd due to 50/8 remainder (1/2 the remainder) - 1, 1, 1, 1, -1, -1, -1, -1, - 1, 1, 1, 1, -1, -1, -1, -1, - 1, 1, 1, 1, -1, -1, -1, -1, - 1, 1, 1, 1, -1, -1, -1, -1, - 1, 1, 1, 1, -1, -1, -1, -1, -1, // note one extra -1 to padd due to 50/8 remainder - }; - */ -void GetHiLoTone(int *LowTone, int *HighTone, int clk, int LowToneFC, int HighToneFC) { - int i,j=0; - int Left_Modifier = ((clk % LowToneFC) % 2) + ((clk % LowToneFC)/2); - int Right_Modifier = (clk % LowToneFC) / 2; - //int HighToneMod = clk mod HighToneFC; - int LeftHalfFCCnt = (LowToneFC % 2) + (LowToneFC/2); //truncate - int FCs_per_clk = clk/LowToneFC; - - // need to correctly split up the clock to field clocks. - // First attempt uses modifiers on each end to make up for when FCs don't evenly divide into Clk - - // start with LowTone - // set extra 1 modifiers to make up for when FC doesn't divide evenly into Clk - for (i = 0; i < Left_Modifier; i++) { - LowTone[i] = 1; - } - - // loop # of field clocks inside the main clock - for (i = 0; i < (FCs_per_clk); i++) { - // loop # of samples per field clock - for (j = 0; j < LowToneFC; j++) { - LowTone[(i*LowToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1; - } - } - - int k; - // add last -1 modifiers - for (k = 0; k < Right_Modifier; k++) { - LowTone[((i-1)*LowToneFC)+Left_Modifier+j+k] = -1; - } - - // now do hightone - Left_Modifier = ((clk % HighToneFC) % 2) + ((clk % HighToneFC)/2); - Right_Modifier = (clk % HighToneFC) / 2; - LeftHalfFCCnt = (HighToneFC % 2) + (HighToneFC/2); //truncate - FCs_per_clk = clk/HighToneFC; - - for (i = 0; i < Left_Modifier; i++) { - HighTone[i] = 1; - } - - // loop # of field clocks inside the main clock - for (i = 0; i < (FCs_per_clk); i++) { - // loop # of samples per field clock - for (j = 0; j < HighToneFC; j++) { - HighTone[(i*HighToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1; - } - } - - // add last -1 modifiers - for (k = 0; k < Right_Modifier; k++) { - PrintAndLog("(i-1)*HighToneFC+lm+j+k %i",((i-1)*HighToneFC)+Left_Modifier+j+k); - HighTone[((i-1)*HighToneFC)+Left_Modifier+j+k] = -1; - } - if (g_debugMode == 2) { - for ( i = 0; i < clk; i++) { - PrintAndLog("Low: %i, High: %i",LowTone[i],HighTone[i]); - } - } -} - -//old CmdFSKdemod adapted by marshmellow -//converts FSK to clear NRZ style wave. (or demodulates) -int FSKToNRZ(int *data, int *dataLen, int clk, int LowToneFC, int HighToneFC) { - uint8_t ans=0; - if (clk == 0 || LowToneFC == 0 || HighToneFC == 0) { - int firstClockEdge=0; - ans = fskClocks((uint8_t *) &LowToneFC, (uint8_t *) &HighToneFC, (uint8_t *) &clk, false, &firstClockEdge); - if (g_debugMode > 1) { - PrintAndLog ("DEBUG FSKtoNRZ: detected clocks: fc_low %i, fc_high %i, clk %i, firstClockEdge %i, ans %u", LowToneFC, HighToneFC, clk, firstClockEdge, ans); - } - } - // currently only know fsk modulations with field clocks < 10 samples and > 4 samples. filter out to remove false positives (and possibly destroying ask/psk modulated waves...) - if (ans == 0 || clk == 0 || LowToneFC == 0 || HighToneFC == 0 || LowToneFC > 10 || HighToneFC < 4) { - if (g_debugMode > 1) { - PrintAndLog ("DEBUG FSKtoNRZ: no fsk clocks found"); - } - return 0; - } - int LowTone[clk]; - int HighTone[clk]; - GetHiLoTone(LowTone, HighTone, clk, LowToneFC, HighToneFC); - - int i, j; - - // loop through ([all samples] - clk) - for (i = 0; i < *dataLen - clk; ++i) { - int lowSum = 0, highSum = 0; - - // sum all samples together starting from this sample for [clk] samples for each tone (multiply tone value with sample data) - for (j = 0; j < clk; ++j) { - lowSum += LowTone[j] * data[i+j]; - highSum += HighTone[j] * data[i + j]; - } - // get abs( [average sample value per clk] * 100 ) (or a rolling average of sorts) - lowSum = abs(100 * lowSum / clk); - highSum = abs(100 * highSum / clk); - // save these back to buffer for later use - data[i] = (highSum << 16) | lowSum; - } - - // now we have the abs( [average sample value per clk] * 100 ) for each tone - // loop through again [all samples] - clk - 16 - // note why 16??? is 16 the largest FC? changed to LowToneFC as that should be the > fc - for(i = 0; i < *dataLen - clk - LowToneFC; ++i) { - int lowTot = 0, highTot = 0; - - // sum a field clock width of abs( [average sample values per clk] * 100) for each tone - for (j = 0; j < LowToneFC; ++j) { //10 for fsk2 - lowTot += (data[i + j] & 0xffff); - } - for (j = 0; j < HighToneFC; j++) { //8 for fsk2 - highTot += (data[i + j] >> 16); - } - - // subtract the sum of lowTone averages by the sum of highTone averages as it - // and write back the new graph value - data[i] = lowTot - highTot; - } - // update dataLen to what we put back to the data sample buffer - *dataLen -= (clk + LowToneFC); - return 0; -} - -int usage_data_fsktonrz() { - PrintAndLog("Usage: data fsktonrz c l f "); - PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" c enter the a clock (omit to autodetect)"); - PrintAndLog(" l enter a field clock (omit to autodetect)"); - PrintAndLog(" f enter a field clock (omit to autodetect)"); - return 0; -} - -int CmdFSKToNRZ(const char *Cmd) { - // take clk, fc_low, fc_high - // blank = auto; - bool errors = false; - int clk = 0; - char cmdp = 0; - int fc_low = 10, fc_high = 8; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { - case 'h': - case 'H': - return usage_data_fsktonrz(); - case 'C': - case 'c': - clk = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'F': - case 'f': - fc_high = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - case 'L': - case 'l': - fc_low = param_get32ex(Cmd, cmdp+1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - if(errors) break; - } - //Validations - if(errors) return usage_data_fsktonrz(); - - setClockGrid(0,0); - DemodBufferLen = 0; - int ans = FSKToNRZ(GraphBuffer, &GraphTraceLen, clk, fc_low, fc_high); - CmdNorm(""); - RepaintGraphWindow(); - return ans; -} - - -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help"}, - {"askedgedetect", CmdAskEdgeDetect, 1, "[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)"}, - {"autocorr", CmdAutoCorr, 1, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"}, - {"biphaserawdecode",CmdBiphaseDecodeRaw,1, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"}, - {"bin2hex", Cmdbin2hex, 1, "bin2hex -- Converts binary to hexadecimal"}, - {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, - {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, - {"dec", CmdDec, 1, "Decimate samples"}, - {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"}, - {"fsktonrz", CmdFSKToNRZ, 1, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"}, - {"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, - {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, - {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, - {"hex2bin", Cmdhex2bin, 1, "hex2bin -- Converts hexadecimal to binary"}, - {"hide", CmdHide, 1, "Hide graph window"}, - {"hpf", CmdHpf, 1, "Remove DC offset from trace"}, - {"load", CmdLoad, 1, " -- Load trace (to graph window"}, - {"ltrim", CmdLtrim, 1, " -- Trim samples from left of trace"}, - {"rtrim", CmdRtrim, 1, " -- Trim samples from right of trace"}, - {"mtrim", CmdMtrim, 1, " -- Trim out samples from the specified start to the specified stop"}, - {"manrawdecode", Cmdmandecoderaw, 1, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"}, - {"norm", CmdNorm, 1, "Normalize max/min to +/-128"}, - {"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"}, - {"printdemodbuffer",CmdPrintDemodBuff, 1, "[x] [o] [l] -- print the data in the DemodBuffer - 'x' for hex output"}, - {"rawdemod", CmdRawDemod, 1, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, - {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, - {"save", CmdSave, 1, " -- Save trace (from graph window)"}, - {"setgraphmarkers", CmdSetGraphMarkers, 1, "[orange_marker] [blue_marker] (in graph window)"}, - {"scale", CmdScale, 1, " -- Set cursor display scale"}, - {"setdebugmode", CmdSetDebugMode, 1, "<0|1|2> -- Turn on or off Debugging Level for lf demods"}, - {"shiftgraphzero", CmdGraphShiftZero, 1, " -- Shift 0 for Graphed wave + or - shift value"}, - {"dirthreshold", CmdDirectionalThreshold, 1, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, - {"tune", CmdTuneSamples, 0, "Get hw tune samples for graph window"}, - {"undec", CmdUndec, 1, "Un-decimate samples by 2"}, - {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"amp", CmdAmp, 1, "Amplify peaks"}, + {"askdemod", Cmdaskdemod, 1, "<0 or 1> -- Attempt to demodulate simple ASK tags"}, + {"autocorr", CmdAutoCorr, 1, " -- Autocorrelation over window"}, + {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, + {"bitstream", CmdBitstream, 1, "[clock rate] -- Convert waveform into a bitstream"}, + {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, + {"dec", CmdDec, 1, "Decimate samples"}, + {"detectclock", CmdDetectClockRate, 1, "Detect clock rate"}, + {"fskdemod", CmdFSKdemod, 1, "Demodulate graph window as a HID FSK"}, + {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, + {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, + {"hide", CmdHide, 1, "Hide graph window"}, + {"hpf", CmdHpf, 1, "Remove DC offset from trace"}, + {"load", CmdLoad, 1, " -- Load trace (to graph window"}, + {"ltrim", CmdLtrim, 1, " -- Trim samples from left of trace"}, + {"mandemod", CmdManchesterDemod, 1, "[i] [clock rate] -- Manchester demodulate binary stream (option 'i' to invert output)"}, + {"manmod", CmdManchesterMod, 1, "[clock rate] -- Manchester modulate a binary stream"}, + {"norm", CmdNorm, 1, "Normalize max/min to +/-500"}, + {"plot", CmdPlot, 1, "Show graph window (hit 'h' in window for keystroke help)"}, + {"samples", CmdSamples, 0, "[512 - 40000] -- Get raw samples for graph window"}, + {"save", CmdSave, 1, " -- Save trace (from graph window)"}, + {"scale", CmdScale, 1, " -- Set cursor display scale"}, + {"threshold", CmdThreshold, 1, " -- Maximize/minimize every value in the graph window depending on threshold"}, + {"zerocrossings", CmdZerocrossings, 1, "Count time between zero-crossings"}, + {NULL, NULL, 0, NULL} }; int CmdData(const char *Cmd) { - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable); + return 0; } diff --git a/client/cmddata.h b/client/cmddata.h index 0484acdb..2f86a941 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -11,70 +11,33 @@ #ifndef CMDDATA_H__ #define CMDDATA_H__ -#include //size_t -#include //uint_32+ -#include //bool - -#include "cmdparser.h" // for command_t - command_t * CmdDataCommands(); int CmdData(const char *Cmd); -void printDemodBuff(void); -void setDemodBuf(uint8_t *buff, size_t size, size_t startIdx); -bool getDemodBuf(uint8_t *buff, size_t *size); -void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore -int CmdPrintDemodBuff(const char *Cmd); -int Cmdaskrawdemod(const char *Cmd); -int Cmdaskmandemod(const char *Cmd); -int AutoCorrelate(const int *in, int *out, size_t len, int window, bool SaveGrph, bool verbose); + +int CmdAmp(const char *Cmd); +int Cmdaskdemod(const char *Cmd); int CmdAutoCorr(const char *Cmd); -int CmdBiphaseDecodeRaw(const char *Cmd); int CmdBitsamples(const char *Cmd); +int CmdBitstream(const char *Cmd); int CmdBuffClear(const char *Cmd); int CmdDec(const char *Cmd); int CmdDetectClockRate(const char *Cmd); -int CmdFSKrawdemod(const char *Cmd); -int CmdPSK1rawDemod(const char *Cmd); -int CmdPSK2rawDemod(const char *Cmd); +int CmdFSKdemod(const char *Cmd); int CmdGrid(const char *Cmd); -int CmdGetBitStream(const char *Cmd); int CmdHexsamples(const char *Cmd); int CmdHide(const char *Cmd); int CmdHpf(const char *Cmd); int CmdLoad(const char *Cmd); int CmdLtrim(const char *Cmd); -int CmdRtrim(const char *Cmd); -int Cmdmandecoderaw(const char *Cmd); +int CmdManchesterDemod(const char *Cmd); +int CmdManchesterMod(const char *Cmd); int CmdNorm(const char *Cmd); -int CmdNRZrawDemod(const char *Cmd); int CmdPlot(const char *Cmd); -int CmdPrintDemodBuff(const char *Cmd); -int CmdRawDemod(const char *Cmd); int CmdSamples(const char *Cmd); -int CmdTuneSamples(const char *Cmd); int CmdSave(const char *Cmd); int CmdScale(const char *Cmd); -int CmdDirectionalThreshold(const char *Cmd); +int CmdThreshold(const char *Cmd); int CmdZerocrossings(const char *Cmd); -int ASKbiphaseDemod(const char *Cmd, bool verbose); -int ASKDemod(const char *Cmd, bool verbose, bool emSearch, uint8_t askType); -int ASKDemod_ext(const char *Cmd, bool verbose, bool emSearch, uint8_t askType, bool *stCheck); -int FSKrawDemod(const char *Cmd, bool verbose); -int PSKDemod(const char *Cmd, bool verbose); -int NRZrawDemod(const char *Cmd, bool verbose); -int getSamples(int n, bool silent); -void setClockGrid(int clk, int offset); -int directionalThreshold(const int* in, int *out, size_t len, int8_t up, int8_t down); -extern int AskEdgeDetect(const int *in, int *out, int len, int threshold); -//int autoCorr(const int* in, int *out, size_t len, int window); - -#define MAX_DEMOD_BUF_LEN (1024*128) -extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; -extern size_t DemodBufferLen; -extern int g_DemodStartIdx; -extern int g_DemodClock; -extern uint8_t g_debugMode; -#define BIGBUF_SIZE 40000 #endif diff --git a/client/cmdhf.c b/client/cmdhf.c index 5aeb7ce4..d955fc83 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -1,6 +1,5 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh -// Merlok - 2017 // // 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 @@ -9,14 +8,13 @@ // High frequency commands //----------------------------------------------------------------------------- -#include "cmdhf.h" - -#include -#include "usb_cmd.h" -#include "comms.h" +#include +//#include "proxusb.h" +#include "proxmark3.h" +#include "graph.h" #include "ui.h" #include "cmdparser.h" -#include "cliparser/cliparser.h" +#include "cmdhf.h" #include "cmdhf14a.h" #include "cmdhf14b.h" #include "cmdhf15.h" @@ -24,14 +22,6 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" -#include "cmdhfmfp.h" -#include "cmdhfmfu.h" -#include "cmdhftopaz.h" -#include "cmdhflist.h" -#include "cmdhffido.h" -#include "cmddata.h" -#include "graph.h" -#include "fpga.h" static int CmdHelp(const char *Cmd); @@ -42,124 +32,24 @@ int CmdHFTune(const char *Cmd) return 0; } -int CmdHFSearch(const char *Cmd){ - int ans = 0; - PrintAndLog(""); - ans = CmdHF14AInfo("s"); - if (ans > 0) { - PrintAndLog("\nValid ISO14443A Tag Found - Quiting Search\n"); - return ans; - } - ans = HFiClassReader(false, false); - if (ans) { - PrintAndLog("\nValid iClass Tag (or PicoPass Tag) Found - Quiting Search\n"); - return ans; - } - ans = HF15Reader("", false); - if (ans) { - PrintAndLog("\nValid ISO15693 Tag Found - Quiting Search\n"); - return ans; - } - //14b is longest test currently (and rarest chip type) ... put last - ans = infoHF14B(false); - if (ans) { - PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); - return ans; - } - ans = CmdLegicRFRead(""); - if (ans == 0) { - PrintAndLog("\nValid Legic Tag Found - Quiting Search\n"); - return ans; - } - PrintAndLog("\nno known/supported 13.56 MHz tags found\n"); - return 0; -} - -int CmdHFSnoop(const char *Cmd) +static command_t CommandTable[] = { - char * pEnd; - UsbCommand c = {CMD_HF_SNIFFER, {strtol(Cmd, &pEnd,0),strtol(pEnd, &pEnd,0),0}}; - SendCommand(&c); - return 0; -} - - -// static void InterpolateShannon(int *source, size_t source_len, int *dest, size_t dest_len) -// { - // int *buf = (int*)malloc(source_len * sizeof(int)); - // memcpy(buf, source, source_len * sizeof(int)); - // for (int i = 0; i < source_len; i++) { - // buf[i] += 128; - // } - // for (int i = 0; i < dest_len; i++) { - // float value = 0.0; - // for (int j = 0; j < source_len; j++) { - // if (i * source_len == j * dest_len) { // sin(0) / 0 = 1 - // value += (float)buf[j]; - // } else { - // value += (float)buf[j] * sin(((float)i*source_len/dest_len-j)*3.1415) / (((float)i*source_len/dest_len-j)*3.1415); - // } - // } - // dest[i] = value - 128; - // } - // free(buf); -// } - - -static int CmdHFPlot(const char *Cmd) -{ - CLIParserInit("hf plot", - "Plots HF signal after RF signal path and A/D conversion.", - "This can be used after any hf command and will show the last few milliseconds of the HF signal.\n" - "Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n"); - void* argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(Cmd, argtable, true); - - uint8_t buf[FPGA_TRACE_SIZE]; - - if (GetFromFpgaRAM(buf, FPGA_TRACE_SIZE)) { - for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) { - GraphBuffer[i] = (int)buf[i] - 128; - } - GraphTraceLen = FPGA_TRACE_SIZE; - // InterpolateShannon(GraphBuffer, FPGA_TRACE_SIZE, GraphBuffer, FPGA_TRACE_SIZE*8/7); - // GraphTraceLen = FPGA_TRACE_SIZE*8/7; - ShowGraphWindow(); - RepaintGraphWindow(); - } - return 0; -} - - -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help"}, - {"14a", CmdHF14A, 0, "{ ISO14443A RFIDs... }"}, - {"14b", CmdHF14B, 0, "{ ISO14443B RFIDs... }"}, - {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, - {"epa", CmdHFEPA, 0, "{ German Identification Card... }"}, - {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, - {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"mfp", CmdHFMFP, 0, "{ MIFARE Plus RFIDs... }"}, - {"topaz", CmdHFTopaz, 0, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"fido", CmdHFFido, 0, "{ FIDO and FIDO2 authenticators... }"}, - {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {"list", CmdHFList, 1, "List protocol data in trace buffer"}, - {"plot", CmdHFPlot, 0, "Plot signal"}, - {"search", CmdHFSearch, 0, "Search for known HF tags [preliminary]"}, - {"snoop", CmdHFSnoop, 0, " Generic HF Snoop"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, + {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, + {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, + {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, + {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, + {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, + {NULL, NULL, 0, NULL} }; int CmdHF(const char *Cmd) { CmdsParse(CommandTable, Cmd); - return 0; + return 0; } int CmdHelp(const char *Cmd) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 58315582..d16d71ff 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- +// 2011, Merlok // Copyright (C) 2010 iZsh , Hagen Fritsch -// 2011, 2017 - 2019 Merlok // // 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 @@ -9,257 +9,201 @@ // High frequency ISO14443A commands //----------------------------------------------------------------------------- -#include "cmdhf14a.h" - #include #include -#include #include #include -#include #include "util.h" -#include "util_posix.h" #include "iso14443crc.h" -#include "comms.h" +#include "data.h" +#include "proxmark3.h" #include "ui.h" #include "cmdparser.h" +#include "cmdhf14a.h" #include "common.h" #include "cmdmain.h" #include "mifare.h" -#include "cmdhfmfu.h" -#include "mifare/mifarehost.h" -#include "cliparser/cliparser.h" -#include "emv/apduinfo.h" -#include "emv/emvcore.h" -#include "taginfo.h" static int CmdHelp(const char *Cmd); -static int waitCmd(uint8_t iLen); - -// iso14a apdu input frame length -static uint16_t frameLength = 0; -uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; +static void waitCmd(uint8_t iLen); int CmdHF14AList(const char *Cmd) { - PrintAndLog("Deprecated command, use 'hf list 14a' instead"); + bool ShowWaitCycles = false; + char param = param_getchar(Cmd, 0); + + if (param == 'h' || (param != 0 && param != 'f')) { + PrintAndLog("List data in trace buffer."); + PrintAndLog("Usage: hf 14a list [f]"); + PrintAndLog("f - show frame delay times as well"); + PrintAndLog("sample: hf 14a list f"); + return 0; + } + + if (param == 'f') { + ShowWaitCycles = true; + } + + uint8_t got[1920]; + GetFromBigBuf(got,sizeof(got),0); + WaitForResponse(CMD_ACK,NULL); + + PrintAndLog("Recorded Activity"); + PrintAndLog(""); + PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); + PrintAndLog("All times are in carrier periods (1/13.56Mhz)"); + PrintAndLog(""); + PrintAndLog(" Start | End | Src | Data"); + PrintAndLog("-----------|-----------|-----|--------"); + + int i = 0; + uint32_t first_timestamp = 0; + uint32_t timestamp; + uint32_t EndOfTransmissionTimestamp = 0; + + for (;;) { + if(i >= 1900) { + break; + } + + bool isResponse; + timestamp = *((uint32_t *)(got+i)); + if (timestamp & 0x80000000) { + timestamp &= 0x7fffffff; + isResponse = true; + } else { + isResponse = false; + } + + if(i==0) { + first_timestamp = timestamp; + } + + int parityBits = *((uint32_t *)(got+i+4)); + + int len = got[i+8]; + + if (len > 100) { + break; + } + if (i + len >= 1900) { + break; + } + + uint8_t *frame = (got+i+9); + + // Break and stick with current result if buffer was not completely full + if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; + + char line[1000] = ""; + int j; + if (len) { + for (j = 0; j < len; j++) { + int oddparity = 0x01; + int k; + + for (k=0;k<8;k++) { + oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); + } + + //if((parityBits >> (len - j - 1)) & 0x01) { + if (isResponse && (oddparity != ((parityBits >> (len - j - 1)) & 0x01))) { + sprintf(line+(j*4), "%02x! ", frame[j]); + } else { + sprintf(line+(j*4), "%02x ", frame[j]); + } + } + } else { + if (ShowWaitCycles) { + uint32_t next_timestamp = (*((uint32_t *)(got+i+9))) & 0x7fffffff; + sprintf(line, "fdt (Frame Delay Time): %d", (next_timestamp - timestamp)); + } + } + + char *crc; + crc = ""; + if (len > 2) { + uint8_t b1, b2; + for (j = 0; j < (len - 1); j++) { + // gives problems... search for the reason.. + /*if(frame[j] == 0xAA) { + switch(frame[j+1]) { + case 0x01: + crc = "[1] Two drops close after each other"; + break; + case 0x02: + crc = "[2] Potential SOC with a drop in second half of bitperiod"; + break; + case 0x03: + crc = "[3] Segment Z after segment X is not possible"; + break; + case 0x04: + crc = "[4] Parity bit of a fully received byte was wrong"; + break; + default: + crc = "[?] Unknown error"; + break; + } + break; + }*/ + } + + if (strlen(crc)==0) { + ComputeCrc14443(CRC_14443_A, frame, len-2, &b1, &b2); + if (b1 != frame[len-2] || b2 != frame[len-1]) { + crc = (isResponse & (len < 6)) ? "" : " !crc"; + } else { + crc = ""; + } + } + } else { + crc = ""; // SHORT + } + + i += (len + 9); + + EndOfTransmissionTimestamp = (*((uint32_t *)(got+i))) & 0x7fffffff; + + if (!ShowWaitCycles) i += 9; + + PrintAndLog(" %9d | %9d | %s | %s %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (len?(isResponse ? "Tag" : "Rdr"):" "), + line, crc); + + } return 0; } -int Hf14443_4aGetCardData(iso14a_card_select_t *card) { +void iso14a_set_timeout(uint32_t timeout) { + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_SET_TIMEOUT, 0, timeout}}; + SendCommand(&c); +} + +int CmdHF14AReader(const char *Cmd) +{ UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_NACK, &resp); - - memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - - if (select_status == 0) { - PrintAndLog("E->iso14443a card select failed"); - return 1; - } - - if (select_status == 2) { - PrintAndLog("E->Card doesn't support iso14443-4 mode"); - return 1; - } - - if (select_status == 3) { - PrintAndLog("E->Card doesn't support standard iso14443-3 anticollision"); - PrintAndLog("\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); - return 1; - } - - PrintAndLog(" UID: %s", sprint_hex(card->uid, card->uidlen)); - PrintAndLog("ATQA: %02x %02x", card->atqa[1], card->atqa[0]); - PrintAndLog(" SAK: %02x [%" PRIu64 "]", card->sak, resp.arg[0]); - if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLog("E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); - return 1; - } - PrintAndLog(" ATS: %s", sprint_hex(card->ats, card->ats_len)); - - return 0; -} - -int CmdHF14AReader(const char *Cmd) { - uint32_t cm = ISO14A_CONNECT; - bool leaveSignalON = false; - - CLIParserInit("hf 14a reader", "Executes ISO1443A anticollision-select group of commands.", NULL); - void* argtable[] = { - arg_param_begin, - arg_lit0("kK", "keep", "keep the field active after command executed"), - arg_lit0("xX", "drop", "just drop the signal field"), - arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), - arg_param_end - }; - if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){ - CLIParserFree(); - return 0; - } - - leaveSignalON = arg_get_lit(1); - if (arg_get_lit(2)) { - cm = cm - ISO14A_CONNECT; - } - if (arg_get_lit(3)) { - cm |= ISO14A_NO_RATS; - } - - CLIParserFree(); - - if (leaveSignalON) - cm |= ISO14A_NO_DISCONNECT; - - UsbCommand c = {CMD_READER_ISO_14443a, {cm, 0, 0}}; - SendCommand(&c); - - if (ISO14A_CONNECT & cm) { - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - - if(select_status == 0) { - PrintAndLog("iso14443a card select failed"); - return 1; - } - - if(select_status == 3) { - PrintAndLog("Card doesn't support standard iso14443-3 anticollision"); - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - return 1; - } - - PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); - } - if (leaveSignalON) { - PrintAndLog("Card is selected. You can now start sending commands"); - } - } - - if (!leaveSignalON) { - PrintAndLog("Field dropped."); - } - - return 0; -} - - -int CmdHF14AInfo(const char *Cmd) { - - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; - SendCommand(&c); - - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_NACK, &resp, 500)) { - if (Cmd[0] != 's') PrintAndLog("Error: No response from Proxmark.\n"); - return 0; - } + WaitForResponse(CMD_ACK,&resp); - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + iso14a_card_select_t *card = (iso14a_card_select_t *)resp.d.asBytes; - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - - if (select_status == 0) { - if (Cmd[0] != 's') PrintAndLog("iso14443a card select failed"); - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); + if(resp.arg[0] == 0) { + PrintAndLog("iso14443a card select failed"); return 0; } - if(select_status == 3) { - PrintAndLog("Card doesn't support standard iso14443-3 anticollision"); - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - return 0; - } + PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]); + PrintAndLog(" UID : %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLog(" SAK : %02x [%d]", card->sak, resp.arg[0]); - PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); - - bool isMifareClassic = true; - switch (card.sak) { - case 0x00: - isMifareClassic = false; - - //***************************************test**************** - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - - uint32_t tagT = GetHF14AMfU_Type(); - ul_print_type(tagT, 0); - - //reconnect for further tests - c.arg[0] = ISO14A_CONNECT | ISO14A_NO_DISCONNECT; - c.arg[1] = 0; - c.arg[2] = 0; - - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_NACK,&resp); - - memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - - select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - - if (select_status == 0) { - //PrintAndLog("iso14443a card select failed"); - // disconnect - c.arg[0] = 0; - c.arg[1] = 0; - c.arg[2] = 0; - SendCommand(&c); - return 0; - } - - /* orig - // check if the tag answers to GETVERSION (0x60) - c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - c.arg[1] = 1; - c.arg[2] = 0; - c.d.asBytes[0] = 0x60; - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - - uint8_t version[10] = {0}; - memcpy(version, resp.d.asBytes, resp.arg[0] < sizeof(version) ? resp.arg[0] : sizeof(version)); - uint8_t len = resp.arg[0] & 0xff; - switch ( len ){ - // todo, identify "Magic UL-C tags". // they usually have a static nonce response to 0x1A command. - // UL-EV1, size, check version[6] == 0x0b (smaller) 0x0b * 4 == 48 - case 0x0A:PrintAndLog("TYPE : NXP MIFARE Ultralight EV1 %d bytes", (version[6] == 0xB) ? 48 : 128);break; - case 0x01:PrintAndLog("TYPE : NXP MIFARE Ultralight C");break; - case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break; - } - */ - break; - case 0x01: PrintAndLog("TYPE : NXP TNP3xxx Activision Game Appliance"); break; + switch (card->sak) { + case 0x00: PrintAndLog("TYPE : NXP MIFARE Ultralight | Ultralight C"); break; case 0x04: PrintAndLog("TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); break; + case 0x08: PrintAndLog("TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1"); break; case 0x09: PrintAndLog("TYPE : NXP MIFARE Mini 0.3k"); break; case 0x10: PrintAndLog("TYPE : NXP MIFARE Plus 2k SL2"); break; @@ -273,102 +217,67 @@ int CmdHF14AInfo(const char *Cmd) { case 0x98: PrintAndLog("TYPE : Gemplus MPCOS"); break; default: ; } - - // Double & triple sized UID, can be mapped to a manufacturer. - // HACK: does this apply for Ultralight cards? - if (card.uidlen > 4) { - PrintAndLog("MANUFACTURER : %s", getManufacturerName(card.uid[0])); - } - - // try to request ATS even if tag claims not to support it - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT; - c.arg[1] = 2; - c.arg[2] = 0; - memcpy(c.d.asBytes, rats, 2); - SendCommand(&c); - WaitForResponse(CMD_ACK,&resp); - - memcpy(card.ats, resp.d.asBytes, resp.arg[0]); - card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes - } - - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + if(resp.arg[0] == 1) { bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; - if (select_status == 2) { - PrintAndLog("SAK incorrectly claims that card doesn't support RATS"); + PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len)); + if (card->ats_len > 0) { + PrintAndLog(" - TL : length is %d bytes", card->ats[0]); } - PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLog(" - TL : length is %d bytes", card.ats[0]); - if (card.ats[0] != card.ats_len - 2) { - PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); - } - - if (card.ats[0] > 1) { // there is a format byte (T0) - ta1 = (card.ats[1] & 0x10) == 0x10; - tb1 = (card.ats[1] & 0x20) == 0x20; - tc1 = (card.ats[1] & 0x40) == 0x40; - int16_t fsci = card.ats[1] & 0x0f; + if (card->ats_len > 1) { + ta1 = (card->ats[1] & 0x10) == 0x10; + tb1 = (card->ats[1] & 0x20) == 0x20; + tc1 = (card->ats[1] & 0x40) == 0x40; PrintAndLog(" - T0 : TA1 is%s present, TB1 is%s present, " - "TC1 is%s present, FSCI is %d (FSC = %ld)", + "TC1 is%s present, FSCI is %d", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), - fsci, - fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1 - ); + (card->ats[1] & 0x0f)); } pos = 2; - if (ta1) { + if (ta1 && card->ats_len > pos) { char dr[16], ds[16]; dr[0] = ds[0] = '\0'; - if (card.ats[pos] & 0x10) strcat(ds, "2, "); - if (card.ats[pos] & 0x20) strcat(ds, "4, "); - if (card.ats[pos] & 0x40) strcat(ds, "8, "); - if (card.ats[pos] & 0x01) strcat(dr, "2, "); - if (card.ats[pos] & 0x02) strcat(dr, "4, "); - if (card.ats[pos] & 0x04) strcat(dr, "8, "); + if (card->ats[pos] & 0x10) strcat(ds, "2, "); + if (card->ats[pos] & 0x20) strcat(ds, "4, "); + if (card->ats[pos] & 0x40) strcat(ds, "8, "); + if (card->ats[pos] & 0x01) strcat(dr, "2, "); + if (card->ats[pos] & 0x02) strcat(dr, "4, "); + if (card->ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; PrintAndLog(" - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", - (card.ats[pos] & 0x80 ? " NOT" : ""), dr, ds); + (card->ats[pos] & 0x80 ? " NOT" : ""), dr, ds); pos++; } - if (tb1) { - uint32_t sfgi = card.ats[pos] & 0x0F; - uint32_t fwi = card.ats[pos] >> 4; - PrintAndLog(" - TB1 : SFGI = %d (SFGT = %s%ld/fc), FWI = %d (FWT = %ld/fc)", - (sfgi), - sfgi ? "" : "(not needed) ", - sfgi ? (1 << 12) << sfgi : 0, - fwi, - (1 << 12) << fwi - ); + if (tb1 && card->ats_len > pos) { + PrintAndLog(" - TB1 : SFGI = %d, FWI = %d", + (card->ats[pos] & 0x08), + (card->ats[pos] & 0x80) >> 4); pos++; } - if (tc1) { + if (tc1 && card->ats_len > pos) { PrintAndLog(" - TC1 : NAD is%s supported, CID is%s supported", - (card.ats[pos] & 0x01) ? "" : " NOT", - (card.ats[pos] & 0x02) ? "" : " NOT"); + (card->ats[pos] & 0x01) ? "" : " NOT", + (card->ats[pos] & 0x02) ? "" : " NOT"); pos++; } - if (card.ats[0] > pos) { + if (card->ats_len > pos) { char *tip = ""; - if (card.ats[0] - pos >= 7) { - if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + if (card->ats_len - pos > 7) { + if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + } else if (memcmp(card->ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { tip = "-> MIFARE Plus S 2K or 4K"; } - } - PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); - if (card.ats[pos] == 0xC1) { + } + PrintAndLog(" - HB : %s%s", sprint_hex(card->ats + pos, card->ats_len - pos - 2), tip); + if (card->ats[pos] == 0xC1) { PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLog(" %02x -> Length is %d bytes", - card.ats[pos + 1], card.ats[pos + 1]); - switch (card.ats[pos + 2] & 0xf0) { + card->ats[pos + 1], card->ats[pos + 1]); + switch (card->ats[pos + 2] & 0xf0) { case 0x10: PrintAndLog(" 1x -> MIFARE DESFire"); break; @@ -376,24 +285,24 @@ int CmdHF14AInfo(const char *Cmd) { PrintAndLog(" 2x -> MIFARE Plus"); break; } - switch (card.ats[pos + 2] & 0x0f) { + switch (card->ats[pos + 2] & 0x0f) { case 0x00: PrintAndLog(" x0 -> <1 kByte"); break; case 0x01: - PrintAndLog(" x1 -> 1 kByte"); + PrintAndLog(" x0 -> 1 kByte"); break; case 0x02: - PrintAndLog(" x2 -> 2 kByte"); + PrintAndLog(" x0 -> 2 kByte"); break; case 0x03: - PrintAndLog(" x3 -> 4 kByte"); + PrintAndLog(" x0 -> 4 kByte"); break; case 0x04: - PrintAndLog(" x4 -> 8 kByte"); + PrintAndLog(" x0 -> 8 kByte"); break; } - switch (card.ats[pos + 3] & 0xf0) { + switch (card->ats[pos + 3] & 0xf0) { case 0x00: PrintAndLog(" 0x -> Engineering sample"); break; @@ -401,7 +310,7 @@ int CmdHF14AInfo(const char *Cmd) { PrintAndLog(" 2x -> Released"); break; } - switch (card.ats[pos + 3] & 0x0f) { + switch (card->ats[pos + 3] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Generation 1"); break; @@ -412,7 +321,7 @@ int CmdHF14AInfo(const char *Cmd) { PrintAndLog(" x2 -> Generation 3"); break; } - switch (card.ats[pos + 4] & 0x0f) { + switch (card->ats[pos + 4] & 0x0f) { case 0x00: PrintAndLog(" x0 -> Only VCSL supported"); break; @@ -426,27 +335,10 @@ int CmdHF14AInfo(const char *Cmd) { } } } else { - PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); - } + PrintAndLog("proprietary non iso14443a-4 card found, RATS not supported"); + } - - // try to see if card responses to "chinese magic backdoor" commands. - (void)mfCIdentify(); - - if (isMifareClassic) { - switch (DetectClassicPrng()) { - case 0: - PrintAndLog("Prng detection: HARDENED (hardnested)"); - break; - case 1: - PrintAndLog("Prng detection: WEAK"); - break; - default: - PrintAndLog("Prng detection error."); - } - } - - return select_status; + return resp.arg[0]; } // Collect ISO14443 Type A UIDs @@ -458,30 +350,33 @@ int CmdHF14ACUIDs(const char *Cmd) n = n > 0 ? n : 1; PrintAndLog("Collecting %d UIDs", n); - PrintAndLog("Start: %" PRIu64, msclock()/1000); + PrintAndLog("Start: %u", time(NULL)); // repeat n times for (int i = 0; i < n; i++) { // execute anticollision procedure - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); - UsbCommand resp; - WaitForResponse(CMD_NACK,&resp); - - iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; + uint8_t *uid = resp.d.asBytes; + iso14a_card_select_t *card = (iso14a_card_select_t *)(uid + 12); // check if command failed if (resp.arg[0] == 0) { PrintAndLog("Card select failed."); } else { - char uid_string[20]; - for (uint16_t i = 0; i < card->uidlen; i++) { - sprintf(&uid_string[2*i], "%02X", card->uid[i]); + // check if UID is 4 bytes + if ((card->atqa[1] & 0xC0) == 0) { + PrintAndLog("%02X%02X%02X%02X", + *uid, *(uid + 1), *(uid + 2), *(uid + 3)); + } else { + PrintAndLog("UID longer than 4 bytes"); } - PrintAndLog("%s", uid_string); } } - PrintAndLog("End: %" PRIu64, msclock()/1000); + PrintAndLog("End: %u", time(NULL)); return 1; } @@ -491,10 +386,10 @@ int CmdHF14ACUIDs(const char *Cmd) int CmdHF14ASim(const char *Cmd) { UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,{0,0,0}}; - + // Retrieve the tag type uint8_t tagtype = param_get8ex(Cmd,0,0,10); - + // When no argument was given, just print help message if (tagtype == 0) { PrintAndLog(""); @@ -503,22 +398,21 @@ int CmdHF14ASim(const char *Cmd) PrintAndLog(" syntax: hf 14a sim "); PrintAndLog(" types: 1 = MIFARE Classic"); PrintAndLog(" 2 = MIFARE Ultralight"); - PrintAndLog(" 3 = MIFARE Desfire"); + PrintAndLog(" 3 = MIFARE DESFIRE"); PrintAndLog(" 4 = ISO/IEC 14443-4"); - PrintAndLog(" 5 = MIFARE Tnp3xxx"); PrintAndLog(""); return 1; } - + // Store the tag type c.arg[0] = tagtype; - - // Retrieve the full 4 or 7 byte long uid + + // Retrieve the full 4 or 7 byte long uid uint64_t long_uid = param_get64ex(Cmd,1,0,16); // Are we handling the (optional) second part uid? if (long_uid > 0xffffffff) { - PrintAndLog("Emulating ISO/IEC 14443 type A tag with 7 byte UID (%014" PRIx64 ")",long_uid); + PrintAndLog("Emulating ISO/IEC 14443 type A tag with 7 byte UID (%014"llx")",long_uid); // Store the second part c.arg[2] = (long_uid & 0xffffffff); long_uid >>= 32; @@ -533,10 +427,14 @@ int CmdHF14ASim(const char *Cmd) // At lease save the mandatory first part of the UID c.arg[0] = long_uid & 0xffffffff; + + // At lease save the mandatory first part of the UID + c.arg[0] = long_uid & 0xffffffff; + if (c.arg[1] == 0) { PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]); } - + switch (c.arg[0]) { case 1: { PrintAndLog("Emulating ISO/IEC 14443-3 type A tag with 4 byte UID"); @@ -552,676 +450,204 @@ int CmdHF14ASim(const char *Cmd) return 1; } break; - } + } */ /* unsigned int hi = 0, lo = 0; int n = 0, i = 0; while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { - hi= (hi << 4) | (lo >> 28); - lo= (lo << 4) | (n & 0xf); + hi= (hi << 4) | (lo >> 28); + lo= (lo << 4) | (n & 0xf); } */ -// UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)}; +// UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)}; // PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]); SendCommand(&c); return 0; } - int CmdHF14ASnoop(const char *Cmd) { int param = 0; - - uint8_t ctmp = param_getchar(Cmd, 0) ; - if (ctmp == 'h' || ctmp == 'H') { + + if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It get data from the field and saves it into command buffer."); - PrintAndLog("Buffer accessible from command hf list 14a."); + PrintAndLog("Buffer accessible from command hf 14a list."); PrintAndLog("Usage: hf 14a snoop [c][r]"); PrintAndLog("c - triggered by first data from card"); PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)"); PrintAndLog("sample: hf 14a snoop c r"); return 0; - } - + } + for (int i = 0; i < 2; i++) { - ctmp = param_getchar(Cmd, i); + char ctmp = param_getchar(Cmd, i); if (ctmp == 'c' || ctmp == 'C') param |= 0x01; if (ctmp == 'r' || ctmp == 'R') param |= 0x02; } - UsbCommand c = {CMD_SNOOP_ISO_14443a, {param, 0, 0}}; - SendCommand(&c); - return 0; -} - - -void DropField() { - UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; - SendCommand(&c); -} - - -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - static bool responseNum = false; - uint16_t cmdc = 0; - *dataoutlen = 0; - - if (activateField) { - responseNum = false; - UsbCommand resp; - - // Anticollision + SELECT card - UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_CLEAR_TRACE, 0, 0}}; - SendCommand(&ca); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLog("14aRAW ERROR: Proxmark connection timeout."); - return 1; - } - - // check result - if (resp.arg[0] == 0) { - PrintAndLog("14aRAW ERROR: No card in field."); - return 1; - } - - if (resp.arg[0] != 1 && resp.arg[0] != 2) { - PrintAndLog("14aRAW ERROR: card not in iso14443-4. res=%d.", resp.arg[0]); - return 1; - } - - if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - // get ATS - UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - memcpy(cr.d.asBytes, rats, 2); - SendCommand(&cr); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLog("14aRAW ERROR: Proxmark connection timeout."); - return 1; - } - - if (resp.arg[0] <= 0) { // ats_len - PrintAndLog("14aRAW ERROR: Can't get ATS."); - return 1; - } - } - } - - if (leaveSignalON) - cmdc |= ISO14A_NO_DISCONNECT; - - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}}; - uint8_t header[] = {0x0a | responseNum, 0x00}; - responseNum ^= 1; - memcpy(c.d.asBytes, header, 2); - memcpy(&c.d.asBytes[2], datain, datainlen); - SendCommand(&c); - - uint8_t *recv; - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - recv = resp.d.asBytes; - int iLen = resp.arg[0]; - - if(!iLen) { - PrintAndLog("14aRAW ERROR: No card response."); - return 1; - } - - *dataoutlen = iLen - 2; - if (*dataoutlen < 0) - *dataoutlen = 0; - - if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); - return 2; - } - - if (recv[0] != header[0]) { - PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]); - return 2; - } - - memcpy(dataout, &recv[2], *dataoutlen); - - // CRC Check - if (iLen == -1) { - PrintAndLog("14aRAW ERROR: ISO 14443A CRC error."); - return 3; - } - - - } else { - PrintAndLog("14aRAW ERROR: Reply timeout."); - return 4; - } - - return 0; -} - - -static int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { - UsbCommand resp; - - frameLength = 0; - - if (card) - memset(card, 0, sizeof(iso14a_card_select_t)); - - DropField(); - - // Anticollision + SELECT card - UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; - SendCommand(&ca); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark connection timeout."); - return 1; - } - - // check result - if (resp.arg[0] == 0) { - PrintAndLogEx(ERR, "No card in field."); - return 1; - } - - if (resp.arg[0] != 1 && resp.arg[0] != 2) { - PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.arg[0]); - return 1; - } - - if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - // try to get ATS although SAK indicated that it is not ISO14443-4 compliant - UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - memcpy(cr.d.asBytes, rats, 2); - SendCommand(&cr); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark connection timeout."); - return 1; - } - - if (resp.arg[0] <= 0) { // ats_len - PrintAndLogEx(ERR, "Can't get ATS."); - return 1; - } - } - - // get frame length from ATS - iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.d.asBytes; - if (vcard->ats_len > 1) { - uint8_t fsci = vcard->ats[1] & 0x0f; - if (fsci < sizeof(atsFSC)) - frameLength = atsFSC[fsci]; - } - - if (card) { - memcpy(card, vcard, sizeof(iso14a_card_select_t)); - } - - if (disconnect) { - DropField(); - } - - return 0; -} - - -static int ExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) -{ - *chainingout = false; - - if (activateField) { - // select with no disconnect and set frameLength - int selres = SelectCard14443_4(false, NULL); - if (selres) - return selres; - } - - uint16_t cmdc = 0; - if (chainingin) - cmdc = ISO14A_SEND_CHAINING; - - // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes - // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size - // here length USB_CMD_DATA_SIZE=512 - // timeout must be authomatically set by "get ATS" - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}}; - memcpy(c.d.asBytes, datain, datainlen); - SendCommand(&c); - - uint8_t *recv; - UsbCommand resp; - - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - recv = resp.d.asBytes; - int iLen = resp.arg[0]; - uint8_t res = resp.arg[1]; - - int dlen = iLen - 2; - if (dlen < 0) - dlen = 0; - *dataoutlen += dlen; - - if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); - return 2; - } - - // I-block ACK - if ((res & 0xf2) == 0xa2) { - *dataoutlen = 0; - *chainingout = true; - return 0; - } - - if(!iLen) { - PrintAndLog("APDU ERROR: No APDU response."); - return 1; - } - - // check apdu length - if (iLen < 2 && iLen >= 0) { - PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen); - return 2; - } - - // check block TODO - if (iLen == -2) { - PrintAndLog("APDU ERROR: Block type mismatch."); - return 2; - } - - memcpy(dataout, recv, dlen); - - // chaining - if ((res & 0x10) != 0) { - *chainingout = true; - } - - // CRC Check - if (iLen == -1) { - PrintAndLog("APDU ERROR: ISO 14443A CRC error."); - return 3; - } - } else { - PrintAndLog("APDU ERROR: Reply timeout."); - return 4; - } - - return 0; -} - - -int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - *dataoutlen = 0; - bool chaining = false; - int res; - - // 3 byte here - 1b framing header, 2b crc16 - if ( (frameLength && (datainlen > frameLength - 3)) || (datainlen > USB_CMD_DATA_SIZE - 3) ) { - int clen = 0; - - bool vActivateField = activateField; - - do { - int vlen = MIN(frameLength - 3, datainlen - clen); - bool chainBlockNotLast = ((clen + vlen) < datainlen); - - *dataoutlen = 0; - res = ExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining); - if (res) { - if (!leaveSignalON) - DropField(); - - return 200; - } - - // check R-block ACK - if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { - if (!leaveSignalON) - DropField(); - - return 201; - } - - clen += vlen; - vActivateField = false; - if (*dataoutlen) { - if (clen != datainlen) - PrintAndLogEx(WARNING, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen); - break; - } - } while (clen < datainlen); - } else { - res = ExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); - if (res) { - if (!leaveSignalON) - DropField(); - - return res; - } - } - - while (chaining) { - // I-block with chaining - res = ExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); - - if (res) { - if (!leaveSignalON) - DropField(); - - return 100; - } - } - - if (!leaveSignalON) - DropField(); - - return 0; -} - -// ISO14443-4. 7. Half-duplex block transmission protocol -int CmdHF14AAPDU(const char *cmd) { - uint8_t data[USB_CMD_DATA_SIZE]; - int datalen = 0; - uint8_t header[5]; - int headerlen = 0; - bool activateField = false; - bool leaveSignalON = false; - bool decodeTLV = false; - bool decodeAPDU = false; - bool makeAPDU = false; - bool extendedAPDU = false; - int le = 0; - int res = 0; - - CLIParserInit("hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013", - "Examples:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" - "\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode APDU\n" - "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard APDU\n" - "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended APDU\n"); - - void* argtable[] = { - arg_param_begin, - arg_lit0("sS", "select", "activate field and select card"), - arg_lit0("kK", "keep", "leave the signal field ON after receive response"), - arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), - arg_lit0("dD", "decapdu", "decode APDU request if it possible"), - arg_str0("mM", "make", "", "make APDU with head from this field and data from data field. Must be 4 bytes length: "), - arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"), - arg_int0("lL", "le", "", "Le APDU parameter (requires `-m`)"), - arg_strx1(NULL, NULL, "", "APDU (without `-m`), or data (with `-m`)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, false); - - activateField = arg_get_lit(1); - leaveSignalON = arg_get_lit(2); - decodeTLV = arg_get_lit(3); - decodeAPDU = arg_get_lit(4); - - res = CLIParamHexToBuf(arg_get_str(5), header, sizeof(header), &headerlen); - makeAPDU = headerlen > 0; - if (res || (makeAPDU && headerlen != 4)) { - PrintAndLogEx(ERR, "header length must be exactly 4 bytes"); - CLIParserFree(); - return 1; - } - extendedAPDU = arg_get_lit(6); - le = arg_get_int_def(7, 0); - - if (makeAPDU) { - uint8_t apdudata[USB_CMD_DATA_SIZE] = {0}; - int apdudatalen = 0; - - CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2); - - APDUStruct apdu; - apdu.cla = header[0]; - apdu.ins = header[1]; - apdu.p1 = header[2]; - apdu.p2 = header[3]; - - apdu.lc = apdudatalen; - apdu.data = apdudata; - - apdu.extended_apdu = extendedAPDU; - apdu.le = le; - - if (APDUEncode(&apdu, data, &datalen)) { - PrintAndLogEx(ERR, "can't make apdu with provided parameters."); - CLIParserFree(); - return 2; - } - } else { - if (extendedAPDU) { - PrintAndLogEx(ERR, "`-e` without `-m`."); - CLIParserFree(); - return 3; - } - if (le > 0) { - PrintAndLogEx(ERR, "`-l` without `-m`."); - CLIParserFree(); - return 3; - } - - // len = data + PCB(1b) + CRC(2b) - CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2); - } - - CLIParserFree(); -// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); - PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - - if (decodeAPDU) { - APDUStruct apdu; - - if (APDUDecode(data, datalen, &apdu) == 0) - APDUPrint(apdu); - else - PrintAndLogEx(WARNING, "can't decode APDU."); - } - - res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); - - if (res) - return res; - - PrintAndLog("<<<< %s", sprint_hex(data, datalen)); - - PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); - - // TLV decoder - if (decodeTLV && datalen > 4) { - TLVPrintFromBuffer(data, datalen - 2); - } - - return 0; + UsbCommand c = {CMD_SNOOP_ISO_14443a, {param, 0, 0}}; + SendCommand(&c); + return 0; } int CmdHF14ACmdRaw(const char *cmd) { - UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; - bool reply=1; - bool crc = false; - bool power = false; - bool active = false; - bool active_select = false; - bool no_rats = false; - uint16_t numbits = 0; - bool bTimeout = false; - uint32_t timeout = 0; - bool topazmode = false; - uint8_t data[USB_CMD_DATA_SIZE]; - int datalen = 0; + UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + uint8_t reply=1; + uint8_t crc=0; + uint8_t power=0; + uint8_t active=0; + uint8_t active_select=0; + uint16_t numbits=0; + char buf[5]=""; + int i=0; + uint8_t data[100]; + unsigned int datalen=0, temp; - // extract parameters - CLIParserInit("hf 14a raw", "Send raw hex data to tag", - "Sample:\n"\ - "\thf 14a raw -pa -b7 -t1000 52 -- execute WUPA\n"\ - "\thf 14a raw -p 9320 -- anticollision\n"\ - "\thf 14a raw -psc 60 00 -- select and mifare AUTH\n"); - void* argtable[] = { - arg_param_begin, - arg_lit0("rR", "nreply", "do not read response"), - arg_lit0("cC", "crc", "calculate and append CRC"), - arg_lit0("pP", "power", "leave the signal field ON after receive"), - arg_lit0("aA", "active", "active signal field ON without select"), - arg_lit0("sS", "actives", "active signal field ON with select"), - arg_int0("bB", "bits", NULL, "number of bits to send. Useful for send partial byte"), - arg_int0("t", "timeout", NULL, "timeout in ms"), - arg_lit0("T", "topaz", "use Topaz protocol to send command"), - arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"), - arg_strx1(NULL, NULL, "", NULL), - arg_param_end - }; - // defaults - arg_get_int(6) = 0; - arg_get_int(7) = 0; + if (strlen(cmd)<2) { + PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] <0A 0B 0C ... hex>"); + PrintAndLog(" -r do not read response"); + PrintAndLog(" -c calculate and append CRC"); + PrintAndLog(" -p leave the signal field ON after receive"); + PrintAndLog(" -a active signal field ON without select"); + PrintAndLog(" -s active signal field ON with select"); + PrintAndLog(" -b number of bits to send. Useful for send partial byte"); + return 0; + } - if (CLIParserParseString(cmd, argtable, arg_getsize(argtable), false)){ - CLIParserFree(); - return 0; - } + // strip + while (*cmd==' ' || *cmd=='\t') cmd++; - reply = !arg_get_lit(1); - crc = arg_get_lit(2); - power = arg_get_lit(3); - active = arg_get_lit(4); - active_select = arg_get_lit(5); - numbits = arg_get_int(6) & 0xFFFF; - timeout = arg_get_int(7); - bTimeout = (timeout > 0); - topazmode = arg_get_lit(8); - no_rats = arg_get_lit(9); - // len = data + CRC(2b) - if (CLIParamHexToBuf(arg_get_str(10), data, sizeof(data) -2, &datalen)) { - CLIParserFree(); - return 1; - } + while (cmd[i]!='\0') { + if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; } + if (cmd[i]=='-') { + switch (cmd[i+1]) { + case 'r': + reply=0; + break; + case 'c': + crc=1; + break; + case 'p': + power=1; + break; + case 'a': + active=1; + break; + case 's': + active_select=1; + break; + case 'b': + sscanf(cmd+i+2,"%d",&temp); + numbits = temp & 0xFFFF; + i+=3; + while(cmd[i]!=' ' && cmd[i]!='\0') { i++; } + i-=2; + break; + default: + PrintAndLog("Invalid option"); + return 0; + } + i+=2; + continue; + } + if ((cmd[i]>='0' && cmd[i]<='9') || + (cmd[i]>='a' && cmd[i]<='f') || + (cmd[i]>='A' && cmd[i]<='F') ) { + buf[strlen(buf)+1]=0; + buf[strlen(buf)]=cmd[i]; + i++; - CLIParserFree(); + if (strlen(buf)>=2) { + sscanf(buf,"%x",&temp); + data[datalen]=(uint8_t)(temp & 0xff); + datalen++; + *buf=0; + } + continue; + } + PrintAndLog("Invalid char on input"); + return 0; + } + if(crc && datalen>0) + { + uint8_t first, second; + ComputeCrc14443(CRC_14443_A, data, datalen, &first, &second); + data[datalen++] = first; + data[datalen++] = second; + } - // logic - if(crc && datalen>0 && datalen0) + c.arg[0] |= ISO14A_RAW; - if(active || active_select) - { - c.arg[0] |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE; - if(active) - c.arg[0] |= ISO14A_NO_SELECT; - } + c.arg[1] = datalen; + c.arg[2] = numbits; + memcpy(c.d.asBytes,data,datalen); - if(bTimeout){ - #define MAX_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s - c.arg[0] |= ISO14A_SET_TIMEOUT; - if(timeout > MAX_TIMEOUT) { - timeout = MAX_TIMEOUT; - PrintAndLog("Set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); - } - c.arg[2] = 13560000 / 1000 / (8*16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) - } + SendCommand(&c); - if(power) { - c.arg[0] |= ISO14A_NO_DISCONNECT; - } - - if(datalen > 0) { - c.arg[0] |= ISO14A_RAW; - } - - if(topazmode) { - c.arg[0] |= ISO14A_TOPAZMODE; - } - - if(no_rats) { - c.arg[0] |= ISO14A_NO_RATS; - } - - // Max buffer is USB_CMD_DATA_SIZE (512) - c.arg[1] = (datalen & 0xFFFF) | ((uint32_t)numbits << 16); - memcpy(c.d.asBytes,data,datalen); - - SendCommand(&c); - - if (reply) { - int res = 0; - if (active_select) - res = waitCmd(1); - if (!res && datalen > 0) - waitCmd(0); - } // if reply - return 0; + if (reply) { + if(active_select) + waitCmd(1); + if(datalen>0) + waitCmd(0); + } // if reply + return 0; } - -static int waitCmd(uint8_t iSelect) { - uint8_t *recv; - UsbCommand resp; - char *hexout; - - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - recv = resp.d.asBytes; - uint8_t iLen = resp.arg[0]; - if (iSelect){ - iLen = resp.arg[1]; - if (iLen){ - PrintAndLog("Card selected. UID[%i]:", iLen); - } else { - PrintAndLog("Can't select card."); - } - } else { - PrintAndLog("received %i bytes:", iLen); - } - if(!iLen) - return 1; - hexout = (char *)malloc(iLen * 3 + 1); - if (hexout != NULL) { - for (int i = 0; i < iLen; i++) { // data in hex - sprintf(&hexout[i * 3], "%02X ", recv[i]); - } - PrintAndLog("%s", hexout); - free(hexout); - } else { - PrintAndLog("malloc failed your client has low memory?"); - return 2; - } - } else { - PrintAndLog("timeout while waiting for reply."); - return 3; - } - return 0; -} - -static command_t CommandTable[] = +static void waitCmd(uint8_t iSelect) { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, - {"reader", CmdHF14AReader, 0, "Start acting like an ISO14443 Type A reader"}, - {"info", CmdHF14AInfo, 0, "Reads card and shows information about it"}, - {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, - {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, - {"apdu", CmdHF14AAPDU, 0, "Send an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol"}, - {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, - {NULL, NULL, 0, NULL} + uint8_t *recv; + UsbCommand resp; + char *hexout; + + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + recv = resp.d.asBytes; + uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0]; + PrintAndLog("received %i octets",iLen); + if(!iLen) + return; + hexout = (char *)malloc(iLen * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < iLen; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); + } else { + PrintAndLog("malloc failed your client has low memory?"); + } + } else { + PrintAndLog("timeout while waiting for reply."); + } +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"list", CmdHF14AList, 0, "List ISO 14443a history"}, + {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, + {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, + {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, + {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, + {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, + {NULL, NULL, 0, NULL} }; int CmdHF14A(const char *Cmd) { - (void)WaitForResponseTimeout(CMD_ACK,NULL,100); - CmdsParse(CommandTable, Cmd); - return 0; + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + + // parse + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index d1669f3a..56329bed 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -12,23 +12,12 @@ #ifndef CMDHF14A_H__ #define CMDHF14A_H__ -#include -#include -#include "mifare.h" +int CmdHF14A(const char *Cmd); -extern int CmdHF14A(const char *Cmd); -extern int CmdHF14AMfDbg(const char* cmd); -extern int CmdHF14AList(const char *Cmd); -extern int CmdHF14AMifare(const char *Cmd); -extern int CmdHF14AReader(const char *Cmd); -extern int CmdHF14AInfo(const char *Cmd); -extern int CmdHF14ASim(const char *Cmd); -extern int CmdHF14ASnoop(const char *Cmd); - -extern void DropField(); - -extern int Hf14443_4aGetCardData(iso14a_card_select_t * card); -extern int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int CmdHF14AList(const char *Cmd); +int CmdHF14AMifare(const char *Cmd); +int CmdHF14AReader(const char *Cmd); +int CmdHF14ASim(const char *Cmd); +int CmdHF14ASnoop(const char *Cmd); #endif diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 2ad35251..c42d54c5 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -8,742 +8,396 @@ // High frequency ISO14443B commands //----------------------------------------------------------------------------- -#include "cmdhf14b.h" - #include #include #include #include #include -#include #include "iso14443crc.h" -#include "comms.h" +//#include "proxusb.h" +#include "proxmark3.h" +#include "data.h" #include "graph.h" -#include "util.h" #include "ui.h" #include "cmdparser.h" +#include "cmdhf14b.h" #include "cmdmain.h" -#include "taginfo.h" +static int CmdHelp(const char *Cmd); -int CmdHF14BList(const char *Cmd) { - PrintAndLog("Deprecated command, use 'hf list 14b' instead"); - return 0; +int CmdHF14BDemod(const char *Cmd) +{ + int i, j, iold; + int isum, qsum; + int outOfWeakAt; + bool negateI, negateQ; + + uint8_t data[256]; + int dataLen = 0; + + // As received, the samples are pairs, correlations against I and Q + // square waves. So estimate angle of initial carrier (or just + // quadrant, actually), and then do the demod. + + // First, estimate where the tag starts modulating. + for (i = 0; i < GraphTraceLen; i += 2) { + if (abs(GraphBuffer[i]) + abs(GraphBuffer[i + 1]) > 40) { + break; + } + } + if (i >= GraphTraceLen) { + PrintAndLog("too weak to sync"); + return 0; + } + PrintAndLog("out of weak at %d", i); + outOfWeakAt = i; + + // Now, estimate the phase in the initial modulation of the tag + isum = 0; + qsum = 0; + for (; i < (outOfWeakAt + 16); i += 2) { + isum += GraphBuffer[i + 0]; + qsum += GraphBuffer[i + 1]; + } + negateI = (isum < 0); + negateQ = (qsum < 0); + + // Turn the correlation pairs into soft decisions on the bit. + j = 0; + for (i = 0; i < GraphTraceLen / 2; i++) { + int si = GraphBuffer[j]; + int sq = GraphBuffer[j + 1]; + if (negateI) si = -si; + if (negateQ) sq = -sq; + GraphBuffer[i] = si + sq; + j += 2; + } + GraphTraceLen = i; + + i = outOfWeakAt / 2; + while (GraphBuffer[i] > 0 && i < GraphTraceLen) + i++; + if (i >= GraphTraceLen) goto demodError; + + iold = i; + while (GraphBuffer[i] < 0 && i < GraphTraceLen) + i++; + if (i >= GraphTraceLen) goto demodError; + if ((i - iold) > 23) goto demodError; + + PrintAndLog("make it to demod loop"); + + for (;;) { + iold = i; + while (GraphBuffer[i] >= 0 && i < GraphTraceLen) + i++; + if (i >= GraphTraceLen) goto demodError; + if ((i - iold) > 6) goto demodError; + + uint16_t shiftReg = 0; + if (i + 20 >= GraphTraceLen) goto demodError; + + for (j = 0; j < 10; j++) { + int soft = GraphBuffer[i] + GraphBuffer[i + 1]; + + if (abs(soft) < (abs(isum) + abs(qsum)) / 20) { + PrintAndLog("weak bit"); + } + + shiftReg >>= 1; + if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) { + shiftReg |= 0x200; + } + + i+= 2; + } + + if ((shiftReg & 0x200) && !(shiftReg & 0x001)) + { + // valid data byte, start and stop bits okay + PrintAndLog(" %02x", (shiftReg >> 1) & 0xff); + data[dataLen++] = (shiftReg >> 1) & 0xff; + if (dataLen >= sizeof(data)) { + return 0; + } + } else if (shiftReg == 0x000) { + // this is EOF + break; + } else { + goto demodError; + } + } + + uint8_t first, second; + ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second); + PrintAndLog("CRC: %02x %02x (%s)\n", first, second, + (first == data[dataLen-2] && second == data[dataLen-1]) ? + "ok" : "****FAIL****"); + + RepaintGraphWindow(); + return 0; + +demodError: + PrintAndLog("demod error"); + RepaintGraphWindow(); + return 0; } +int CmdHF14BList(const char *Cmd) +{ + uint8_t got[960]; + GetFromBigBuf(got,sizeof(got),0); + WaitForResponse(CMD_ACK,NULL); -int CmdHF14BSim(const char *Cmd) { - UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B}; - clearCommandBuffer(); + PrintAndLog("recorded activity:"); + PrintAndLog(" time :rssi: who bytes"); + PrintAndLog("---------+----+----+-----------"); + + int i = 0; + int prev = -1; + + for(;;) { + if(i >= 900) { + break; + } + + bool isResponse; + int timestamp = *((uint32_t *)(got+i)); + if(timestamp & 0x80000000) { + timestamp &= 0x7fffffff; + isResponse = 1; + } else { + isResponse = 0; + } + int metric = *((uint32_t *)(got+i+4)); + + int len = got[i+8]; + + if(len > 100) { + break; + } + if(i + len >= 900) { + break; + } + + uint8_t *frame = (got+i+9); + + // Break and stick with current result if buffer was not completely full + if (frame[0] == 0x44 && frame[1] == 0x44 && frame[2] == 0x44 && frame[3] == 0x44) break; + + char line[1000] = ""; + int j; + for(j = 0; j < len; j++) { + sprintf(line+(j*3), "%02x ", frame[j]); + } + + char *crc; + if(len > 2) { + uint8_t b1, b2; + ComputeCrc14443(CRC_14443_B, frame, len-2, &b1, &b2); + if(b1 != frame[len-2] || b2 != frame[len-1]) { + crc = "**FAIL CRC**"; + } else { + crc = ""; + } + } else { + crc = "(SHORT)"; + } + + char metricString[100]; + if(isResponse) { + sprintf(metricString, "%3d", metric); + } else { + strcpy(metricString, " "); + } + + PrintAndLog(" +%7d: %s: %s %s %s", + (prev < 0 ? 0 : timestamp - prev), + metricString, + (isResponse ? "TAG" : " "), line, crc); + + prev = timestamp; + i += (len + 9); + } + return 0; +} + +int CmdHF14BRead(const char *Cmd) +{ + UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}}; SendCommand(&c); return 0; } - -int CmdHF14BSnoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_ISO_14443B}; - clearCommandBuffer(); +int CmdHF14Sim(const char *Cmd) +{ + UsbCommand c={CMD_SIMULATE_TAG_ISO_14443}; SendCommand(&c); return 0; } +int CmdHFSimlisten(const char *Cmd) +{ + UsbCommand c = {CMD_SIMULATE_TAG_HF_LISTEN}; + SendCommand(&c); + return 0; +} + +int CmdHF14BSnoop(const char *Cmd) +{ + UsbCommand c = {CMD_SNOOP_ISO_14443}; + SendCommand(&c); + return 0; +} /* New command to read the contents of a SRI512 tag * SRI512 tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory */ -int CmdSri512Read(const char *Cmd) { +int CmdSri512Read(const char *Cmd) +{ UsbCommand c = {CMD_READ_SRI512_TAG, {strtol(Cmd, NULL, 0), 0, 0}}; - clearCommandBuffer(); SendCommand(&c); return 0; } - /* New command to read the contents of a SRIX4K tag * SRIX4K tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory/ */ -int CmdSrix4kRead(const char *Cmd) { +int CmdSrix4kRead(const char *Cmd) +{ UsbCommand c = {CMD_READ_SRIX4K_TAG, {strtol(Cmd, NULL, 0), 0, 0}}; - clearCommandBuffer(); SendCommand(&c); return 0; } +int CmdHF14BCmdRaw (const char *cmd) { + UsbCommand resp; + uint8_t *recv; + UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv? + uint8_t reply=1; + uint8_t crc=0; + uint8_t power=0; + char buf[5]=""; + int i=0; + uint8_t data[100]; + unsigned int datalen=0, temp; + char *hexout; + + if (strlen(cmd)<3) { + PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] <0A 0B 0C ... hex>"); + PrintAndLog(" -r do not read response"); + PrintAndLog(" -c calculate and append CRC"); + PrintAndLog(" -p leave the field on after receive"); + return 0; + } -static bool switch_off_field_14b(void) { - UsbCommand resp; - UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { - return false; - } - return false; + // strip + while (*cmd==' ' || *cmd=='\t') cmd++; + + while (cmd[i]!='\0') { + if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; } + if (cmd[i]=='-') { + switch (cmd[i+1]) { + case 'r': + case 'R': + reply=0; + break; + case 'c': + case 'C': + crc=1; + break; + case 'p': + case 'P': + power=1; + break; + default: + PrintAndLog("Invalid option"); + return 0; + } + i+=2; + continue; + } + if ((cmd[i]>='0' && cmd[i]<='9') || + (cmd[i]>='a' && cmd[i]<='f') || + (cmd[i]>='A' && cmd[i]<='F') ) { + buf[strlen(buf)+1]=0; + buf[strlen(buf)]=cmd[i]; + i++; + + if (strlen(buf)>=2) { + sscanf(buf,"%x",&temp); + data[datalen]=(uint8_t)(temp & 0xff); + datalen++; + *buf=0; + } + continue; + } + PrintAndLog("Invalid char on input"); + return 0; + } + if (datalen == 0) + { + PrintAndLog("Missing data input"); + return 0; + } + if(crc) + { + uint8_t first, second; + ComputeCrc14443(CRC_14443_B, data, datalen, &first, &second); + data[datalen++] = first; + data[datalen++] = second; + } + + c.arg[0] = datalen; + c.arg[1] = reply; + c.arg[2] = power; + memcpy(c.d.asBytes,data,datalen); + + SendCommand(&c); + + if (reply) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + recv = resp.d.asBytes; + PrintAndLog("received %i octets",resp.arg[0]); + if(!resp.arg[0]) + return 0; + hexout = (char *)malloc(resp.arg[0] * 3 + 1); + if (hexout != NULL) { + uint8_t first, second; + for (int i = 0; i < resp.arg[0]; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); + ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second); + if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) { + PrintAndLog("CRC OK"); + } else { + PrintAndLog("CRC failed"); + } + } else { + PrintAndLog("malloc failed your client has low memory?"); + } + } else { + PrintAndLog("timeout while waiting for reply."); + } + } // if reply + return 0; } - -int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datalen, bool verbose) { - UsbCommand resp; - UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv,power - if (*crc) { - uint8_t first, second; - ComputeCrc14443(CRC_14443_B, data, *datalen, &first, &second); - data[*datalen] = first; - data[*datalen + 1] = second; - *datalen += 2; - } - - c.arg[0] = *datalen; - c.arg[1] = reply; - c.arg[2] = power; - memcpy(c.d.asBytes,data, *datalen); - clearCommandBuffer(); - SendCommand(&c); - - if (!reply) return 1; - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { - if (verbose) PrintAndLog("timeout while waiting for reply."); - return 0; - } - - int ret = resp.arg[0]; - if (verbose) { - if (ret < 0) { - PrintAndLog("tag didn't respond"); - } else if (ret == 0) { - PrintAndLog("received SOF only (maybe iCLASS/Picopass)"); - } else { - PrintAndLog("received %u octets", ret); - } - } - - *datalen = ret; - - if (ret < 2) return 0; - - memcpy(data, resp.d.asBytes, *datalen); - if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen)); - - uint8_t first, second; - ComputeCrc14443(CRC_14443_B, data, *datalen-2, &first, &second); - if (data[*datalen-2] == first && data[*datalen-1] == second) { - if (verbose) PrintAndLog("CRC OK"); - *crc = true; - } else { - if (verbose) PrintAndLog("CRC failed"); - *crc = false; - } - return 1; -} - - -static int CmdHF14BCmdRaw (const char *Cmd) { - bool reply = true; - bool crc = false; - bool power = false; - bool select = false; - bool SRx = false; - char buf[5] = ""; - uint8_t data[100] = {0x00}; - uint8_t datalen = 0; - unsigned int temp; - int i = 0; - if (strlen(Cmd) < 2) { - PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] [-s || -ss] <0A 0B 0C ... hex>"); - PrintAndLog(" -r do not read response"); - PrintAndLog(" -c calculate and append CRC"); - PrintAndLog(" -p leave the field on after receive"); - PrintAndLog(" -s active signal field ON with select"); - PrintAndLog(" -ss active signal field ON with select for SRx ST Microelectronics tags"); - return 0; - } - - // strip - while (*Cmd == ' ' || *Cmd == '\t') Cmd++; - - while (Cmd[i] != '\0') { - if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } - if (Cmd[i] == '-') { - switch (Cmd[i+1]) { - case 'r': - case 'R': - reply = false; - break; - case 'c': - case 'C': - crc = true; - break; - case 'p': - case 'P': - power = true; - break; - case 's': - case 'S': - select = true; - if (Cmd[i+2] == 's' || Cmd[i+2] == 'S') { - SRx = true; - i++; - } - break; - default: - PrintAndLog("Invalid option"); - return 0; - } - i += 2; - continue; - } - if ((Cmd[i] >= '0' && Cmd[i] <= '9') || - (Cmd[i] >= 'a' && Cmd[i] <= 'f') || - (Cmd[i] >= 'A' && Cmd[i] <= 'F') ) { - buf[strlen(buf)+1] = 0; - buf[strlen(buf)] = Cmd[i]; - i++; - - if (strlen(buf) >= 2) { - sscanf(buf, "%x", &temp); - data[datalen++] = (uint8_t)(temp & 0xff); - *buf = 0; - } - continue; - } - PrintAndLog("Invalid char on input"); - return 0; - } - if (datalen == 0) { - PrintAndLog("Missing data input"); - return 0; - } - - if (select) { //auto select 14b tag - uint8_t cmd2[16]; - bool crc2 = true; - uint8_t cmdLen; - - if (SRx) { - // REQ SRx - cmdLen = 2; - cmd2[0] = 0x06; - cmd2[1] = 0x00; - } else { - cmdLen = 3; - // REQB - cmd2[0] = 0x05; - cmd2[1] = 0x00; - cmd2[2] = 0x08; - } - - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); - - if (SRx) { - if (cmdLen != 3 || !crc2) return switch_off_field_14b(); - } else { - if (cmd2[0] != 0x50 || cmdLen != 14 || !crc2) return switch_off_field_14b(); - } - - uint8_t chipID = 0; - if (SRx) { - // select - chipID = cmd2[0]; - cmd2[0] = 0x0E; - cmd2[1] = chipID; - cmdLen = 2; - } else { - // attrib - cmd2[0] = 0x1D; - // UID from cmd2[1 - 4] - cmd2[5] = 0x00; - cmd2[6] = 0x08; - cmd2[7] = 0x01; - cmd2[8] = 0x00; - cmdLen = 9; - } - - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); - - if (cmdLen != 3 || !crc2) return switch_off_field_14b(); - if (SRx && cmd2[0] != chipID) return switch_off_field_14b(); - } - - return HF14BCmdRaw(reply, &crc, power, data, &datalen, true); - -} - - -// print full atqb info -static void print_atqb_resp(uint8_t *data) { - //PrintAndLog (" UID: %s", sprint_hex(data+1,4)); - PrintAndLog(" App Data: %s", sprint_hex(data+5,4)); - PrintAndLog(" Protocol: %s", sprint_hex(data+9,3)); - uint8_t BitRate = data[9]; - if (!BitRate) - PrintAndLog (" Bit Rate: 106 kbit/s only PICC <-> PCD"); - if (BitRate & 0x10) - PrintAndLog (" Bit Rate: 212 kbit/s PICC -> PCD supported"); - if (BitRate & 0x20) - PrintAndLog (" Bit Rate: 424 kbit/s PICC -> PCD supported"); - if (BitRate & 0x40) - PrintAndLog (" Bit Rate: 847 kbit/s PICC -> PCD supported"); - if (BitRate & 0x01) - PrintAndLog (" Bit Rate: 212 kbit/s PICC <- PCD supported"); - if (BitRate & 0x02) - PrintAndLog (" Bit Rate: 424 kbit/s PICC <- PCD supported"); - if (BitRate & 0x04) - PrintAndLog (" Bit Rate: 847 kbit/s PICC <- PCD supported"); - if (BitRate & 0x80) - PrintAndLog (" Same bit rate <-> required"); - - uint16_t maxFrame = data[10] >> 4; - if (maxFrame < 5) - maxFrame = 8*maxFrame + 16; - else if (maxFrame == 5) - maxFrame = 64; - else if (maxFrame == 6) - maxFrame = 96; - else if (maxFrame == 7) - maxFrame = 128; - else if (maxFrame == 8) - maxFrame = 256; - else - maxFrame = 257; - - PrintAndLog ("Max Frame Size: %u%s", maxFrame, (maxFrame == 257) ? "+ RFU" : ""); - - uint8_t protocolT = data[10] & 0xF; - PrintAndLog (" Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4",(protocolT) ? "" : "not " ); - PrintAndLog ("Frame Wait Int: %u", data[11]>>4); - PrintAndLog (" App Data Code: Application is %s",(data[11]&4) ? "Standard" : "Proprietary"); - PrintAndLog (" Frame Options: NAD is %ssupported",(data[11]&2) ? "" : "not "); - PrintAndLog (" Frame Options: CID is %ssupported",(data[11]&1) ? "" : "not "); - PrintAndLog ("Max Buf Length: %u (MBLI) %s",data[14]>>4, (data[14] & 0xF0) ? "" : "not supported"); - - return; -} - - -int print_ST_Lock_info(uint8_t model) { - //assume connection open and tag selected... - uint8_t data[16] = {0x00}; - uint8_t datalen = 2; - bool crc = true; - uint8_t resplen; - uint8_t blk1; - data[0] = 0x08; - - if (model == 0x02) { //SR176 has special command: - data[1] = 0x0f; - resplen = 4; - } else { - data[1] = 0xff; - resplen = 6; - } - - //std read cmd - if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) == 0) return switch_off_field_14b(); - - if (datalen != resplen || !crc) return switch_off_field_14b(); - - PrintAndLog("Chip Write Protection Bits:"); - // now interpret the data - switch (model){ - case 0x0: //fall through (SRIX4K special) - case 0x3: //fall through (SRIx4K) - case 0x7: // (SRI4K) - //only need data[3] - blk1 = 9; - PrintAndLog(" raw: %s",printBits(1,data+3)); - PrintAndLog(" 07/08:%slocked", (data[3] & 1) ? " not " : " " ); - for (uint8_t i = 1; i < 8; i++){ - PrintAndLog(" %02u:%slocked", blk1, (data[3] & (1 << i)) ? " not " : " " ); - blk1++; - } - break; - case 0x4: //fall through (SRIX512) - case 0x6: //fall through (SRI512) - case 0xC: // (SRT512) - //need data[2] and data[3] - blk1 = 0; - PrintAndLog(" raw: %s", printBits(2,data+2)); - for (uint8_t b = 2; b < 4; b++) { - for (uint8_t i = 0; i < 8; i++) { - PrintAndLog(" %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " ); - blk1++; - } - } - break; - case 0x2: // (SR176) - //need data[2] - blk1 = 0; - PrintAndLog(" raw: %s",printBits(1, data+2)); - for (uint8_t i = 0; i < 8; i++){ - PrintAndLog(" %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " ); - blk1 += 2; - } - break; - default: - return switch_off_field_14b(); - } - return 1; -} - - -// print UID info from SRx chips (ST Microelectronics) -static void print_st_general_info(uint8_t *data) { - //uid = first 8 bytes in data - PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data, 8, 8), 8)); - PrintAndLog(" MFG: %02X, %s", data[6], getManufacturerName(data[6])); - PrintAndLog(" Chip: %02X, %s", data[5], getChipInfo(data[6], data[5])); - return; -} - - -// 14b get and print UID only (general info) -int HF14BStdReader(uint8_t *data, uint8_t *datalen) { - //05 00 00 = find one tag in field - //1d xx xx xx xx 00 08 01 00 = attrib xx=UID (resp 10 [f9 e0]) - //a3 = ? (resp 03 [e2 c2]) - //02 = ? (resp 02 [6a d3]) - // 022b (resp 02 67 00 [29 5b]) - // 0200a40400 (resp 02 67 00 [29 5b]) - // 0200a4040c07a0000002480300 (resp 02 67 00 [29 5b]) - // 0200a4040c07a0000002480200 (resp 02 67 00 [29 5b]) - // 0200a4040006a0000000010100 (resp 02 6a 82 [4b 4c]) - // 0200a4040c09d27600002545500200 (resp 02 67 00 [29 5b]) - // 0200a404000cd2760001354b414e4d30310000 (resp 02 6a 82 [4b 4c]) - // 0200a404000ca000000063504b43532d313500 (resp 02 6a 82 [4b 4c]) - // 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c]) - //03 = ? (resp 03 [e3 c2]) - //c2 = ? (resp c2 [66 15]) - //b2 = ? (resp a3 [e9 67]) - //a2 = ? (resp 02 [6a d3]) - bool crc = true; - *datalen = 3; - //std read cmd - data[0] = 0x05; - data[1] = 0x00; - data[2] = 0x08; - - if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - - if (data[0] != 0x50 || *datalen != 14 || !crc) return switch_off_field_14b(); - - PrintAndLog ("\n14443-3b tag found:"); - PrintAndLog (" UID: %s", sprint_hex(data+1, 4)); - - uint8_t cmd2[16]; - uint8_t cmdLen = 3; - bool crc2 = true; - - cmd2[0] = 0x1D; - // UID from data[1 - 4] - cmd2[1] = data[1]; - cmd2[2] = data[2]; - cmd2[3] = data[3]; - cmd2[4] = data[4]; - cmd2[5] = 0x00; - cmd2[6] = 0x08; - cmd2[7] = 0x01; - cmd2[8] = 0x00; - cmdLen = 9; - - // attrib - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); - - if (cmdLen != 3 || !crc2) return switch_off_field_14b(); - // add attrib responce to data - data[14] = cmd2[0]; - switch_off_field_14b(); - return 1; -} - - -// 14b get and print Full Info (as much as we know) -static bool HF14B_Std_Info(uint8_t *data, uint8_t *datalen) { - if (!HF14BStdReader(data, datalen)) return false; - - //add more info here - print_atqb_resp(data); - - return true; -} - - -// SRx get and print general info about SRx chip from UID -static bool HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){ - bool crc = true; - *datalen = 2; - //wake cmd - data[0] = 0x06; - data[1] = 0x00; - - //leave power on - // verbose on for now for testing - turn off when functional - if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - - if (*datalen != 3 || !crc) return switch_off_field_14b(); - - uint8_t chipID = data[0]; - // select - data[0] = 0x0E; - data[1] = chipID; - *datalen = 2; - - //leave power on - if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - - if (*datalen != 3 || !crc || data[0] != chipID) return switch_off_field_14b(); - - // get uid - data[0] = 0x0B; - *datalen = 1; - - //leave power on - if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - - if (*datalen != 10 || !crc) return switch_off_field_14b(); - - //power off ? - if (closeCon) switch_off_field_14b(); - - PrintAndLog("\n14443-3b ST tag found:"); - print_st_general_info(data); - return 1; -} - - -// SRx get and print full info (needs more info...) -static bool HF14B_ST_Info(bool verbose) { - uint8_t data[100]; - uint8_t datalen; - - if (!HF14B_ST_Reader(data, &datalen, false)) return false; - - //add locking bit information here. - if (print_ST_Lock_info(data[5] >> 2)) - switch_off_field_14b(); - - return true; -} - - -// test for other 14b type tags (mimic another reader - don't have tags to identify) -static bool HF14B_Other_Reader(uint8_t *data, bool verbose) { - uint8_t datalen; - bool crc = true; - - //std read cmd - data[0] = 0x00; - data[1] = 0x0b; - data[2] = 0x3f; - data[3] = 0x80; - datalen = 4; - - if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { - if (datalen > 2 || !crc) { - PrintAndLog ("\n14443-3b tag found:"); - PrintAndLog ("Unknown tag type answered to a 0x000b3f80 command:"); - PrintAndLog ("%s", sprint_hex(data, datalen)); - switch_off_field_14b(); - return true; - } - } - - crc = false; - datalen = 1; - data[0] = 0x0a; - - if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { - if (datalen > 0) { - PrintAndLog ("\n14443-3b tag found:"); - PrintAndLog ("Unknown tag type answered to a 0x0A command:"); - PrintAndLog ("%s", sprint_hex(data, datalen)); - switch_off_field_14b(); - return true; - } - } - - crc = false; - datalen = 1; - data[0] = 0x0c; - - if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { - if (datalen > 0) { - PrintAndLog ("\n14443-3b tag found:"); - PrintAndLog ("Unknown tag type answered to a 0x0C command:"); - PrintAndLog ("%s", sprint_hex(data, datalen)); - switch_off_field_14b(); - return true; - } - } - switch_off_field_14b(); - return false; -} - - -// get and print all info known about any known 14b tag -static int usage_hf_14b_info(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14b info [h] [s]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " s silently"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b info"); - return 0; -} - -int infoHF14B(bool verbose) { - uint8_t data[100]; - uint8_t datalen; - - // try std 14b (atqb) - if (HF14B_Std_Info(data, &datalen)) return 1; - - // try st 14b - if (HF14B_ST_Info(verbose)) return 1; - - // try unknown 14b read commands (to be identified later) - // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_Other_Reader(data, verbose)) return 1; - - if (verbose) PrintAndLog("no 14443B tag found"); - return 0; -} - - -// menu command to get and print all info known about any known 14b tag -static int CmdHF14Binfo(const char *Cmd){ - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_14b_info(); - - bool verbose = !(cmdp == 's'); - return infoHF14B(verbose); -} - - -// get and print general info about all known 14b chips -int readHF14B(bool verbose){ - uint8_t data[100]; - uint8_t datalen = 5; - - // try std 14b (atqb) - if (HF14BStdReader(data, &datalen)) return 1; - - // try st 14b - if (HF14B_ST_Reader(data, &datalen, true)) return 1; - - // try unknown 14b read commands (to be identified later) - // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_Other_Reader(data, verbose)) return 1; - - if (verbose) PrintAndLog("no 14443B tag found"); - return 0; -} - - -// menu command to get and print general info about all known 14b chips -static int usage_hf_14b_reader(void) { - PrintAndLogEx(NORMAL, "Usage: hf 14b reader [h] [s]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " s silently"); - PrintAndLogEx(NORMAL, "Example:"); - PrintAndLogEx(NORMAL, " hf 14b reader"); - return 0; -} - - -static int CmdHF14BReader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_14b_reader(); - - bool verbose = !(cmdp == 's'); - return readHF14B(verbose); -} - - -int CmdSriWrite(const char *Cmd) { -/* - * For SRIX4K blocks 00 - 7F - * hf 14b raw -c -p 09 $srix4kwblock $srix4kwdata - * - * For SR512 blocks 00 - 0F - * hf 14b raw -c -p 09 $sr512wblock $sr512wdata - * - * Special block FF = otp_lock_reg block. - * Data len 4 bytes- - */ - char cmdp = param_getchar(Cmd, 0); - uint8_t blockno = -1; - uint8_t data[4] = {0x00}; - bool isSrix4k = true; - - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf 14b write <1|2> "); - PrintAndLog(" [1 = SRIX4K]"); - PrintAndLog(" [2 = SRI512]"); - PrintAndLog(" [BLOCK number depends on tag, special block == FF]"); - PrintAndLog(" sample: hf 14b write 1 7F 11223344"); - PrintAndLog(" : hf 14b write 1 FF 11223344"); - PrintAndLog(" : hf 14b write 2 15 11223344"); - PrintAndLog(" : hf 14b write 2 FF 11223344"); - return 0; - } - - if ( cmdp == '2' ) - isSrix4k = false; - - //blockno = param_get8(Cmd, 1); - - if (param_gethex(Cmd,1, &blockno, 2) ) { - PrintAndLog("Block number must include 2 HEX symbols"); - return 0; - } - - if (isSrix4k) { - if (blockno > 0x7f && blockno != 0xff){ - PrintAndLog("Block number out of range"); - return 0; - } - } else { - if (blockno > 0x0f && blockno != 0xff){ - PrintAndLog("Block number out of range"); - return 0; - } - } - - if (param_gethex(Cmd, 2, data, 8)) { - PrintAndLog("Data must include 8 HEX symbols"); - return 0; - } - - if (blockno == 0xff) - PrintAndLog("[%s] Write special block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data, 4)); - else - PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data, 4)); - - char str[22]; - sprintf(str, "-ss -c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]); - - CmdHF14BCmdRaw(str); - return 0; -} - - -static int CmdHelp(const char *Cmd); - -static command_t CommandTable[] = +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"info", CmdHF14Binfo, 0, "Find and print details about a 14443B tag"}, - {"list", CmdHF14BList, 0, "[Deprecated] List ISO 14443B history"}, - {"reader", CmdHF14BReader, 0, "Act as a 14443B reader to identify a tag"}, - {"sim", CmdHF14BSim, 0, "Fake ISO 14443B tag"}, - {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443B"}, + {"demod", CmdHF14BDemod, 1, "Demodulate ISO14443 Type B from tag"}, + {"list", CmdHF14BList, 0, "List ISO 14443 history"}, + {"read", CmdHF14BRead, 0, "Read HF tag (ISO 14443)"}, + {"sim", CmdHF14Sim, 0, "Fake ISO 14443 tag"}, + {"simlisten", CmdHFSimlisten, 0, "Get HF samples as fake tag"}, + {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443"}, {"sri512read", CmdSri512Read, 0, "Read contents of a SRI512 tag"}, {"srix4kread", CmdSrix4kRead, 0, "Read contents of a SRIX4K tag"}, - {"sriwrite", CmdSriWrite, 0, "Write data to a SRI512 | SRIX4K tag"}, {"raw", CmdHF14BCmdRaw, 0, "Send raw hex data to tag"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf14b.h b/client/cmdhf14b.h index 4897d879..50d64762 100644 --- a/client/cmdhf14b.h +++ b/client/cmdhf14b.h @@ -11,16 +11,15 @@ #ifndef CMDHF14B_H__ #define CMDHF14B_H__ -#include - int CmdHF14B(const char *Cmd); + +int CmdHF14BDemod(const char *Cmd); int CmdHF14BList(const char *Cmd); -int CmdHF14BInfo(const char *Cmd); -int CmdHF14BSim(const char *Cmd); +int CmdHF14BRead(const char *Cmd); +int CmdHF14Sim(const char *Cmd); +int CmdHFSimlisten(const char *Cmd); int CmdHF14BSnoop(const char *Cmd); int CmdSri512Read(const char *Cmd); int CmdSrix4kRead(const char *Cmd); -int CmdHF14BWrite( const char *cmd); -int infoHF14B(bool verbose); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index cc86841b..cc61d289 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -22,100 +22,131 @@ // 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 #include #include #include - -#include "comms.h" +//#include "proxusb.h" +#include "proxmark3.h" +#include "data.h" #include "graph.h" #include "ui.h" -#include "util.h" #include "cmdparser.h" +#include "cmdhf15.h" #include "iso15693tools.h" -#include "protocols.h" #include "cmdmain.h" -#include "taginfo.h" + +#define FrameSOF Iso15693FrameSOF +#define Logic0 Iso15693Logic0 +#define Logic1 Iso15693Logic1 +#define FrameEOF Iso15693FrameEOF #define Crc(data,datalen) Iso15693Crc(data,datalen) #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) -// SOF defined as -// 1) Unmodulated time of 56.64us -// 2) 24 pulses of 423.75khz -// 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) +// structure and database for uid -> tagtype lookups +typedef struct { + uint64_t uid; + int mask; // how many MSB bits used + char* desc; +} productName; -static const int Iso15693FrameSOF[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 -}; -static const int Iso15693Logic0[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1 -}; -static const int Iso15693Logic1[] = { - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 -}; -// EOF defined as -// 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) -// 2) 24 pulses of 423.75khz -// 3) Unmodulated time of 56.64us - -static const int Iso15693FrameEOF[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +const productName uidmapping[] = { + // UID, #significant Bits, "Vendor(+Product)" + { 0xE001000000000000LL, 16, "Motorola" }, + { 0xE002000000000000LL, 16, "ST Microelectronics" }, + { 0xE003000000000000LL, 16, "Hitachi" }, + { 0xE004000000000000LL, 16, "Philips" }, + { 0xE004010000000000LL, 24, "Philips; IC SL2 ICS20" }, + { 0xE005000000000000LL, 16, "Infineon" }, + { 0xE005400000000000LL, 24, "Infineon; 56x32bit" }, + { 0xE006000000000000LL, 16, "Cylinc" }, + { 0xE007000000000000LL, 16, "Texas Instrument; " }, + { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" }, + { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" }, + { 0xE007800000000000LL, 23, "Texas Instrument; Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" }, + { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" }, + { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" }, + { 0xE008000000000000LL, 16, "Fujitsu" }, + { 0xE009000000000000LL, 16, "Matsushita" }, + { 0xE00A000000000000LL, 16, "NEC" }, + { 0xE00B000000000000LL, 16, "Oki Electric" }, + { 0xE00C000000000000LL, 16, "Toshiba" }, + { 0xE00D000000000000LL, 16, "Mitsubishi" }, + { 0xE00E000000000000LL, 16, "Samsung" }, + { 0xE00F000000000000LL, 16, "Hyundai" }, + { 0xE010000000000000LL, 16, "LG-Semiconductors" }, + { 0xE012000000000000LL, 16, "HID Corporation" }, + { 0xE016000000000000LL, 16, "EM-Marin SA (Skidata)" }, + { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034? no 'read', just 'readmulti'" }, + { 0xE0160c0000000000LL, 24, "EM-Marin SA; EM4035?" }, + { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135; 36x64bit start page 13" }, + { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); 51x64bit" }, + { 0,0,"no tag-info available" } // must be the last entry }; // fast method to just read the UID of a tag (collission detection not supported) // *buf should be large enough to fit the 64bit uid -// returns true if suceeded -static bool getUID(uint8_t *buf) { +// returns 1 if suceeded +int getUID(uint8_t *buf) +{ UsbCommand resp; uint8_t *recv; UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? - uint8_t *req = c.d.asBytes; + uint8_t *req=c.d.asBytes; int reqlen=0; - for (int retry = 0;retry < 3; retry++) { // don't give up the at the first try - req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; - req[1] = ISO15693_INVENTORY; - req[2] = 0; // mask length - reqlen = AddCrc(req, 3); - c.arg[0] = reqlen; + for (int retry=0;retry<3; retry++) { // don't give up the at the first try + + req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; + req[1]=ISO15_CMD_INVENTORY; + req[2]=0; // mask length + reqlen=AddCrc(req,3); + c.arg[0]=reqlen; SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; - if (resp.arg[0] >= 12 && ISO15693_CRC_CHECK == Crc(recv, 12)) { - memcpy(buf, &recv[2], 8); - return true; + if (resp.arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) { + memcpy(buf,&recv[2],8); + return 1; } } } // retry - return false; + return 0; +} + + + +// get a product description based on the UID +// uid[8] tag uid +// returns description of the best match +static char* getTagInfo(uint8_t *uid) { + uint64_t myuid,mask; + int i=0, best=-1; + memcpy(&myuid,uid,sizeof(uint64_t)); + while (uidmapping[i].mask>0) { + mask=(~0LL) <<(64-uidmapping[i].mask); + if ((myuid & mask) == uidmapping[i].uid) { + if (best==-1) { + best=i; + } else { + if (uidmapping[i].mask>uidmapping[best].mask) { + best=i; + } + } + } + i++; + } + + if (best>=0) return uidmapping[best].desc; + + return uidmapping[i].desc; } @@ -126,7 +157,7 @@ static char* TagErrorStr(uint8_t error) { case 0x02: return "The command is not recognised"; case 0x03: return "The option is not supported."; case 0x0f: return "Unknown error."; - case 0x10: return "The specified block is not available (doesn't exist)."; + case 0x10: return "The specified block is not available (doesn’t exist)."; case 0x11: return "The specified block is already -locked and thus cannot be locked again"; case 0x12: return "The specified block is locked and its content cannot be changed."; case 0x13: return "The specified block was not successfully programmed."; @@ -137,21 +168,22 @@ static char* TagErrorStr(uint8_t error) { // Mode 3 -static int CmdHF15Demod(const char *Cmd) { +int CmdHF15Demod(const char *Cmd) +{ // The sampling rate is 106.353 ksps/s, for T = 18.8 us int i, j; int max = 0, maxPos = 0; - int skip = 2; + int skip = 4; - if (GraphTraceLen < 2000) return 0; + if (GraphTraceLen < 1000) return 0; // First, correlate for SOF - for (i = 0; i < 200; i++) { + for (i = 0; i < 100; i++) { int corr = 0; - for (j = 0; j < arraylen(Iso15693FrameSOF); j += skip) { - corr += Iso15693FrameSOF[j] * GraphBuffer[i + (j / skip)]; + for (j = 0; j < arraylen(FrameSOF); j += skip) { + corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; } if (corr > max) { max = corr; @@ -159,50 +191,43 @@ static int CmdHF15Demod(const char *Cmd) { } } PrintAndLog("SOF at %d, correlation %d", maxPos, - max / (arraylen(Iso15693FrameSOF) / skip)); + max / (arraylen(FrameSOF) / skip)); - i = maxPos + arraylen(Iso15693FrameSOF) / skip; + i = maxPos + arraylen(FrameSOF) / skip; int k = 0; uint8_t outBuf[20]; memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for (;;) { - int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Iso15693Logic0); j += skip) { - corr0 += Iso15693Logic0[j]*GraphBuffer[i+(j/skip)]; - } - corr01 = corr00 = corr0; - for(j = 0; j < arraylen(Iso15693Logic0); j += skip) { - corr00 += Iso15693Logic0[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)]; - corr01 += Iso15693Logic1[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)]; - } - for(j = 0; j < arraylen(Iso15693Logic1); j += skip) { - corr1 += Iso15693Logic1[j]*GraphBuffer[i+(j/skip)]; - } - for(j = 0; j < arraylen(Iso15693FrameEOF); j += skip) { - corrEOF += Iso15693FrameEOF[j]*GraphBuffer[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr00 *= 2; - corr01 *= 2; - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) { - PrintAndLog("EOF at %d", i); - break; + int corr0 = 0, corr1 = 0, corrEOF = 0; + for (j = 0; j < arraylen(Logic0); j += skip) { + corr0 += Logic0[j] * GraphBuffer[i + (j / skip)]; + } + for (j = 0; j < arraylen(Logic1); j += skip) { + corr1 += Logic1[j] * GraphBuffer[i + (j / skip)]; + } + for (j = 0; j < arraylen(FrameEOF); j += skip) { + corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)]; + } + // Even things out by the length of the target waveform. + corr0 *= 4; + corr1 *= 4; + + if (corrEOF > corr1 && corrEOF > corr0) { + PrintAndLog("EOF at %d", i); + break; } else if (corr1 > corr0) { - i += arraylen(Iso15693Logic1) / skip; + i += arraylen(Logic1) / skip; outBuf[k] |= mask; } else { - i += arraylen(Iso15693Logic0) / skip; + i += arraylen(Logic0) / skip; } mask <<= 1; if (mask == 0) { k++; mask = 0x01; } - if ((i + (int)arraylen(Iso15693FrameEOF)) >= GraphTraceLen) { + if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) { PrintAndLog("ran off end!"); break; } @@ -221,85 +246,49 @@ static int CmdHF15Demod(const char *Cmd) { } + // * Acquire Samples as Reader (enables carrier, sends inquiry) -static int CmdHF15Read(const char *Cmd) { +int CmdHF15Read(const char *Cmd) +{ UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); return 0; } - -// Record Activity without enabling carrier -static int CmdHF15Snoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_ISO_15693}; +// Record Activity without enabeling carrier +int CmdHF15Record(const char *Cmd) +{ + UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693}; SendCommand(&c); return 0; } - -int HF15Reader(const char *Cmd, bool verbose) { - uint8_t uid[8]; - - if (!getUID(uid)) { - if (verbose) PrintAndLog("No Tag found."); - return 0; - } - - PrintAndLog("UID: %s", sprintUID(NULL,uid)); - PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6])); - PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5])); - return 1; -} - - -static int CmdHF15Reader(const char *Cmd) { +int CmdHF15Reader(const char *Cmd) +{ UsbCommand c = {CMD_READER_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; SendCommand(&c); return 0; } - // Simulation is still not working very good -static int CmdHF15Sim(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - uint8_t uid[8] = {0x00}; - - //E0 16 24 00 00 00 00 00 - if (cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf 15 sim "); - PrintAndLog(""); - PrintAndLog(" sample: hf 15 sim E016240000000000"); - return 0; - } - - if (param_gethex(Cmd, 0, uid, 16)) { - PrintAndLog("UID must include 16 HEX symbols"); - return 0; - } - - PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X", - uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]); - PrintAndLog("Press the button to stop simulation"); - - UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; - memcpy(c.d.asBytes,uid,8); - +int CmdHF15Sim(const char *Cmd) +{ + UsbCommand c = {CMD_SIMTAG_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}}; SendCommand(&c); return 0; } - // finds the AFI (Application Family Idendifier) of a card, by trying all values // (There is no standard way of reading the AFI, allthough some tags support this) -static int CmdHF15Afi(const char *Cmd) { +int CmdHF15Afi(const char *Cmd) +{ UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}}; SendCommand(&c); return 0; } - // Reads all memory pages -static int CmdHF15DumpMem(const char*Cmd) { +int CmdHF15DumpMem(const char*Cmd) { UsbCommand resp; uint8_t uid[8]; uint8_t *recv=NULL; @@ -314,29 +303,28 @@ static int CmdHF15DumpMem(const char*Cmd) { return 0; } - PrintAndLog("Reading memory from tag"); - PrintAndLog("UID: %s", sprintUID(NULL,uid)); - PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6])); - PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5])); + PrintAndLog("Reading memory from tag UID=%s",sprintUID(NULL,uid)); + PrintAndLog("Tag Info: %s",getTagInfo(uid)); for (int retry=0; retry<5; retry++) { - req[0]= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; - req[1] = ISO15693_READBLOCK; + req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[1]=ISO15_CMD_READ; memcpy(&req[2],uid,8); - req[10] = blocknum; - reqlen = AddCrc(req,11); - c.arg[0] = reqlen; + req[10]=blocknum; + reqlen=AddCrc(req,11); + c.arg[0]=reqlen; SendCommand(&c); if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; - if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15693_RES_ERROR)) { + if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { retry=0; *output=0; // reset outputstring - sprintf(output, "Block %02x ",blocknum); + sprintf(output, "Block %2i ",blocknum); for ( int i=1; i=12) { - recv = resp.d.asBytes; - PrintAndLog("UID: %s", sprintUID(NULL,recv+2)); - PrintAndLog("Manufacturer byte: %02X, %s", recv[8], getManufacturerName(recv[8])); - PrintAndLog("Chip ID: %02X, %s", recv[7], getChipInfo(recv[8], recv[7])); + recv = resp.d.asBytes; + PrintAndLog("UID=%s",sprintUID(NULL,&recv[2])); + PrintAndLog("Tag Info: %s",getTagInfo(&recv[2])); } else { PrintAndLog("Response to short, just %i bytes. No tag?\n",resp.arg[0]); } @@ -397,12 +418,11 @@ static int CmdHF15CmdInquiry(const char *Cmd) { // Turns debugging on(1)/off(0) -static int CmdHF15CmdDebug( const char *cmd) { - int debug = atoi(cmd); - if (strlen(cmd) < 1) { - PrintAndLog("Usage: hf 15 debug <0|1>"); - PrintAndLog(" 0 no debugging"); - PrintAndLog(" 1 turn debugging on"); +int CmdHF15CmdDebug( const char *cmd) { + int debug=atoi(cmd); + if (strlen(cmd)<1) { + PrintAndLog("Usage: hf 15 cmd debug <0/1>"); + PrintAndLog(" 0..no debugging output 1..turn debugging on"); return 0; } @@ -412,7 +432,7 @@ static int CmdHF15CmdDebug( const char *cmd) { } -static int CmdHF15CmdRaw (const char *cmd) { +int CmdHF15CmdRaw (const char *cmd) { UsbCommand resp; uint8_t *recv; UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? @@ -426,7 +446,7 @@ static int CmdHF15CmdRaw (const char *cmd) { char *hexout; - if (strlen(cmd)<2) { + if (strlen(cmd)<3) { PrintAndLog("Usage: hf 15 cmd raw [-r] [-2] [-c] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -2 use slower '1 out of 256' mode"); @@ -488,31 +508,22 @@ static int CmdHF15CmdRaw (const char *cmd) { SendCommand(&c); if (reply) { - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; - int recv_len = resp.arg[0]; - if (recv_len == 0) { - PrintAndLog("received SOF only. Maybe Picopass/iCLASS?"); - } else if (recv_len > 0) { - PrintAndLog("received %i octets", recv_len); - hexout = (char *)malloc(resp.arg[0] * 3 + 1); - if (hexout != NULL) { - for (int i = 0; i < resp.arg[0]; i++) { // data in hex - sprintf(&hexout[i * 3], "%02X ", recv[i]); - } - PrintAndLog("%s", hexout); - free(hexout); + PrintAndLog("received %i octets",resp.arg[0]); + hexout = (char *)malloc(resp.arg[0] * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < resp.arg[0]; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); } - } else if (recv_len == -1) { - PrintAndLog("card didn't respond"); - } else if (recv_len == -2) { - PrintAndLog("receive buffer overflow"); + PrintAndLog("%s", hexout); + free(hexout); } } else { PrintAndLog("timeout while waiting for reply."); } - } - + + } // if reply return 0; } @@ -522,30 +533,29 @@ static int CmdHF15CmdRaw (const char *cmd) { * Parameters: * **cmd command line */ -static int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) { +int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) { int temp; - uint8_t *req = c->d.asBytes; - uint8_t uid[8] = {0x00}; - uint32_t reqlen = 0; + uint8_t *req=c->d.asBytes, uid[8]; + uint32_t reqlen=0; // strip while (**cmd==' ' || **cmd=='\t') (*cmd)++; - if (strstr(*cmd, "-2") == *cmd) { - c->arg[1] = 0; // use 1of256 - (*cmd) += 2; + if (strstr(*cmd,"-2")==*cmd) { + c->arg[1]=0; // use 1of256 + (*cmd)+=2; } // strip - while (**cmd == ' ' || **cmd == '\t') (*cmd)++; + while (**cmd==' ' || **cmd=='\t') (*cmd)++; - if (strstr(*cmd, "-o") == *cmd) { - req[reqlen] = ISO15693_REQ_OPTION; - (*cmd) += 2; + if (strstr(*cmd,"-o")==*cmd) { + req[reqlen]=ISO15_REQ_OPTION; + (*cmd)+=2; } // strip - while (**cmd == ' ' || **cmd == '\t') (*cmd)++; + while (**cmd==' ' || **cmd=='\t') (*cmd)++; switch (**cmd) { case 0: @@ -555,55 +565,59 @@ static int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso case 's': case 'S': // you must have selected the tag earlier - req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_SELECT; - memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen); - reqlen += iso15cmdlen; + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; break; case 'u': case 'U': // unaddressed mode may not be supported by all vendors - req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH; - memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen); - reqlen += iso15cmdlen; + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; break; case '*': // we scan for the UID ourself - req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; - memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen); - reqlen += iso15cmdlen; - if (!getUID(uid)) { - PrintAndLog("No Tag found"); - return 0; - } - memcpy(req+reqlen ,uid, 8); - PrintAndLog("Detected UID %s",sprintUID(NULL,uid)); - reqlen += 8; + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; + if (!getUID(uid)) { + PrintAndLog("No Tag found"); + return 0; + } + memcpy(req+reqlen,uid,8); + PrintAndLog("Detected UID %s",sprintUID(NULL,uid)); + reqlen+=8; break; default: - req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; - memcpy(&req[reqlen], &iso15cmd[0], iso15cmdlen); - reqlen += iso15cmdlen; + req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | + ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen+=iso15cmdlen; /* sscanf(cmd,"%hX%hX%hX%hX%hX%hX%hX%hX", (short unsigned int *)&uid[7],(short unsigned int *)&uid[6], (short unsigned int *)&uid[5],(short unsigned int *)&uid[4], (short unsigned int *)&uid[3],(short unsigned int *)&uid[2], (short unsigned int *)&uid[1],(short unsigned int *)&uid[0]); */ - for (int i=0; i<8 && (*cmd)[i*2] && (*cmd)[i*2+1]; i++) { // parse UID + for (int i=0;i<8 && (*cmd)[i*2] && (*cmd)[i*2+1];i++) { // parse UID sscanf((char[]){(*cmd)[i*2],(*cmd)[i*2+1],0},"%X",&temp); uid[7-i]=temp&0xff; } - PrintAndLog("Using UID %s", sprintUID(NULL, uid)); - memcpy(&req[reqlen], &uid[0], 8); - reqlen += 8; + PrintAndLog("Using UID %s",sprintUID(NULL,uid)); + memcpy(&req[reqlen],&uid[0],8); + reqlen+=8; } // skip to next space - while (**cmd != ' ' && **cmd != '\t') (*cmd)++; + while (**cmd!=' ' && **cmd!='\t') (*cmd)++; // skip over the space - while (**cmd == ' ' || **cmd == '\t') (*cmd)++; + while (**cmd==' ' || **cmd=='\t') (*cmd)++; - c->arg[0] = reqlen; + c->arg[0]=reqlen; return 1; } @@ -611,7 +625,7 @@ static int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso * Commandline handling: HF15 CMD SYSINFO * get system information from tag/VICC */ -static int CmdHF15CmdSysinfo(const char *Cmd) { +int CmdHF15CmdSysinfo(const char *Cmd) { UsbCommand resp; uint8_t *recv; UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv? @@ -639,7 +653,7 @@ static int CmdHF15CmdSysinfo(const char *Cmd) { return 0; } - prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_GET_SYSTEM_INFO},1); + prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1); reqlen=c.arg[0]; reqlen=AddCrc(req,reqlen); @@ -647,14 +661,20 @@ static int CmdHF15CmdSysinfo(const char *Cmd) { SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000) && resp.arg[0] > 2) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) { recv = resp.d.asBytes; - if (ISO15693_CRC_CHECK == Crc(recv, resp.arg[0])) { - if (!(recv[0] & ISO15693_RES_ERROR)) { + if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { *output=0; // reset outputstring - PrintAndLog("UID: %s", sprintUID(NULL,recv+2)); - PrintAndLog("Manufacturer byte: %02X, %s", recv[8], getManufacturerName(recv[8])); - PrintAndLog("Chip ID: %02X, %s", recv[7], getChipInfo(recv[8], recv[7])); + for ( i=1; i2) { recv = resp.d.asBytes; - if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15693_RES_ERROR)) { + if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { *output=0; // reset outputstring for ( int i=1; i2) { recv = resp.d.asBytes; - if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15693_RES_ERROR)) { + if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { *output=0; // reset outputstring //sprintf(output, "Block %2i ",blocknum); for ( int i=1; i "); PrintAndLog(" options:"); PrintAndLog(" -2 use slower '1 out of 256' mode"); @@ -876,207 +895,84 @@ static int CmdHF15CmdWrite(const char *Cmd) { return 0; } - prepareHF15Cmd(&cmd, &c, (uint8_t[]){ISO15693_WRITEBLOCK}, 1); - reqlen = c.arg[0]; + prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_WRITE},1); + reqlen=c.arg[0]; // *cmd -> page num ; *cmd2 -> data - cmd2 = cmd; - while (*cmd2 != ' ' && *cmd2 != '\t' && *cmd2) cmd2++; - *cmd2 = 0; + cmd2=cmd; + while (*cmd2!=' ' && *cmd2!='\t' && *cmd2) cmd2++; + *cmd2=0; cmd2++; - pagenum = strtol(cmd, NULL, 0); + pagenum=strtol(cmd,NULL,0); /*if (pagenum<0) { PrintAndLog("invalid pagenum"); return 0; } */ - req[reqlen++] = (uint8_t)pagenum; + req[reqlen++]=(uint8_t)pagenum; while (cmd2[0] && cmd2[1]) { // hexdata, read by 2 hexchars - if (*cmd2 == ' ') { + if (*cmd2==' ') { cmd2++; continue; } - sscanf((char[]){cmd2[0], cmd2[1], 0}, "%X", &temp); - req[reqlen++] = temp & 0xff; - cmd2 += 2; + sscanf((char[]){cmd2[0],cmd2[1],0},"%X",&temp); + req[reqlen++]=temp & 0xff; + cmd2+=2; } - reqlen = AddCrc(req, reqlen); - c.arg[0] = reqlen; + reqlen=AddCrc(req,reqlen); + + c.arg[0]=reqlen; SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - int recv_len = resp.arg[0]; - uint8_t *recv = resp.d.asBytes; - if (recv_len == 0) { - PrintAndLog("Received SOF only. Maybe Picopass/iCLASS?"); - } else if (recv_len == -1) { - PrintAndLog("Tag didn't respond"); - } else if (recv_len == -2) { - PrintAndLog("Receive buffer overflow"); - } else if (ISO15693_CRC_CHECK != Crc(recv, resp.arg[0])) { - PrintAndLog("CRC check failed on Tag response"); - } else if (!(recv[0] & ISO15693_RES_ERROR)) { - PrintAndLog("Tag returned OK"); + if (WaitForResponseTimeout(CMD_ACK,&resp,2000) && resp.arg[0]>2) { + recv = resp.d.asBytes; + if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15_RES_ERROR)) { + PrintAndLog("OK"); + } else { + PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1])); + } } else { - PrintAndLog("Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1])); + PrintAndLog("CRC failed"); } } else { - PrintAndLog("No answer from Proxmark"); + PrintAndLog("timeout: no answer - data may be written anyway"); } return 0; } -static int CmdHF15CSetUID(const char *Cmd) { - uint8_t uid[8] = {0x00}; - uint8_t oldUid[8], newUid[8] = {0x00}; - - uint8_t needHelp = 0; - char cmdp = 1; - - if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 16)) { - PrintAndLog("UID must include 16 HEX symbols"); - return 1; - } - - if (uid[0] != 0xe0) { - PrintAndLog("UID must begin with the byte 'E0'"); - return 1; - } - - while (param_getchar(Cmd, cmdp) != 0x00) { - switch (param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - needHelp = 1; - break; - default: - PrintAndLog("ERROR: Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - needHelp = 1; - break; - } - cmdp++; - } - - if (strlen(Cmd) < 1 || needHelp) { - PrintAndLog(""); - PrintAndLog("Usage: hf 15 csetuid "); - PrintAndLog("sample: hf 15 csetuid E004013344556677"); - PrintAndLog("Set UID for magic Chinese card (only works with such cards)"); - return 0; - } - - PrintAndLog("Using backdoor Magic tag function"); - - if (!getUID(oldUid)) { - PrintAndLog("Can't get old UID."); - return 1; - } - - UsbCommand c = {CMD_CSETUID_ISO_15693, {0, 0, 0}}; - memcpy(c.d.asBytes, uid, 8); - - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - int recv_len = resp.arg[0]; - uint8_t *recv = resp.d.asBytes; - if (recv_len == 0) { - PrintAndLog("Received SOF only. Maybe Picopass/iCLASS?"); - } else if (recv_len == -1) { - PrintAndLog("Tag didn't respond"); - } else if (recv_len == -2) { - PrintAndLog("Receive buffer overflow"); - } else if (ISO15693_CRC_CHECK != Crc(recv, recv_len)) { - PrintAndLog("CRC check failed on Tag response"); - } else if (!(recv[0] & ISO15693_RES_ERROR)) { - PrintAndLog("Tag returned OK"); - } else { - PrintAndLog("Tag returned Error %i: %s", recv[1], TagErrorStr(recv[1])); - } - } else { - PrintAndLog("No answer from Proxmark"); - } - - if (!getUID(newUid)) { - PrintAndLog("Can't get new UID."); - return 1; - } - - PrintAndLog(""); - PrintAndLog("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]); - PrintAndLog("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]); - return 0; -} - -// "HF 15 Cmd" Interface -// Allows direct communication with the tag on command level - -static int CmdHF15CmdHelp(const char*Cmd); - -static command_t CommandTable15Cmd[] = { - {"help", CmdHF15CmdHelp, 1, "This Help"}, - {"inquiry", CmdHF15CmdInquiry, 0, "Search for tags in range"}, +static command_t CommandTable15Cmd[] = +{ + {"help", CmdHF15CmdHelp, 1, "This Help"}, + {"inquiry", CmdHF15CmdInquiry, 0, "Search for tags in range"}, /* - {"select", CmdHF15CmdSelect, 0, "Select an tag with a specific UID for further commands"}, + {"select", CmdHF15CmdSelect, 0, "Select an tag with a specific UID for further commands"}, */ - {"read", CmdHF15CmdRead, 0, "Read a block"}, - {"write", CmdHF15CmdWrite, 0, "Write a block"}, - {"readmulti", CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"}, - {"sysinfo", CmdHF15CmdSysinfo, 0, "Get Card Information"}, - {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, - {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"}, - {NULL, NULL, 0, NULL} + {"read", CmdHF15CmdRead, 0, "Read a block"}, + {"write", CmdHF15CmdWrite, 0, "Write a block"}, + {"readmulti",CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"}, + {"sysinfo",CmdHF15CmdSysinfo, 0, "Get Card Information"}, + {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"}, + {NULL, NULL, 0, NULL} }; - -static int CmdHF15Cmd(const char *Cmd) { +int CmdHF15Cmd(const char *Cmd) +{ CmdsParse(CommandTable15Cmd, Cmd); return 0; } - - -static int CmdHF15CmdHelp(const char *Cmd) { + +int CmdHF15CmdHelp(const char *Cmd) +{ CmdsHelp(CommandTable15Cmd); return 0; } - -// "HF 15" interface - -static int CmdHF15Help(const char*Cmd); - -static command_t CommandTable15[] = { - {"help", CmdHF15Help, 1, "This help"}, - {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"}, - {"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"}, - {"snoop", CmdHF15Snoop, 0, "Eavesdrop ISO 15693 communications"}, - {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, - {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, - {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, - {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, - {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"}, - {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, - {NULL, NULL, 0, NULL} -}; - - -int CmdHF15(const char *Cmd) { - CmdsParse(CommandTable15, Cmd); - return 0; -} - - -static int CmdHF15Help(const char *Cmd) { - CmdsHelp(CommandTable15); - return 0; -} - - diff --git a/client/cmdhf15.h b/client/cmdhf15.h index 89cbd259..8d78e13f 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -11,9 +11,15 @@ #ifndef CMDHF15_H__ #define CMDHF15_H__ -#include +int CmdHF15(const char *Cmd); -extern int CmdHF15(const char *Cmd); -extern int HF15Reader(const char *Cmd, bool verbose); +int CmdHF15Demod(const char *Cmd); +int CmdHF15Read(const char *Cmd); +int CmdHF15Reader(const char *Cmd); +int CmdHF15Sim(const char *Cmd); +int CmdHF15Record(const char *Cmd); +int CmdHF15Cmd(const char*Cmd); +int CmdHF15CmdHelp(const char*Cmd); +int CmdHF15Help(const char*Cmd); #endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index 76664bf5..8a36d6ae 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -8,20 +8,15 @@ // Commands related to the German electronic Identification Card //----------------------------------------------------------------------------- -#include "cmdhfepa.h" - -#include -#include -#include -#include -#include #include "util.h" -#include "util_posix.h" -#include "comms.h" +//#include "proxusb.h" +#include "proxmark3.h" #include "ui.h" #include "cmdparser.h" #include "common.h" #include "cmdmain.h" +#include "sleep.h" +#include "cmdhfepa.h" static int CmdHelp(const char *Cmd); @@ -34,23 +29,23 @@ int CmdHFEPACollectPACENonces(const char *Cmd) unsigned int n = 0; // delay between requests unsigned int d = 0; - + sscanf(Cmd, "%u %u %u", &m, &n, &d); - + // values are expected to be > 0 m = m > 0 ? m : 1; n = n > 0 ? n : 1; - PrintAndLog("Collecting %u %u-byte nonces", n, m); - PrintAndLog("Start: %" PRIu64 , msclock()/1000); + PrintAndLog("Collecting %u %"hhu"-byte nonces", n, m); + PrintAndLog("Start: %u", time(NULL)); // repeat n times for (unsigned int i = 0; i < n; i++) { // execute PACE UsbCommand c = {CMD_EPA_PACE_COLLECT_NONCE, {(int)m, 0, 0}}; SendCommand(&c); UsbCommand resp; - - WaitForResponse(CMD_ACK,&resp); + + WaitForResponse(CMD_ACK,&resp); // check if command failed if (resp.arg[0] != 0) { @@ -59,138 +54,27 @@ int CmdHFEPACollectPACENonces(const char *Cmd) size_t nonce_length = resp.arg[1]; char *nonce = (char *) malloc(2 * nonce_length + 1); for(int j = 0; j < nonce_length; j++) { - sprintf(nonce + (2 * j), "%02X", resp.d.asBytes[j]); + snprintf(nonce + (2 * j), 3, "%02X", resp.d.asBytes[j]); } // print nonce - PrintAndLog("Length: %d, Nonce: %s", nonce_length, nonce); - free(nonce); + PrintAndLog("Length: %d, Nonce: %s",resp.arg[1], nonce); } if (i < n - 1) { sleep(d); } } - PrintAndLog("End: %" PRIu64, msclock()/1000); + PrintAndLog("End: %u", time(NULL)); return 1; } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////The commands lie below here///////////////////////////////////////////////////////////////////////////////////////// - -// perform the PACE protocol by replaying APDUs -int CmdHFEPAPACEReplay(const char *Cmd) -{ - // the 4 APDUs which are replayed + their lengths - uint8_t msesa_apdu[41], gn_apdu[8], map_apdu[75]; - uint8_t pka_apdu[75], ma_apdu[18], apdu_lengths[5] = {0}; - // pointers to the arrays to be able to iterate - uint8_t *apdus[] = {msesa_apdu, gn_apdu, map_apdu, pka_apdu, ma_apdu}; - - // usage message - static const char *usage_msg = - "Please specify 5 APDUs separated by spaces. " - "Example:\n preplay 0022C1A4 1068000000 1086000002 1234ABCDEF 1A2B3C4D"; - - // Proxmark response - UsbCommand resp; - - int skip = 0, skip_add = 0, scan_return = 0; - // for each APDU - for (int i = 0; i < sizeof(apdu_lengths); i++) { - // scan to next space or end of string - while (Cmd[skip] != ' ' && Cmd[skip] != '\0') { - // convert - scan_return = sscanf(Cmd + skip, "%2X%n", - (unsigned int *) (apdus[i] + apdu_lengths[i]), - &skip_add); - if (scan_return < 1) { - PrintAndLog((char *)usage_msg); - PrintAndLog("Not enough APDUs! Try again!"); - return 0; - } - skip += skip_add; - apdu_lengths[i]++; - } - - // break on EOF - if (Cmd[skip] == '\0') { - if (i < sizeof(apdu_lengths) - 1) { - - PrintAndLog((char *)usage_msg); - return 0; - } - break; - } - // skip the space - skip++; - } - - // transfer the APDUs to the Proxmark - UsbCommand usb_cmd; - usb_cmd.cmd = CMD_EPA_PACE_REPLAY; - for (int i = 0; i < sizeof(apdu_lengths); i++) { - // APDU number - usb_cmd.arg[0] = i + 1; - // transfer the APDU in several parts if necessary - for (int j = 0; j * sizeof(usb_cmd.d.asBytes) < apdu_lengths[i]; j++) { - // offset into the APDU - usb_cmd.arg[1] = j * sizeof(usb_cmd.d.asBytes); - // amount of data in this packet - int packet_length = apdu_lengths[i] - (j * sizeof(usb_cmd.d.asBytes)); - if (packet_length > sizeof(usb_cmd.d.asBytes)) { - packet_length = sizeof(usb_cmd.d.asBytes); - } - usb_cmd.arg[2] = packet_length; - - memcpy(usb_cmd.d.asBytes, // + (j * sizeof(usb_cmd.d.asBytes)), - apdus[i] + (j * sizeof(usb_cmd.d.asBytes)), - packet_length); - SendCommand(&usb_cmd); - WaitForResponse(CMD_ACK, &resp); - if (resp.arg[0] != 0) { - PrintAndLog("Transfer of APDU #%d Part %d failed!", i, j); - return 0; - } - } - } - - // now perform the replay - usb_cmd.arg[0] = 0; - SendCommand(&usb_cmd); - WaitForResponse(CMD_ACK, &resp); - if (resp.arg[0] != 0) { - PrintAndLog("\nPACE replay failed in step %u!", (uint32_t)resp.arg[0]); - PrintAndLog("Measured times:"); - PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]); - PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]); - PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]); - PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]); - PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]); - } else { - PrintAndLog("PACE replay successfull!"); - PrintAndLog("MSE Set AT: %u us", resp.d.asDwords[0]); - PrintAndLog("GA Get Nonce: %u us", resp.d.asDwords[1]); - PrintAndLog("GA Map Nonce: %u us", resp.d.asDwords[2]); - PrintAndLog("GA Perform Key Agreement: %u us", resp.d.asDwords[3]); - PrintAndLog("GA Mutual Authenticate: %u us", resp.d.asDwords[4]); - } - - - return 1; -} - -////////////////////////////////The new commands lie above here///////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // UI-related stuff -static const command_t CommandTable[] = +static const command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"cnonces", CmdHFEPACollectPACENonces, 0, " Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses"}, - {"preplay", CmdHFEPAPACEReplay, 0, - " Perform PACE protocol by replaying given APDUs"}, {NULL, NULL, 0, NULL} }; @@ -202,7 +86,10 @@ int CmdHelp(const char *Cmd) int CmdHFEPA(const char *Cmd) { - (void)WaitForResponseTimeout(CMD_ACK,NULL,100); - CmdsParse(CommandTable, Cmd); - return 0; -} + // flush + WaitForResponseTimeout(CMD_ACK,NULL,100); + + // parse + CmdsParse(CommandTable, Cmd); + return 0; +} \ No newline at end of file diff --git a/client/cmdhffido.c b/client/cmdhffido.c deleted file mode 100644 index 25862445..00000000 --- a/client/cmdhffido.c +++ /dev/null @@ -1,926 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2018 Merlok -// -// 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. -//----------------------------------------------------------------------------- -// High frequency MIFARE Plus commands -//----------------------------------------------------------------------------- -// -// Documentation here: -// -// FIDO Alliance specifications -// https://fidoalliance.org/download/ -// FIDO NFC Protocol Specification v1.0 -// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html -// FIDO U2F Raw Message Formats -// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html -//----------------------------------------------------------------------------- - - -#include "cmdhffido.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "comms.h" -#include "cmdmain.h" -#include "util.h" -#include "ui.h" -#include "proxmark3.h" -#include "mifare.h" -#include "emv/emvcore.h" -#include "emv/emvjson.h" -#include "emv/dump.h" -#include "emv/apduinfo.h" -#include "cliparser/cliparser.h" -#include "crypto/asn1utils.h" -#include "crypto/libpcrypto.h" -#include "fido/cbortools.h" -#include "fido/fidocore.h" -#include "fido/cose.h" - -static int CmdHelp(const char *Cmd); - -int CmdHFFidoInfo(const char *cmd) { - - if (cmd && strlen(cmd) > 0) - PrintAndLog("WARNING: command don't have any parameters.\n"); - - // info about 14a part - CmdHF14AInfo(""); - - // FIDO info - PrintAndLog("--------------------------------------------"); - SetAPDULogging(false); - - uint8_t buf[APDU_RESPONSE_LEN] = {0}; - size_t len = 0; - uint16_t sw = 0; - int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); - - if (res) { - DropField(); - return res; - } - - if (sw != 0x9000) { - if (sw) - PrintAndLog("Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - else - PrintAndLog("APDU exchange error. Card returns 0x0000."); - - DropField(); - return 0; - } - - if (!strncmp((char *)buf, "U2F_V2", 7)) { - if (!strncmp((char *)buf, "FIDO_2_0", 8)) { - PrintAndLog("FIDO2 authenricator detected. Version: %.*s", len, buf); - } else { - PrintAndLog("FIDO authenricator detected (not standard U2F)."); - PrintAndLog("Non U2F authenticator version:"); - dump_buffer((const unsigned char *)buf, len, NULL, 0); - } - } else { - PrintAndLog("FIDO U2F authenricator detected. Version: %.*s", len, buf); - } - - res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw); - DropField(); - if (res) { - return res; - } - if (sw != 0x9000) { - PrintAndLog("FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - - return 0; - } - - if(buf[0]) { - PrintAndLog("FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); - return 0; - } - - if (len > 1) { -// if (false) { -// PrintAndLog("FIDO2 version: (len=%d)", len); -// dump_buffer((const unsigned char *)buf, len, NULL, 0); -// } - - PrintAndLog("FIDO2 version CBOR decoded:"); - TinyCborPrintFIDOPackage(fido2CmdGetInfo, true, &buf[1], len - 1); - } else { - PrintAndLog("FIDO2 version length error"); - } - - return 0; -} - -json_t *OpenJson(int paramnum, char *fname, void* argtable[], bool *err) { - json_t *root = NULL; - json_error_t error; - *err = false; - - uint8_t jsonname[250] ={0}; - char *cjsonname = (char *)jsonname; - int jsonnamelen = 0; - - // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen); - if (CLIParamStrToBuf(arg_get_str(paramnum), jsonname, sizeof(jsonname), &jsonnamelen)) { - CLIParserFree(); - return NULL; - } - - // current path + file name - if (!strstr(cjsonname, ".json")) - strcat(cjsonname, ".json"); - - if (jsonnamelen) { - strcpy(fname, get_my_executable_directory()); - strcat(fname, cjsonname); - if (access(fname, F_OK) != -1) { - root = json_load_file(fname, 0, &error); - if (!root) { - PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); - *err = true; - return NULL; - } - - if (!json_is_object(root)) { - PrintAndLog("ERROR: Invalid json format. root must be an object."); - json_decref(root); - *err = true; - return NULL; - } - - } else { - root = json_object(); - } - } - return root; -} - -int CmdHFFidoRegister(const char *cmd) { - uint8_t data[64] = {0}; - int chlen = 0; - uint8_t cdata[250] = {0}; - int applen = 0; - uint8_t adata[250] = {0}; - json_t *root = NULL; - - CLIParserInit("hf fido reg", - "Initiate a U2F token registration. Needs two 32-byte hash number. \nchallenge parameter (32b) and application parameter (32b).", - "Usage:\n\thf fido reg -> execute command with 2 parameters, filled 0x00\n" - "\thf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" - "\thf fido reg -p s0 s1 -> execute command with plain parameters"); - - void* argtable[] = { - arg_param_begin, - arg_lit0("aA", "apdu", "show APDU reqests and responses"), - arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), - arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"), - arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"), - arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), - arg_str0(NULL, NULL, "", NULL), - arg_str0(NULL, NULL, "", NULL), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - - bool APDULogging = arg_get_lit(1); - bool verbose = arg_get_lit(2); - bool verbose2 = arg_get_lit(2) > 1; - bool paramsPlain = arg_get_lit(3); - bool showDERTLV = arg_get_lit(4); - - char fname[250] = {0}; - bool err; - root = OpenJson(5, fname, argtable, &err); - if(err) - return 1; - if (root) { - size_t jlen; - JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen); - JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen); - } - - if (paramsPlain) { - memset(cdata, 0x00, 32); - CLIGetStrWithReturn(6, cdata, &chlen); - if (chlen && chlen > 16) { - PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen); - return 1; - } - } else { - CLIGetHexWithReturn(6, cdata, &chlen); - if (chlen && chlen != 32) { - PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); - return 1; - } - } - if (chlen) - memmove(data, cdata, 32); - - - if (paramsPlain) { - memset(adata, 0x00, 32); - CLIGetStrWithReturn(7, adata, &applen); - if (applen && applen > 16) { - PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen); - return 1; - } - } else { - CLIGetHexWithReturn(7, adata, &applen); - if (applen && applen != 32) { - PrintAndLog("ERROR: application parameter length must be 32 bytes only."); - return 1; - } - } - if (applen) - memmove(&data[32], adata, 32); - - CLIParserFree(); - - SetAPDULogging(APDULogging); - - // challenge parameter [32 bytes] - The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares - // application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity - - uint8_t buf[2048] = {0}; - size_t len = 0; - uint16_t sw = 0; - - DropField(); - int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); - - if (res) { - PrintAndLog("Can't select authenticator. res=%x. Exit...", res); - DropField(); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return 2; - } - - res = FIDORegister(data, buf, sizeof(buf), &len, &sw); - DropField(); - if (res) { - PrintAndLog("Can't execute register command. res=%x. Exit...", res); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return 3; - } - - PrintAndLog(""); - if (APDULogging) - PrintAndLog("---------------------------------------------------------------"); - PrintAndLog("data len: %d", len); - if (verbose2) { - PrintAndLog("--------------data----------------------"); - dump_buffer((const unsigned char *)buf, len, NULL, 0); - PrintAndLog("--------------data----------------------"); - } - - if (buf[0] != 0x05) { - PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]); - return 5; - } - PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65)); - - uint8_t keyHandleLen = buf[66]; - PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen)); - - int derp = 67 + keyHandleLen; - int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4; - if (verbose2) { - PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen); - dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL); - PrintAndLog("\n----------------DER---------------------"); - } else { - if (verbose) - PrintAndLog("------------------DER-------------------"); - PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20)); - } - - // check and print DER certificate - uint8_t public_key[65] = {0}; - - // print DER certificate in TLV view - if (showDERTLV) { - PrintAndLog("----------------DER TLV-----------------"); - asn1_print(&buf[derp], derLen, " "); - PrintAndLog("----------------DER TLV-----------------"); - } - - FIDOCheckDERAndGetKey(&buf[derp], derLen, verbose, public_key, sizeof(public_key)); - - // get hash - int hashp = 1 + 65 + 1 + keyHandleLen + derLen; - PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp)); - - // check ANSI X9.62 format ECDSA signature (on P-256) - uint8_t rval[300] = {0}; - uint8_t sval[300] = {0}; - res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval); - if (!res) { - if (verbose) { - PrintAndLog(" r: %s", sprint_hex(rval, 32)); - PrintAndLog(" s: %s", sprint_hex(sval, 32)); - } - - uint8_t xbuf[4096] = {0}; - size_t xbuflen = 0; - res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen, - "\x00", 1, - &data[32], 32, // application parameter - &data[0], 32, // challenge parameter - &buf[67], keyHandleLen, // keyHandle - &buf[1], 65, // user public key - NULL, 0); - //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); - res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[hashp], len - hashp, true); - if (res) { - if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) { - PrintAndLog("Signature is NOT VALID."); - } else { - PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); - } - } else { - PrintAndLog("Signature is OK."); - } - - } else { - PrintAndLog("Invalid signature. res=%d.", res); - } - - PrintAndLog("\nauth command: "); - printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen)); - if(chlen || applen) - printf(" %s", paramsPlain?(char *)cdata:sprint_hex_inrow(cdata, 32)); - if(applen) - printf(" %s", paramsPlain?(char *)adata:sprint_hex_inrow(adata, 32)); - printf("\n"); - - if (root) { - JsonSaveBufAsHex(root, "ChallengeParam", data, 32); - JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); - JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65); - JsonSaveInt(root, "KeyHandleLen", keyHandleLen); - JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen); - JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen); - - res = json_dump_file(root, fname, JSON_INDENT(2)); - if (res) { - PrintAndLog("ERROR: can't save the file: %s", fname); - return 200; - } - PrintAndLog("File `%s` saved.", fname); - - // free json object - json_decref(root); - } - - return 0; -}; - -int CmdHFFidoAuthenticate(const char *cmd) { - uint8_t data[512] = {0}; - uint8_t hdata[250] = {0}; - bool public_key_loaded = false; - uint8_t public_key[65] = {0}; - int hdatalen = 0; - uint8_t keyHandleLen = 0; - json_t *root = NULL; - - CLIParserInit("hf fido auth", - "Initiate a U2F token authentication. Needs key handle and two 32-byte hash number. \nkey handle(var 0..255), challenge parameter (32b) and application parameter (32b).", - "Usage:\n\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n" - "\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f " - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"); - - void* argtable[] = { - arg_param_begin, - arg_lit0("aA", "apdu", "show APDU reqests and responses"), - arg_lit0("vV", "verbose", "show technical data"), - arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"), - arg_rem("default mode:", "dont-enforce-user-presence-and-sign"), - arg_lit0("uU", "user", "mode: enforce-user-presence-and-sign"), - arg_lit0("cC", "check", "mode: check-only"), - arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), - arg_str0("kK", "key", "public key to verify signature", NULL), - arg_str0(NULL, NULL, "", NULL), - arg_str0(NULL, NULL, "", NULL), - arg_str0(NULL, NULL, "", NULL), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - - bool APDULogging = arg_get_lit(1); - bool verbose = arg_get_lit(2); - bool paramsPlain = arg_get_lit(3); - uint8_t controlByte = 0x08; - if (arg_get_lit(5)) - controlByte = 0x03; - if (arg_get_lit(6)) - controlByte = 0x07; - - char fname[250] = {0}; - bool err; - root = OpenJson(7, fname, argtable, &err); - if(err) - return 1; - if (root) { - size_t jlen; - JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen); - JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen); - JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen); - keyHandleLen = jlen & 0xff; - data[64] = keyHandleLen; - JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen); - public_key_loaded = (jlen > 0); - } - - // public key - CLIGetHexWithReturn(8, hdata, &hdatalen); - if (hdatalen && hdatalen != 65) { - PrintAndLog("ERROR: public key length must be 65 bytes only."); - return 1; - } - if (hdatalen) { - memmove(public_key, hdata, hdatalen); - public_key_loaded = true; - } - - CLIGetHexWithReturn(9, hdata, &hdatalen); - if (hdatalen > 255) { - PrintAndLog("ERROR: application parameter length must be less than 255."); - return 1; - } - if (hdatalen) { - keyHandleLen = hdatalen; - data[64] = keyHandleLen; - memmove(&data[65], hdata, keyHandleLen); - } - - if (paramsPlain) { - memset(hdata, 0x00, 32); - CLIGetStrWithReturn(9, hdata, &hdatalen); - if (hdatalen && hdatalen > 16) { - PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); - return 1; - } - } else { - CLIGetHexWithReturn(10, hdata, &hdatalen); - if (hdatalen && hdatalen != 32) { - PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); - return 1; - } - } - if (hdatalen) - memmove(data, hdata, 32); - - if (paramsPlain) { - memset(hdata, 0x00, 32); - CLIGetStrWithReturn(11, hdata, &hdatalen); - if (hdatalen && hdatalen > 16) { - PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); - return 1; - } - } else { - CLIGetHexWithReturn(10, hdata, &hdatalen); - if (hdatalen && hdatalen != 32) { - PrintAndLog("ERROR: application parameter length must be 32 bytes only."); - return 1; - } - } - if (hdatalen) - memmove(&data[32], hdata, 32); - - CLIParserFree(); - - SetAPDULogging(APDULogging); - - // (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only - // challenge parameter [32 bytes] - // application parameter [32 bytes] - // key handle length [1b] = N - // key handle [N] - - uint8_t datalen = 32 + 32 + 1 + keyHandleLen; - - uint8_t buf[2048] = {0}; - size_t len = 0; - uint16_t sw = 0; - - DropField(); - int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); - - if (res) { - PrintAndLog("Can't select authenticator. res=%x. Exit...", res); - DropField(); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return 2; - } - - res = FIDOAuthentication(data, datalen, controlByte, buf, sizeof(buf), &len, &sw); - DropField(); - if (res) { - PrintAndLog("Can't execute authentication command. res=%x. Exit...", res); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return 3; - } - - PrintAndLog("---------------------------------------------------------------"); - PrintAndLog("User presence: %s", (buf[0]?"verified":"not verified")); - uint32_t cntr = (uint32_t)bytes_to_num(&buf[1], 4); - PrintAndLog("Counter: %d", cntr); - PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5)); - - // check ANSI X9.62 format ECDSA signature (on P-256) - uint8_t rval[300] = {0}; - uint8_t sval[300] = {0}; - res = ecdsa_asn1_get_signature(&buf[5], len - 5, rval, sval); - if (!res) { - if (verbose) { - PrintAndLog(" r: %s", sprint_hex(rval, 32)); - PrintAndLog(" s: %s", sprint_hex(sval, 32)); - } - if (public_key_loaded) { - uint8_t xbuf[4096] = {0}; - size_t xbuflen = 0; - res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen, - &data[32], 32, // application parameter - &buf[0], 1, // user presence - &buf[1], 4, // counter - data, 32, // challenge parameter - NULL, 0); - //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); - res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[5], len - 5, true); - if (res) { - if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) { - PrintAndLog("Signature is NOT VALID."); - } else { - PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); - } - } else { - PrintAndLog("Signature is OK."); - } - } else { - PrintAndLog("No public key provided. can't check signature."); - } - } else { - PrintAndLog("Invalid signature. res=%d.", res); - } - - if (root) { - JsonSaveBufAsHex(root, "ChallengeParam", data, 32); - JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); - JsonSaveInt(root, "KeyHandleLen", keyHandleLen); - JsonSaveBufAsHexCompact(root, "KeyHandle", &data[65], keyHandleLen); - JsonSaveInt(root, "Counter", cntr); - - res = json_dump_file(root, fname, JSON_INDENT(2)); - if (res) { - PrintAndLog("ERROR: can't save the file: %s", fname); - return 200; - } - PrintAndLog("File `%s` saved.", fname); - - // free json object - json_decref(root); - } - return 0; -}; - -void CheckSlash(char *fileName) { - if ((fileName[strlen(fileName) - 1] != '/') && - (fileName[strlen(fileName) - 1] != '\\')) - strcat(fileName, "/"); -} - -int GetExistsFileNameJson(char *prefixDir, char *reqestedFileName, char *fileName) { - fileName[0] = 0x00; - strcpy(fileName, get_my_executable_directory()); - CheckSlash(fileName); - - strcat(fileName, prefixDir); - CheckSlash(fileName); - - strcat(fileName, reqestedFileName); - if (!strstr(fileName, ".json")) - strcat(fileName, ".json"); - - if (access(fileName, F_OK) < 0) { - strcpy(fileName, get_my_executable_directory()); - CheckSlash(fileName); - - strcat(fileName, reqestedFileName); - if (!strstr(fileName, ".json")) - strcat(fileName, ".json"); - - if (access(fileName, F_OK) < 0) { - return 1; // file not found - } - } - return 0; -} - -int CmdHFFido2MakeCredential(const char *cmd) { - json_error_t error; - json_t *root = NULL; - char fname[300] = {0}; - - CLIParserInit("hf fido make", - "Execute a FIDO2 Make Credentional command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.", - "Usage:\n\thf fido make -> execute command default parameters file `fido2.json`\n" - "\thf fido make test.json -> execute command with parameters file `text.json`"); - - void* argtable[] = { - arg_param_begin, - arg_lit0("aA", "apdu", "show APDU reqests and responses"), - arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), - arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"), - arg_lit0("cC", "cbor", "show CBOR decoded data"), - arg_str0(NULL, NULL, "", "JSON input / output file name for parameters. Default `fido2.json`"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - - bool APDULogging = arg_get_lit(1); - bool verbose = arg_get_lit(2); - bool verbose2 = arg_get_lit(2) > 1; - bool showDERTLV = arg_get_lit(3); - bool showCBOR = arg_get_lit(4); - - uint8_t jsonname[250] ={0}; - char *cjsonname = (char *)jsonname; - int jsonnamelen = 0; - CLIGetStrWithReturn(5, jsonname, &jsonnamelen); - - if (!jsonnamelen) { - strcat(cjsonname, "fido2"); - jsonnamelen = strlen(cjsonname); - } - - CLIParserFree(); - - SetAPDULogging(APDULogging); - - int res = GetExistsFileNameJson("fido", cjsonname, fname); - if(res) { - PrintAndLog("ERROR: Can't found the json file."); - return res; - } - PrintAndLog("fname: %s\n", fname); - root = json_load_file(fname, 0, &error); - if (!root) { - PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); - return 1; - } - - uint8_t data[2048] = {0}; - size_t datalen = 0; - uint8_t buf[2048] = {0}; - size_t len = 0; - uint16_t sw = 0; - - DropField(); - res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); - - if (res) { - PrintAndLog("Can't select authenticator. res=%x. Exit...", res); - DropField(); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return 2; - } - - res = FIDO2CreateMakeCredentionalReq(root, data, sizeof(data), &datalen); - if (res) - return res; - - if (showCBOR) { - PrintAndLog("CBOR make credentional request:"); - PrintAndLog("---------------- CBOR ------------------"); - TinyCborPrintFIDOPackage(fido2CmdMakeCredential, false, data, datalen); - PrintAndLog("---------------- CBOR ------------------"); - } - - res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw); - DropField(); - if (res) { - PrintAndLog("Can't execute make credential command. res=%x. Exit...", res); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return 3; - } - - if(buf[0]) { - PrintAndLog("FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); - return 0; - } - - PrintAndLog("MakeCredential result (%d b) OK.", len); - if (showCBOR) { - PrintAndLog("CBOR make credentional response:"); - PrintAndLog("---------------- CBOR ------------------"); - TinyCborPrintFIDOPackage(fido2CmdMakeCredential, true, &buf[1], len - 1); - PrintAndLog("---------------- CBOR ------------------"); - } - - // parse returned cbor - FIDO2MakeCredentionalParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR, showDERTLV); - - if (root) { - res = json_dump_file(root, fname, JSON_INDENT(2)); - if (res) { - PrintAndLog("ERROR: can't save the file: %s", fname); - return 200; - } - PrintAndLog("File `%s` saved.", fname); - } - - json_decref(root); - - return 0; -}; - -int CmdHFFido2GetAssertion(const char *cmd) { - json_error_t error; - json_t *root = NULL; - char fname[300] = {0}; - - CLIParserInit("hf fido assert", - "Execute a FIDO2 Get Assertion command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.", - "Usage:\n\thf fido assert -> execute command default parameters file `fido2.json`\n" - "\thf fido assert test.json -l -> execute command with parameters file `text.json` and add to request CredentialId"); - - void* argtable[] = { - arg_param_begin, - arg_lit0("aA", "apdu", "show APDU reqests and responses"), - arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), - arg_lit0("cC", "cbor", "show CBOR decoded data"), - arg_lit0("lL", "list", "add CredentialId from json to allowList. Needs if `rk` option is `false` (authenticator don't store credential to its memory)"), - arg_str0(NULL, NULL, "", "JSON input / output file name for parameters. Default `fido2.json`"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - - bool APDULogging = arg_get_lit(1); - bool verbose = arg_get_lit(2); - bool verbose2 = arg_get_lit(2) > 1; - bool showCBOR = arg_get_lit(3); - bool createAllowList = arg_get_lit(4); - - uint8_t jsonname[250] ={0}; - char *cjsonname = (char *)jsonname; - int jsonnamelen = 0; - CLIGetStrWithReturn(5, jsonname, &jsonnamelen); - - if (!jsonnamelen) { - strcat(cjsonname, "fido2"); - jsonnamelen = strlen(cjsonname); - } - - CLIParserFree(); - - SetAPDULogging(APDULogging); - - int res = GetExistsFileNameJson("fido", "fido2", fname); - if(res) { - PrintAndLog("ERROR: Can't found the json file."); - return res; - } - PrintAndLog("fname: %s\n", fname); - root = json_load_file(fname, 0, &error); - if (!root) { - PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); - return 1; - } - - uint8_t data[2048] = {0}; - size_t datalen = 0; - uint8_t buf[2048] = {0}; - size_t len = 0; - uint16_t sw = 0; - - DropField(); - res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); - - if (res) { - PrintAndLog("Can't select authenticator. res=%x. Exit...", res); - DropField(); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - DropField(); - return 2; - } - - res = FIDO2CreateGetAssertionReq(root, data, sizeof(data), &datalen, createAllowList); - if (res) - return res; - - if (showCBOR) { - PrintAndLog("CBOR get assertion request:"); - PrintAndLog("---------------- CBOR ------------------"); - TinyCborPrintFIDOPackage(fido2CmdGetAssertion, false, data, datalen); - PrintAndLog("---------------- CBOR ------------------"); - } - - res = FIDO2GetAssertion(data, datalen, buf, sizeof(buf), &len, &sw); - DropField(); - if (res) { - PrintAndLog("Can't execute get assertion command. res=%x. Exit...", res); - return res; - } - - if (sw != 0x9000) { - PrintAndLog("ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - return 3; - } - - if(buf[0]) { - PrintAndLog("FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); - return 0; - } - - PrintAndLog("GetAssertion result (%d b) OK.", len); - if (showCBOR) { - PrintAndLog("CBOR get assertion response:"); - PrintAndLog("---------------- CBOR ------------------"); - TinyCborPrintFIDOPackage(fido2CmdGetAssertion, true, &buf[1], len - 1); - PrintAndLog("---------------- CBOR ------------------"); - } - - // parse returned cbor - FIDO2GetAssertionParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR); - - if (root) { - res = json_dump_file(root, fname, JSON_INDENT(2)); - if (res) { - PrintAndLog("ERROR: can't save the file: %s", fname); - return 200; - } - PrintAndLog("File `%s` saved.", fname); - } - - json_decref(root); - - return 0; -}; - -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help."}, - {"info", CmdHFFidoInfo, 0, "Info about FIDO tag."}, - {"reg", CmdHFFidoRegister, 0, "FIDO U2F Registration Message."}, - {"auth", CmdHFFidoAuthenticate, 0, "FIDO U2F Authentication Message."}, - {"make", CmdHFFido2MakeCredential, 0, "FIDO2 MakeCredential command."}, - {"assert", CmdHFFido2GetAssertion, 0, "FIDO2 GetAssertion command."}, - {NULL, NULL, 0, NULL} -}; - -int CmdHFFido(const char *Cmd) { - (void)WaitForResponseTimeout(CMD_ACK,NULL,100); - CmdsParse(CommandTable, Cmd); - return 0; -} - -int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; -} diff --git a/client/cmdhffido.h b/client/cmdhffido.h deleted file mode 100644 index 2460a170..00000000 --- a/client/cmdhffido.h +++ /dev/null @@ -1,27 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2018 Merlok -// -// 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. -//----------------------------------------------------------------------------- -// High frequency FIDO U2F and FIDO2 contactless authenticators -//----------------------------------------------------------------------------- -// -// Documentation here: -// -// FIDO Alliance specifications -// https://fidoalliance.org/download/ -// FIDO NFC Protocol Specification v1.0 -// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html -// FIDO U2F Raw Message Formats -// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html -//----------------------------------------------------------------------------- - -#ifndef CMDHFFIDO_H__ -#define CMDHFFIDO_H__ - -extern int CmdHFFido(const char *Cmd); - - -#endif \ No newline at end of file diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 93e46b67..f807e972 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,8 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans -// Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende -// Copyright (C) 2019 piwi // // 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 @@ -14,2214 +12,245 @@ #include #include #include -#include -#include #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type -#include "comms.h" +#include "data.h" +//#include "proxusb.h" +#include "proxmark3.h" #include "ui.h" -#include "cliparser/cliparser.h" #include "cmdparser.h" #include "cmdhficlass.h" #include "common.h" #include "util.h" -#include "cmdmain.h" -#include "mbedtls/des.h" -#include "loclass/cipherutils.h" -#include "loclass/cipher.h" -#include "loclass/ikeys.h" -#include "loclass/elite_crack.h" -#include "loclass/fileutils.h" -#include "protocols.h" -#include "usb_cmd.h" -#include "cmdhfmfu.h" -#include "util_posix.h" -#include "cmdhf14a.h" // DropField() - - -#define ICLASS_KEYS_MAX 8 -static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } -}; - - -// iclass / picopass chip config structures and shared routines -typedef struct { - uint8_t app_limit; //[8] - uint8_t otp[2]; //[9-10] - uint8_t block_writelock;//[11] - uint8_t chip_config; //[12] - uint8_t mem_config; //[13] - uint8_t eas; //[14] - uint8_t fuses; //[15] -} picopass_conf_block; - -typedef struct { - uint8_t csn[8]; - picopass_conf_block conf; - uint8_t epurse[8]; - uint8_t key_d[8]; - uint8_t key_c[8]; - uint8_t app_issuer_area[8]; -} picopass_hdr; - - -static void fuse_config(const picopass_hdr *hdr) { - uint8_t fuses = hdr->conf.fuses; - - if (fuses & FUSE_FPERS) - PrintAndLog(" Mode: Personalization [Programmable]"); - else - PrintAndLog(" Mode: Application [Locked]"); - - if (fuses & FUSE_CODING1) - PrintAndLog("Coding: RFU"); - else { - if (fuses & FUSE_CODING0) - PrintAndLog("Coding: ISO 14443-2 B/ISO 15693"); - else - PrintAndLog("Coding: ISO 14443B only"); - } - if ((fuses & FUSE_CRYPT1) && (fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Secured page, keys not locked"); - if ((fuses & FUSE_CRYPT1) && !(fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Secured page, keys locked"); - if (!(fuses & FUSE_CRYPT1) && (fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: Non secured page"); - if (!(fuses & FUSE_CRYPT1) && !(fuses & FUSE_CRYPT0)) PrintAndLog(" Crypt: No auth possible. Read only if RA is enabled"); - - if (fuses & FUSE_RA) - PrintAndLog(" RA: Read access enabled"); - else - PrintAndLog(" RA: Read access not enabled"); -} - - -static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *max_blk, uint8_t *app_areas, uint8_t *kb) { - // mem-bit 5, mem-bit 7, chip-bit 4: defines chip type - if((chip_cfg & 0x10) && !(mem_cfg & 0x80) && !(mem_cfg & 0x20)) { - *kb = 2; - *app_areas = 2; - *max_blk = 31; - } else if((chip_cfg & 0x10) && (mem_cfg & 0x80) && !(mem_cfg & 0x20)) { - *kb = 16; - *app_areas = 2; - *max_blk = 255; //16kb - } else if(!(chip_cfg & 0x10) && !(mem_cfg & 0x80) && !(mem_cfg & 0x20)) { - *kb = 16; - *app_areas = 16; - *max_blk = 255; //16kb - } else if((chip_cfg & 0x10) && (mem_cfg & 0x80) && (mem_cfg & 0x20)) { - *kb = 32; - *app_areas = 3; - *max_blk = 255; //16kb - } else if(!(chip_cfg & 0x10) && !(mem_cfg & 0x80) && (mem_cfg & 0x20)) { - *kb = 32; - *app_areas = 17; - *max_blk = 255; //16kb - } else { - *kb = 32; - *app_areas = 2; - *max_blk = 255; - } -} - - -static void mem_app_config(const picopass_hdr *hdr) { - uint8_t mem = hdr->conf.mem_config; - uint8_t chip = hdr->conf.chip_config; - uint8_t applimit = hdr->conf.app_limit; - if (applimit < 6) applimit = 26; - uint8_t kb = 2; - uint8_t app_areas = 2; - uint8_t max_blk = 31; - getMemConfig(mem, chip, &max_blk, &app_areas, &kb); - PrintAndLog(" Mem: %u KBits/%u App Areas (%u * 8 bytes) [%02X]", kb, app_areas, max_blk+1, mem); - PrintAndLog(" AA1: blocks 06-%02X", applimit); - PrintAndLog(" AA2: blocks %02X-%02X", applimit+1, max_blk); -} - - -static void printIclassDumpInfo(uint8_t* iclass_dump) { - fuse_config((picopass_hdr*)iclass_dump); - mem_app_config((picopass_hdr*)iclass_dump); -} - - -static void usage_hf_iclass_chk(void) { - PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); - PrintAndLog("Usage: hf iclass chk [h|e|r] "); - PrintAndLog("Options:"); - PrintAndLog("h Show this help"); - PrintAndLog("f Dictionary file with default iclass keys"); - PrintAndLog(" e target Elite / High security key scheme"); - PrintAndLog(" r interpret dictionary file as raw (diversified keys)"); - PrintAndLog("Samples:"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); -} - - -static int CmdHFiClassList(const char *Cmd) { - PrintAndLog("Deprecated command, use 'hf list iclass' instead"); - return 0; -} - - -static int CmdHFiClassSnoop(const char *Cmd) { - - CLIParserInit("hf iclass snoop", "\nSnoop a communication between an iClass Reader and an iClass Tag.", NULL); - void* argtable[] = { - arg_param_begin, - arg_lit0("j", "jam", "Jam (prevent) e-purse Updates"), - arg_param_end - }; - if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){ - CLIParserFree(); - return 0; - } - - bool jam_epurse_update = arg_get_lit(1); - - const uint8_t update_epurse_sequence[2] = {0x87, 0x02}; - - UsbCommand c = {CMD_SNOOP_ICLASS, {0}}; - if (jam_epurse_update) { - c.arg[0] = sizeof(update_epurse_sequence); - memcpy(c.d.asBytes, update_epurse_sequence, sizeof(update_epurse_sequence)); - } - SendCommand(&c); - - return 0; -} - - -static void usage_hf_iclass_sim(void) { - PrintAndLog("Usage: hf iclass sim